pax_global_header00006660000000000000000000000064130345323140014510gustar00rootroot0000000000000052 comment=88b1087f6ab2c860c8729478643e081b6e97f6d3 ocproxy-1.60/000077500000000000000000000000001303453231400131415ustar00rootroot00000000000000ocproxy-1.60/.gitignore000066400000000000000000000005701303453231400151330ustar00rootroot00000000000000# autotools stuff Makefile Makefile.in aclocal.m4 compile config.h config.h.in config.log config.status configure depcomp install-sh missing .deps/ .dirstamp stamp-h1 autom4te.cache/ config.guess config.sub m4/ # objects *.o ocproxy vpnns ocproxy*.tar.gz ocproxy*.tar.gz.asc /TAGS /tags # Debian tmp.debian/ ocproxy*.deb lintian.txt ppa/changelog # scratch files .*.sw* *~ ocproxy-1.60/.travis.yml000066400000000000000000000007011303453231400152500ustar00rootroot00000000000000language: c compiler: - gcc - clang notifications: email: on_success: change on_failure: always before_install: - sudo apt-get update -qq - sudo apt-get install -qq autoconf automake debhelper dh-autoreconf devscripts fakeroot git-core libevent-dev script: - ./autogen.sh && mkdir build && pushd build && ../configure && make && make dist && mv ocproxy*.tar.gz ../ && popd && ./build-debian.sh ocproxy-1.60/AUTHORS000066400000000000000000000003401303453231400142060ustar00rootroot00000000000000ocproxy / vpnns: Copyright (c) 2012-2014 David Edmondson Copyright (c) 2012-2014 Kevin Cernekee Copyright (c) 2016 Google Inc. lwIP: See lwip/COPYING and credits in each individual file ocproxy-1.60/CHANGES000066400000000000000000000010401303453231400141270ustar00rootroot00000000000000v1.60 - 2017/01/08 - Allow specifying the local SOCKS address via "-D :". - Add experimental vpnns program v1.50 - 2014/07/06 - Fix a bunch of stability issues seen under load (web browsing on SOCKS) - Add man page - Switch build system to GNU autotools - Update to the latest lwIP and fix DNS lookup bugs - Delete unused netmask and gateway options - Add scripts to build one-off packages for Ubuntu PPA - Use Travis CI to run automated builds on each commit v1.20121120160713 - 2012/11/20 - Initial release. ocproxy-1.60/LICENSE000066400000000000000000000024721303453231400141530ustar00rootroot00000000000000Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ocproxy-1.60/Makefile.am000066400000000000000000000114441303453231400152010ustar00rootroot00000000000000AUTOMAKE_OPTIONS = foreign subdir-objects AM_CFLAGS = -Dunix -DIPv4 \ -I$(srcdir)/lwip/src \ -I$(srcdir)/lwip/src/include \ -I$(srcdir)/lwip/src/include/ipv4 \ -I$(srcdir)/lwip/src/include/ipv6 \ -I$(srcdir)/contrib/ports/unix/include \ -I$(srcdir)/src LWIP_SOURCES := \ lwip/src/include/lwip/api.h \ lwip/src/include/lwip/api_msg.h \ lwip/src/include/lwip/arch.h \ lwip/src/include/lwip/debug.h \ lwip/src/include/lwip/def.h \ lwip/src/include/lwip/dhcp.h \ lwip/src/include/lwip/dns.h \ lwip/src/include/lwip/err.h \ lwip/src/include/lwip/inet_chksum.h \ lwip/src/include/lwip/init.h \ lwip/src/include/lwip/ip.h \ lwip/src/include/lwip/ip_addr.h \ lwip/src/include/lwip/mem.h \ lwip/src/include/lwip/memp.h \ lwip/src/include/lwip/memp_std.h \ lwip/src/include/lwip/netbuf.h \ lwip/src/include/lwip/netdb.h \ lwip/src/include/lwip/netifapi.h \ lwip/src/include/lwip/netif.h \ lwip/src/include/lwip/opt.h \ lwip/src/include/lwip/pbuf.h \ lwip/src/include/lwip/pppapi.h \ lwip/src/include/lwip/raw.h \ lwip/src/include/lwip/sio.h \ lwip/src/include/lwip/snmp_asn1.h \ lwip/src/include/lwip/snmp.h \ lwip/src/include/lwip/snmp_msg.h \ lwip/src/include/lwip/snmp_structs.h \ lwip/src/include/lwip/sockets.h \ lwip/src/include/lwip/stats.h \ lwip/src/include/lwip/sys.h \ lwip/src/include/lwip/tcp.h \ lwip/src/include/lwip/tcp_impl.h \ lwip/src/include/lwip/tcpip.h \ lwip/src/include/lwip/timers.h \ lwip/src/include/lwip/udp.h \ lwip/src/include/netif/etharp.h \ lwip/src/include/netif/slipif.h \ lwip/src/include/netif/ppp/ppp.h \ lwip/src/include/netif/ppp/pppoe.h \ lwip/src/include/netif/ppp/pppol2tp.h \ lwip/src/core/def.c \ lwip/src/core/dns.c \ lwip/src/core/inet_chksum.c \ lwip/src/core/init.c \ lwip/src/core/mem.c \ lwip/src/core/memp.c \ lwip/src/core/netif.c \ lwip/src/core/pbuf.c \ lwip/src/core/stats.c \ lwip/src/core/sys.c \ lwip/src/core/tcp.c \ lwip/src/core/tcp_in.c \ lwip/src/core/tcp_out.c \ lwip/src/core/timers.c \ lwip/src/core/udp.c \ lwip/src/include/ipv4/lwip/autoip.h \ lwip/src/include/ipv4/lwip/icmp.h \ lwip/src/include/ipv4/lwip/igmp.h \ lwip/src/include/ipv4/lwip/inet.h \ lwip/src/include/ipv4/lwip/ip4_addr.h \ lwip/src/include/ipv4/lwip/ip4.h \ lwip/src/include/ipv4/lwip/ip_frag.h \ lwip/src/include/ipv6/lwip/icmp6.h \ lwip/src/include/ipv6/lwip/ip6_addr.h \ lwip/src/include/ipv6/lwip/ip6.h \ lwip/src/include/ipv6/lwip/ip6_frag.h \ lwip/src/include/ipv6/lwip/mld6.h \ lwip/src/include/ipv6/lwip/nd6.h \ lwip/src/core/ipv4/icmp.c \ lwip/src/core/ipv4/ip4.c \ lwip/src/core/ipv4/ip4_addr.c \ lwip/src/core/ipv4/ip_frag.c \ lwip/src/api/api_lib.c \ lwip/src/api/api_msg.c \ lwip/src/api/err.c \ lwip/src/api/netdb.c \ lwip/src/api/tcpip.c \ contrib/ports/unix/include/arch/cc.h \ contrib/ports/unix/include/arch/perf.h \ contrib/ports/unix/include/arch/sys_arch.h \ contrib/ports/unix/include/netif/delif.h \ contrib/ports/unix/include/netif/dropif.h \ contrib/ports/unix/include/netif/fifo.h \ contrib/ports/unix/include/netif/list.h \ contrib/ports/unix/include/netif/pcapif.h \ contrib/ports/unix/include/netif/sio.h \ contrib/ports/unix/include/netif/tapif.h \ contrib/ports/unix/include/netif/tcpdump.h \ contrib/ports/unix/include/netif/tunif.h \ contrib/ports/unix/include/netif/unixif.h \ contrib/ports/unix/lwip_chksum.c \ contrib/ports/unix/perf.c \ contrib/ports/unix/sys_arch.c \ contrib/ports/unix/netif/list.c \ contrib/ports/unix/netif/tcpdump.c APP_SOURCES := src/ocproxy.c src/lwipopts.h bin_PROGRAMS = ocproxy ocproxy_SOURCES = $(LWIP_SOURCES) $(APP_SOURCES) dist_man_MANS = ocproxy.1 dist_doc_DATA = README.md CHANGES dist_noinst_SCRIPTS = autogen.sh if ENABLE_VPNNS vpnns_SOURCES = src/vpnns.c bin_PROGRAMS += vpnns dist_man_MANS += vpnns.1 endif EXTRA_DIST = .gitignore DISTCLEANFILES = *~ LWIP_GIT = git://git.savannah.nongnu.org/lwip.git LWIP_GIT_TAG = master LWIP_CONTRIB_GIT = git://git.savannah.nongnu.org/lwip/lwip-contrib.git LWIP_CONTRIB_GIT_TAG = master .PHONY: update-lwip update-lwip: rm -rf lwip contrib git clone --depth 1 $(LWIP_GIT) lwip cd lwip && git checkout $(LWIP_GIT_TAG) && \ git rev-parse HEAD > VERSION rm -rf lwip/.git git clone --depth 1 $(LWIP_CONTRIB_GIT) contrib cd contrib && git checkout $(LWIP_CONTRIB_GIT_TAG) && \ git rev-parse HEAD > VERSION rm -rf contrib/.git ocproxy-1.60/README.md000066400000000000000000000142101303453231400144160ustar00rootroot00000000000000ocproxy ======= ocproxy is a user-level SOCKS and port forwarding proxy for [OpenConnect](http://www.infradead.org/openconnect/) based on lwIP. When using ocproxy, OpenConnect only handles network activity that the user specifically asks to proxy, so the VPN interface no longer "hijacks" all network traffic on the host. Basic usage ----------- Commonly used options include: -D port Set up a SOCKS5 server on PORT -L lport:rhost:rport Connections to localhost:LPORT will be redirected over the VPN to RHOST:RPORT -g Allow non-local clients. -k interval Send TCP keepalive every INTERVAL seconds, to prevent connection timeouts ocproxy should not be run directly. Instead, it should be started by openconnect using the --script-tun option: openconnect --script-tun --script \ "./ocproxy -L 2222:unix-host:22 -L 3389:win-host:3389 -D 11080" \ vpn.example.com Once ocproxy is running, connections can be established over the VPN link by connecting directly to a forwarded port or by utilizing the builtin SOCKS server: ssh -p2222 localhost rdesktop localhost socksify ssh unix-host tsocks ssh 172.16.1.2 ... OpenConnect can (and should) be run as a non-root user when using ocproxy. Using the SOCKS5 proxy ---------------------- tsocks, Dante, or similar wrappers can be used with non-SOCKS-aware applications. Sample tsocks.conf (no DNS): server = 127.0.0.1 server_type = 5 server_port = 11080 Sample socks.conf for Dante (DNS lookups via SOCKS5 "DOMAIN" addresses): resolveprotocol: fake route { from: 0.0.0.0/0 to: 0.0.0.0/0 via: 127.0.0.1 port = 11080 command: connect proxyprotocol: socks_v5 } [FoxyProxy](http://getfoxyproxy.org/) can be used to tunnel Firefox or Chrome browsing through the SOCKS5 server. This will send DNS queries through the VPN connection, and unqualified internal hostnames (e.g. http://intranet/) should work. FoxyProxy also allows the user to route requests based on URL patterns, so that (for instance) certain domains always use the proxy server but all other traffic connects directly. It is possible to start several different instances of Firefox, each with its own separate profile (and hence, proxy settings): # initial setup firefox -no-remote -ProfileManager # run with previous configured profile "vpn" firefox -no-remote -P vpn Building ocproxy ---------------- Dependencies: * libevent >= 2.0: *.so library and headers * autoconf * automake * gcc, binutils, make, etc. Building from git: ./autogen.sh ./configure make Other possible uses for ocproxy ------------------------------- * Routing traffic from different applications/browsers through different VPNs (or no VPN) * Connecting to multiple VPNs or sites concurrently, even if their IP ranges overlap or their DNS settings are incompatible * Situations in which root access is unavailable or undesirable; multiuser systems It is possible to write a proxy autoconfig (PAC) script that decides whether each request should use ocproxy or a direct connection, based on the domain or other criteria. ocproxy also works with OpenVPN; the necessary patches are posted [here](http://thread.gmane.org/gmane.network.openvpn.devel/8478). Network configuration --------------------- ocproxy normally reads its network configuration from the following environment variables set by OpenConnect: * `INTERNAL_IP4_ADDRESS`: IPv4 address * `INTERNAL_IP4_MTU`: interface MTU * `INTERNAL_IP4_DNS`: DNS server list (optional but recommended) * `CISCO_DEF_DOMAIN`: default domain name (optional) The `VPNFD` environment variable tells ocproxy which file descriptor is used to pass the tunneled traffic. vpnns (experimental) -------------------- Another approach to solving this problem is to create a separate network namespace (netns). This is supported by Linux kernels >= v3.8. This starts up an application in a fresh user/net/uts/mount namespace: vpnns -- google-chrome --user-data-dir=/tmp/vpntest vpnns -- firefox -no-remote -P vpn vpnns -- transmission-gtk Initially it will not have any network access as the only interface present in the netns is the loopback device. The application should still be able to talk to Xorg through UNIX sockets in /tmp. The next step is to connect to a VPN and invoke `vpnns --attach` to pass the VPN traffic back and forth: openconnect --script "vpnns --attach" --script-tun vpn.example.com openvpn --script-security 2 --config example.ovpn \ --dev "|HOME=$HOME vpnns --attach" These commands connect to an ocserv or openvpn gateway, then tell vpnns to set up a tunnel device, default route, and resolv.conf inside the namespace created above. On success, the web browser will have connectivity. When the VPN disconnects, the browser will lose all connectivity, preventing leaks. `vpnns` can be rerun multiple times if the connection fails or if the VPN client crashes. If run without arguments, it will open a shell inside the namespace. Some differences between vpnns and ocproxy: * No proxies are involved, so apps should not require any special configuration. * vpnns is better-suited for hard-to-proxy protocols such as VOIP or BitTorrent. * vpnns will only ever run on Linux. * vpnns may interfere with dbus connections. Unlike previous approaches to the problem (e.g. anything that involves running `ip netns`), vpnns does not require root privileges or changing the host network configuration. The `--name` option allows additional (and separate) namespaces to be created. The OpenVPN example requires out-of-tree patches. Updated openvpn and ocproxy packages are available for Ubuntu 14.04 LTS and 16.04 LTS: sudo -s apt-get install software-properties-common add-apt-repository --yes ppa:cernekee apt-get update apt-get install ocproxy openvpn Credits ------- Original author: David Edmondson <dme@dme.org> Current maintainer: Kevin Cernekee <cernekee@gmail.com> Project home page: https://github.com/cernekee/ocproxy ocproxy-1.60/acinclude.m4000066400000000000000000000357371303453231400153510ustar00rootroot00000000000000dnl dnl http://cgit.freedesktop.org/swfdec/swfdec/plain/m4/as-compiler-flag.m4 dnl as-compiler-flag.m4 0.1.0 dnl autostars m4 macro for detection of compiler flags dnl David Schleef dnl $Id: as-compiler-flag.m4,v 1.1 2005/12/15 23:35:19 ds Exp $ dnl AS_COMPILER_FLAG(CFLAGS, ACTION-IF-ACCEPTED, [ACTION-IF-NOT-ACCEPTED]) dnl Tries to compile with the given CFLAGS. dnl Runs ACTION-IF-ACCEPTED if the compiler can compile with the flags, dnl and ACTION-IF-NOT-ACCEPTED otherwise. AC_DEFUN([AS_COMPILER_FLAG], [ AC_MSG_CHECKING([to see if compiler understands $1]) save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS $1" AC_TRY_COMPILE([ ], [], [flag_ok=yes], [flag_ok=no]) CFLAGS="$save_CFLAGS" if test "X$flag_ok" = Xyes ; then m4_ifvaln([$2],[$2]) true else m4_ifvaln([$3],[$3]) true fi AC_MSG_RESULT([$flag_ok]) ]) dnl AS_COMPILER_FLAGS(VAR, FLAGS) dnl Tries to compile with the given CFLAGS. AC_DEFUN([AS_COMPILER_FLAGS], [ list=$2 flags_supported="" flags_unsupported="" AC_MSG_CHECKING([for supported compiler flags]) for each in $list do save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS $each" AC_TRY_COMPILE([ ], [], [flag_ok=yes], [flag_ok=no]) CFLAGS="$save_CFLAGS" if test "X$flag_ok" = Xyes ; then flags_supported="$flags_supported $each" else flags_unsupported="$flags_unsupported $each" fi done AC_MSG_RESULT([$flags_supported]) if test "X$flags_unsupported" != X ; then AC_MSG_WARN([unsupported compiler flags: $flags_unsupported]) fi $1="$$1 $flags_supported" ]) # =========================================================================== # http://www.gnu.org/software/autoconf-archive/ax_pthread.html # =========================================================================== # # SYNOPSIS # # AX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]]) # # DESCRIPTION # # This macro figures out how to build C programs using POSIX threads. It # sets the PTHREAD_LIBS output variable to the threads library and linker # flags, and the PTHREAD_CFLAGS output variable to any special C compiler # flags that are needed. (The user can also force certain compiler # flags/libs to be tested by setting these environment variables.) # # Also sets PTHREAD_CC to any special C compiler that is needed for # multi-threaded programs (defaults to the value of CC otherwise). (This # is necessary on AIX to use the special cc_r compiler alias.) # # NOTE: You are assumed to not only compile your program with these flags, # but also link it with them as well. e.g. you should link with # $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS $LIBS # # If you are only building threads programs, you may wish to use these # variables in your default LIBS, CFLAGS, and CC: # # LIBS="$PTHREAD_LIBS $LIBS" # CFLAGS="$CFLAGS $PTHREAD_CFLAGS" # CC="$PTHREAD_CC" # # In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute constant # has a nonstandard name, defines PTHREAD_CREATE_JOINABLE to that name # (e.g. PTHREAD_CREATE_UNDETACHED on AIX). # # Also HAVE_PTHREAD_PRIO_INHERIT is defined if pthread is found and the # PTHREAD_PRIO_INHERIT symbol is defined when compiling with # PTHREAD_CFLAGS. # # ACTION-IF-FOUND is a list of shell commands to run if a threads library # is found, and ACTION-IF-NOT-FOUND is a list of commands to run it if it # is not found. If ACTION-IF-FOUND is not specified, the default action # will define HAVE_PTHREAD. # # Please let the authors know if this macro fails on any platform, or if # you have any other suggestions or comments. This macro was based on work # by SGJ on autoconf scripts for FFTW (http://www.fftw.org/) (with help # from M. Frigo), as well as ac_pthread and hb_pthread macros posted by # Alejandro Forero Cuervo to the autoconf macro repository. We are also # grateful for the helpful feedback of numerous users. # # Updated for Autoconf 2.68 by Daniel Richard G. # # LICENSE # # Copyright (c) 2008 Steven G. Johnson # Copyright (c) 2011 Daniel Richard G. # # This program is free software: you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation, either version 3 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General # Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program. If not, see . # # As a special exception, the respective Autoconf Macro's copyright owner # gives unlimited permission to copy, distribute and modify the configure # scripts that are the output of Autoconf when processing the Macro. You # need not follow the terms of the GNU General Public License when using # or distributing such scripts, even though portions of the text of the # Macro appear in them. The GNU General Public License (GPL) does govern # all other use of the material that constitutes the Autoconf Macro. # # This special exception to the GPL applies to versions of the Autoconf # Macro released by the Autoconf Archive. When you make and distribute a # modified version of the Autoconf Macro, you may extend this special # exception to the GPL to apply to your modified version as well. AU_ALIAS([ACX_PTHREAD], [AX_PTHREAD]) AC_DEFUN([AX_PTHREAD], [ AC_REQUIRE([AC_CANONICAL_HOST]) AC_LANG_PUSH([C]) ax_pthread_ok=no # We used to check for pthread.h first, but this fails if pthread.h # requires special compiler flags (e.g. on True64 or Sequent). # It gets checked for in the link test anyway. # First of all, check if the user has set any of the PTHREAD_LIBS, # etcetera environment variables, and if threads linking works using # them: if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS" save_LIBS="$LIBS" LIBS="$PTHREAD_LIBS $LIBS" AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS]) AC_TRY_LINK_FUNC([pthread_join], [ax_pthread_ok=yes]) AC_MSG_RESULT([$ax_pthread_ok]) if test x"$ax_pthread_ok" = xno; then PTHREAD_LIBS="" PTHREAD_CFLAGS="" fi LIBS="$save_LIBS" CFLAGS="$save_CFLAGS" fi # We must check for the threads library under a number of different # names; the ordering is very important because some systems # (e.g. DEC) have both -lpthread and -lpthreads, where one of the # libraries is broken (non-POSIX). # Create a list of thread flags to try. Items starting with a "-" are # C compiler flags, and other items are library names, except for "none" # which indicates that we try without any flags at all, and "pthread-config" # which is a program returning the flags for the Pth emulation library. ax_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config" # The ordering *is* (sometimes) important. Some notes on the # individual items follow: # pthreads: AIX (must check this before -lpthread) # none: in case threads are in libc; should be tried before -Kthread and # other compiler flags to prevent continual compiler warnings # -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h) # -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able) # lthread: LinuxThreads port on FreeBSD (also preferred to -pthread) # -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads) # -pthreads: Solaris/gcc # -mthreads: Mingw32/gcc, Lynx/gcc # -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it # doesn't hurt to check since this sometimes defines pthreads too; # also defines -D_REENTRANT) # ... -mt is also the pthreads flag for HP/aCC # pthread: Linux, etcetera # --thread-safe: KAI C++ # pthread-config: use pthread-config program (for GNU Pth library) case ${host_os} in solaris*) # On Solaris (at least, for some versions), libc contains stubbed # (non-functional) versions of the pthreads routines, so link-based # tests will erroneously succeed. (We need to link with -pthreads/-mt/ # -lpthread.) (The stubs are missing pthread_cleanup_push, or rather # a function called by this macro, so we could check for that, but # who knows whether they'll stub that too in a future libc.) So, # we'll just look for -pthreads and -lpthread first: ax_pthread_flags="-pthreads pthread -mt -pthread $ax_pthread_flags" ;; darwin*) ax_pthread_flags="-pthread $ax_pthread_flags" ;; esac # Clang doesn't consider unrecognized options an error unless we specify # -Werror. We throw in some extra Clang-specific options to ensure that # this doesn't happen for GCC, which also accepts -Werror. AC_MSG_CHECKING([if compiler needs -Werror to reject unknown flags]) save_CFLAGS="$CFLAGS" ax_pthread_extra_flags="-Werror" CFLAGS="$CFLAGS $ax_pthread_extra_flags -Wunknown-warning-option -Wsizeof-array-argument" AC_COMPILE_IFELSE([AC_LANG_PROGRAM([int foo(void);],[foo()])], [AC_MSG_RESULT([yes])], [ax_pthread_extra_flags= AC_MSG_RESULT([no])]) CFLAGS="$save_CFLAGS" if test x"$ax_pthread_ok" = xno; then for flag in $ax_pthread_flags; do case $flag in none) AC_MSG_CHECKING([whether pthreads work without any flags]) ;; -*) AC_MSG_CHECKING([whether pthreads work with $flag]) PTHREAD_CFLAGS="$flag" ;; pthread-config) AC_CHECK_PROG([ax_pthread_config], [pthread-config], [yes], [no]) if test x"$ax_pthread_config" = xno; then continue; fi PTHREAD_CFLAGS="`pthread-config --cflags`" PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`" ;; *) AC_MSG_CHECKING([for the pthreads library -l$flag]) PTHREAD_LIBS="-l$flag" ;; esac save_LIBS="$LIBS" save_CFLAGS="$CFLAGS" LIBS="$PTHREAD_LIBS $LIBS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS $ax_pthread_extra_flags" # Check for various functions. We must include pthread.h, # since some functions may be macros. (On the Sequent, we # need a special flag -Kthread to make this header compile.) # We check for pthread_join because it is in -lpthread on IRIX # while pthread_create is in libc. We check for pthread_attr_init # due to DEC craziness with -lpthreads. We check for # pthread_cleanup_push because it is one of the few pthread # functions on Solaris that doesn't have a non-functional libc stub. # We try pthread_create on general principles. AC_LINK_IFELSE([AC_LANG_PROGRAM([#include static void routine(void *a) { a = 0; } static void *start_routine(void *a) { return a; }], [pthread_t th; pthread_attr_t attr; pthread_create(&th, 0, start_routine, 0); pthread_join(th, 0); pthread_attr_init(&attr); pthread_cleanup_push(routine, 0); pthread_cleanup_pop(0) /* ; */])], [ax_pthread_ok=yes], []) LIBS="$save_LIBS" CFLAGS="$save_CFLAGS" AC_MSG_RESULT([$ax_pthread_ok]) if test "x$ax_pthread_ok" = xyes; then break; fi PTHREAD_LIBS="" PTHREAD_CFLAGS="" done fi # Various other checks: if test "x$ax_pthread_ok" = xyes; then save_LIBS="$LIBS" LIBS="$PTHREAD_LIBS $LIBS" save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS" # Detect AIX lossage: JOINABLE attribute is called UNDETACHED. AC_MSG_CHECKING([for joinable pthread attribute]) attr_name=unknown for attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do AC_LINK_IFELSE([AC_LANG_PROGRAM([#include ], [int attr = $attr; return attr /* ; */])], [attr_name=$attr; break], []) done AC_MSG_RESULT([$attr_name]) if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then AC_DEFINE_UNQUOTED([PTHREAD_CREATE_JOINABLE], [$attr_name], [Define to necessary symbol if this constant uses a non-standard name on your system.]) fi AC_MSG_CHECKING([if more special flags are required for pthreads]) flag=no case ${host_os} in aix* | freebsd* | darwin*) flag="-D_THREAD_SAFE";; osf* | hpux*) flag="-D_REENTRANT";; solaris*) if test "$GCC" = "yes"; then flag="-D_REENTRANT" else # TODO: What about Clang on Solaris? flag="-mt -D_REENTRANT" fi ;; esac AC_MSG_RESULT([$flag]) if test "x$flag" != xno; then PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS" fi AC_CACHE_CHECK([for PTHREAD_PRIO_INHERIT], [ax_cv_PTHREAD_PRIO_INHERIT], [ AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include ]], [[int i = PTHREAD_PRIO_INHERIT;]])], [ax_cv_PTHREAD_PRIO_INHERIT=yes], [ax_cv_PTHREAD_PRIO_INHERIT=no]) ]) AS_IF([test "x$ax_cv_PTHREAD_PRIO_INHERIT" = "xyes"], [AC_DEFINE([HAVE_PTHREAD_PRIO_INHERIT], [1], [Have PTHREAD_PRIO_INHERIT.])]) LIBS="$save_LIBS" CFLAGS="$save_CFLAGS" # More AIX lossage: compile with *_r variant if test "x$GCC" != xyes; then case $host_os in aix*) AS_CASE(["x/$CC"], [x*/c89|x*/c89_128|x*/c99|x*/c99_128|x*/cc|x*/cc128|x*/xlc|x*/xlc_v6|x*/xlc128|x*/xlc128_v6], [#handle absolute path differently from PATH based program lookup AS_CASE(["x$CC"], [x/*], [AS_IF([AS_EXECUTABLE_P([${CC}_r])],[PTHREAD_CC="${CC}_r"])], [AC_CHECK_PROGS([PTHREAD_CC],[${CC}_r],[$CC])])]) ;; esac fi fi test -n "$PTHREAD_CC" || PTHREAD_CC="$CC" AC_SUBST([PTHREAD_LIBS]) AC_SUBST([PTHREAD_CFLAGS]) AC_SUBST([PTHREAD_CC]) # Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND: if test x"$ax_pthread_ok" = xyes; then ifelse([$1],,[AC_DEFINE([HAVE_PTHREAD],[1],[Define if you have POSIX threads libraries and header files.])],[$1]) : else ax_pthread_ok=no $2 fi AC_LANG_POP ])dnl AX_PTHREAD ocproxy-1.60/autogen.sh000077500000000000000000000001241303453231400151370ustar00rootroot00000000000000#!/bin/bash set -ex autoreconf --force --install --verbose rm -rf autom4te*.cache ocproxy-1.60/build-debian.sh000077500000000000000000000034441303453231400160240ustar00rootroot00000000000000#!/bin/bash gpgkey="BC0B0D65" ppaname="cernekee/ppa" builddir=tmp.debian pkg=ocproxy function build_one { arg="$1" rm -rf $builddir mkdir $builddir pushd $builddir cp ../$tarball "${pkg}_${ver}.orig.tar.gz" mkdir "$pkg-$ver" cd "$pkg-$ver" tar --strip 1 -zxf ../../$tarball cp -a ../../ppa debian if [ "$nosign" = "0" ]; then debuild "$arg" else debuild "$arg" -us -uc fi cd .. lintian -IE --pedantic *.changes | tee -a ../lintian.txt || true popd } # # MAIN # release=0 while [ -n "$1" ]; do case "$1" in -r) release=1 ;; *) echo "usage: $0 [-r]" exit 1 ;; esac shift done tarball=$(ls -1 ${pkg}-*.tar.gz 2> /dev/null || true) if [ -z "$tarball" -o ! -e "$tarball" ]; then echo "missing release tarball" exit 1 fi ver=${tarball#*-} ver=${ver%%.tar.gz} if gpg --list-secret-keys $gpgkey >& /dev/null; then nosign=0 else nosign=1 fi rm -f lintian.txt ${pkg}*.deb touch lintian.txt set -ex dist=$(lsb_release -si) if [ "$dist" = "Ubuntu" ]; then rm -f ppa/changelog codename=$(lsb_release -sc) if [ $release != 1 ]; then today=$(date +%Y%m%d%H%M%S) ver="${ver}~${today}" fi uver="${ver}-1ppa1" dch --create --changelog ppa/changelog --package $pkg \ --newversion "${uver}~${codename}" \ --distribution $codename \ "New PPA build." elif [ ! -e ppa/changelog ]; then dch --create --changelog ppa/changelog --package $pkg \ --newversion "${ver}-1" \ --distribution unstable \ "Test build. (Closes: #12345)" fi build_one "" cp $builddir/*.deb . echo "------------" >> lintian.txt build_one "-S" set +ex echo "--------" echo "lintian:" echo "--------" cat lintian.txt echo "--------" if [ -n "$uver" -a "$nosign" = "0" ]; then echo "" echo "UPLOAD COMMAND:" echo "" echo " dput ppa:$ppaname tmp.debian/*_source.changes" echo "" fi exit 0 ocproxy-1.60/configure.ac000066400000000000000000000034501303453231400154310ustar00rootroot00000000000000AC_PREREQ([2.61]) AC_INIT([ocproxy], [1.60], [dme@dme.org], [ocproxy], [https://github.com/cernekee/ocproxy]) AM_INIT_AUTOMAKE AC_CONFIG_HEADERS([config.h]) AC_CONFIG_MACRO_DIR([m4]) AC_USE_SYSTEM_EXTENSIONS AC_GNU_SOURCE m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) AC_PROG_CC AC_CANONICAL_HOST AC_CONFIG_FILES([Makefile]) # --enable-debug AC_ARG_ENABLE( [debug], [AS_HELP_STRING([--enable-debug],[enable debugging code and output])], [], [enable_debug="no"] ) if test "x$enable_debug" = xyes; then CFLAGS="$CFLAGS -O0 -ggdb" fi # --enable-vpnns case $host_os in *linux*) vpnns_default=yes ;; *) vpnns_default=no ;; esac AC_ARG_ENABLE( [vpnns], [AS_HELP_STRING([--enable-vpnns],[build vpnns binary (Linux only)])], [enable_vpnns="$enableval"], [enable_vpnns="$vpnns_default"] ) if test "x$enable_vpnns" = xyes; then AC_CHECK_HEADERS([linux/if_tun.h sched.h], [], [AC_MSG_ERROR([Missing headers for vpnns])]) fi AM_CONDITIONAL([ENABLE_VPNNS], [test "x$enable_vpnns" = xyes]) EXTRA_PC_LIBS="" AS_COMPILER_FLAGS(WFLAGS, "-Wall -Wextra -Wno-missing-field-initializers -Wno-sign-compare -Wno-pointer-sign -Wno-unused-parameter -Werror=pointer-to-int-cast -Wdeclaration-after-statement -Werror-implicit-function-declaration -Wformat-nonliteral -Wformat-security -Winit-self -Wno-missing-declarations -Wmissing-include-dirs -Wnested-externs -Wpointer-arith -Wwrite-strings") AC_SUBST(WFLAGS, [$WFLAGS]) AC_SEARCH_LIBS([event_add], [event]) AC_CHECK_HEADERS([event2/event.h], [], [AC_MSG_ERROR([Missing development files for libevent2])]) AX_PTHREAD LIBS="$PTHREAD_LIBS $LIBS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS" CC="$PTHREAD_CC" AC_OUTPUT ocproxy-1.60/contrib/000077500000000000000000000000001303453231400146015ustar00rootroot00000000000000ocproxy-1.60/contrib/VERSION000066400000000000000000000000511303453231400156450ustar00rootroot0000000000000036eab8918473ab575ed11c87cee33954a52e6a1d ocproxy-1.60/contrib/apps/000077500000000000000000000000001303453231400155445ustar00rootroot00000000000000ocproxy-1.60/contrib/apps/chargen/000077500000000000000000000000001303453231400171535ustar00rootroot00000000000000ocproxy-1.60/contrib/apps/chargen/README000066400000000000000000000043701303453231400200370ustar00rootroot00000000000000 CHARGEN This file implements a nice example of handling multiple tcp sockets in a server environment. Just call chargen_init() from your application after you have initialized lwip and added your network interfaces. Change the MAX_SERV option to increase or decrease the number of sessions supported. chargen will jam as much data as possible into the output socket, so it will take up a lot of CPU time. Therefore it will be a good idea to run it as the lowest possible priority (just ahead of any idle task). This is also a good example of how to support multiple sessions in an embedded system where you might not have fork(). The multiple sessions are all handled by the same thread and select() is used for demultiplexing. No makefile is provided, just add chargen to the makefile for your application. It is OS and HW independent. Once the chargen server is running in your application, go to another system and open a telnet session to your lwip platform at port 19. You should see an ASCII pattern start to stream on you screen. As an example, lets say that your system running lwip is at IP address 192.168.10.244 and you have a linux system connected to it at IP address 192.168.10.59. Issue the following command at a terminal prompt on the linux system: telnet 192.168.10.244 19 You will see a pattern similar to the following on streaming by on your screen: ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{ BCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{| CDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|} DEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ EFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~! FGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~!" GHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~!"# HIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~!"#$ IJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~!"#$% JKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~!"#$%& KLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~!"#$%&' LMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~!"#$%&'( It even works from windows: At a dos prompt you can also issue the same telnet command and you will get a similar (but much slower, at least on W98) data stream. David Haas ocproxy-1.60/contrib/apps/chargen/chargen.c000066400000000000000000000227731303453231400207410ustar00rootroot00000000000000/** @file * * chargen server for lwip */ /* * Copyright (c) 2003 NBS Card Technology, Paramus, NJ. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: David Haas * * Purpose: chargen server for testing and demonstration purposes * * This file implements a nice example of handling multiple tcp sockets in a * server environment. Just call chargen_init() from your application after * you have initialized lwip and added your network interfaces. Change the * MAX_SERV option to increase or decrease the number of sessions supported. * * chargen will jam as much data as possible into the output socket, so it * will take up a lot of CPU time. Therefore it will be a good idea to run it * as the lowest possible priority (just ahead of any idle task). * * This is also a good example of how to support multiple sessions in an * embedded system where you might not have fork(). */ #include "lwip/opt.h" #include "lwip/sys.h" #include "lwip/sockets.h" #include "lwip/mem.h" #include #include "chargen.h" #if LWIP_SOCKET #define MAX_SERV 5 /* Maximum number of chargen services. Don't need too many */ #define CHARGEN_THREAD_NAME "chargen" #define CHARGEN_PRIORITY 254 /* Really low priority */ #define CHARGEN_THREAD_STACKSIZE 0 #define SEND_SIZE TCP_SNDLOWAT /* If we only send this much, then when select says we can send, we know we won't block */ struct charcb { struct charcb *next; int socket; struct sockaddr_in cliaddr; socklen_t clilen; char nextchar; }; static struct charcb *charcb_list = 0; static int do_read(struct charcb *p_charcb); static void close_chargen(struct charcb *p_charcb); /************************************************************** * void chargen_thread(void *arg) * * chargen task. This server will wait for connections on well * known TCP port number: 19. For every connection, the server will * write as much data as possible to the tcp port. **************************************************************/ static void chargen_thread(void *arg) { int listenfd; struct sockaddr_in chargen_saddr; fd_set readset; fd_set writeset; int i, maxfdp1; struct charcb *p_charcb; LWIP_UNUSED_ARG(arg); /* First acquire our socket for listening for connections */ listenfd = socket(AF_INET, SOCK_STREAM, 0); LWIP_ASSERT("chargen_thread(): Socket create failed.", listenfd >= 0); memset(&chargen_saddr, 0, sizeof(chargen_saddr)); chargen_saddr.sin_family = AF_INET; chargen_saddr.sin_addr.s_addr = PP_HTONL(INADDR_ANY); chargen_saddr.sin_port = htons(19); /* Chargen server port */ if (bind(listenfd, (struct sockaddr *) &chargen_saddr, sizeof(chargen_saddr)) == -1) LWIP_ASSERT("chargen_thread(): Socket bind failed.", 0); /* Put socket into listening mode */ if (listen(listenfd, MAX_SERV) == -1) LWIP_ASSERT("chargen_thread(): Listen failed.", 0); /* Wait forever for network input: This could be connections or data */ for (;;) { maxfdp1 = listenfd+1; /* Determine what sockets need to be in readset */ FD_ZERO(&readset); FD_ZERO(&writeset); FD_SET(listenfd, &readset); for (p_charcb = charcb_list; p_charcb; p_charcb = p_charcb->next) { if (maxfdp1 < p_charcb->socket + 1) maxfdp1 = p_charcb->socket + 1; FD_SET(p_charcb->socket, &readset); FD_SET(p_charcb->socket, &writeset); } /* Wait for data or a new connection */ i = select(maxfdp1, &readset, &writeset, 0, 0); if (i == 0) continue; /* At least one descriptor is ready */ if (FD_ISSET(listenfd, &readset)) { /* We have a new connection request!!! */ /* Lets create a new control block */ p_charcb = (struct charcb *)mem_malloc(sizeof(struct charcb)); if (p_charcb) { p_charcb->socket = accept(listenfd, (struct sockaddr *) &p_charcb->cliaddr, &p_charcb->clilen); if (p_charcb->socket < 0) mem_free(p_charcb); else { /* Keep this tecb in our list */ p_charcb->next = charcb_list; charcb_list = p_charcb; p_charcb->nextchar = 0x21; } } else { /* No memory to accept connection. Just accept and then close */ int sock; struct sockaddr cliaddr; socklen_t clilen; sock = accept(listenfd, &cliaddr, &clilen); if (sock >= 0) close(sock); } } /* Go through list of connected clients and process data */ for (p_charcb = charcb_list; p_charcb; p_charcb = p_charcb->next) { if (FD_ISSET(p_charcb->socket, &readset)) { /* This socket is ready for reading. This could be because someone typed * some characters or it could be because the socket is now closed. Try reading * some data to see. */ if (do_read(p_charcb) < 0) break; } if (FD_ISSET(p_charcb->socket, &writeset)) { char line[80]; char setchar = p_charcb->nextchar; for( i = 0; i < 59; i++) { line[i] = setchar; if (++setchar == 0x7f) setchar = 0x21; } line[i] = 0; strcat(line, "\n\r"); if (write(p_charcb->socket, line, strlen(line)) < 0) { close_chargen(p_charcb); break; } if (++p_charcb->nextchar == 0x7f) p_charcb->nextchar = 0x21; } } } } /************************************************************** * void close_chargen(struct charcb *p_charcb) * * Close the socket and remove this charcb from the list. **************************************************************/ static void close_chargen(struct charcb *p_charcb) { struct charcb *p_search_charcb; /* Either an error or tcp connection closed on other * end. Close here */ close(p_charcb->socket); /* Free charcb */ if (charcb_list == p_charcb) charcb_list = p_charcb->next; else for (p_search_charcb = charcb_list; p_search_charcb; p_search_charcb = p_search_charcb->next) { if (p_search_charcb->next == p_charcb) { p_search_charcb->next = p_charcb->next; break; } } mem_free(p_charcb); } /************************************************************** * void do_read(struct charcb *p_charcb) * * Socket definitely is ready for reading. Read a buffer from the socket and * discard the data. If no data is read, then the socket is closed and the * charcb is removed from the list and freed. **************************************************************/ static int do_read(struct charcb *p_charcb) { char buffer[80]; int readcount; /* Read some data */ readcount = read(p_charcb->socket, &buffer, 80); if (readcount <= 0) { close_chargen(p_charcb); return -1; } return 0; } /************************************************************** * void chargen_init(void) * * This function initializes the chargen service. This function * may only be called either before or after tasking has started. **************************************************************/ void chargen_init(void) { sys_thread_new( CHARGEN_THREAD_NAME, chargen_thread, 0, CHARGEN_THREAD_STACKSIZE, CHARGEN_PRIORITY); } #endif /* LWIP_SOCKET */ ocproxy-1.60/contrib/apps/chargen/chargen.h000066400000000000000000000002501303453231400207300ustar00rootroot00000000000000#ifndef LWIP_CHARGEN_H #define LWIP_CHARGEN_H #include "lwip/opt.h" #if LWIP_SOCKET void chargen_init(void); #endif /* LWIP_SOCKET */ #endif /* LWIP_CHARGEN_H */ ocproxy-1.60/contrib/apps/httpserver/000077500000000000000000000000001303453231400177525ustar00rootroot00000000000000ocproxy-1.60/contrib/apps/httpserver/README000066400000000000000000000005171303453231400206350ustar00rootroot00000000000000HTTPSERVER This is a demonstration of how to make the most basic kind of server using lWIP. * httpserver-raw.c - uses raw TCP calls (coming soon!) * httpserver-netconn.c - uses netconn and netbuf API This code updates the examples in Adam Dunkel's original lwIP documentation to match changes in the code since that PDF release. ocproxy-1.60/contrib/apps/httpserver/httpserver-netconn.c000066400000000000000000000055521303453231400237750ustar00rootroot00000000000000 #include "lwip/opt.h" #include "lwip/arch.h" #include "lwip/api.h" #include "httpserver-netconn.h" #if LWIP_NETCONN #ifndef HTTPD_DEBUG #define HTTPD_DEBUG LWIP_DBG_OFF #endif const static char http_html_hdr[] = "HTTP/1.1 200 OK\r\nContent-type: text/html\r\n\r\n"; const static char http_index_html[] = "Congrats!

Welcome to our lwIP HTTP server!

This is a small test page, served by httpserver-netconn."; /** Serve one HTTP connection accepted in the http thread */ static void http_server_netconn_serve(struct netconn *conn) { struct netbuf *inbuf; char *buf; u16_t buflen; err_t err; /* Read the data from the port, blocking if nothing yet there. We assume the request (the part we care about) is in one netbuf */ err = netconn_recv(conn, &inbuf); if (err == ERR_OK) { netbuf_data(inbuf, (void**)&buf, &buflen); /* Is this an HTTP GET command? (only check the first 5 chars, since there are other formats for GET, and we're keeping it very simple )*/ if (buflen>=5 && buf[0]=='G' && buf[1]=='E' && buf[2]=='T' && buf[3]==' ' && buf[4]=='/' ) { /* Send the HTML header * subtract 1 from the size, since we dont send the \0 in the string * NETCONN_NOCOPY: our data is const static, so no need to copy it */ netconn_write(conn, http_html_hdr, sizeof(http_html_hdr)-1, NETCONN_NOCOPY); /* Send our HTML page */ netconn_write(conn, http_index_html, sizeof(http_index_html)-1, NETCONN_NOCOPY); } } /* Close the connection (server closes in HTTP) */ netconn_close(conn); /* Delete the buffer (netconn_recv gives us ownership, so we have to make sure to deallocate the buffer) */ netbuf_delete(inbuf); } /** The main function, never returns! */ static void http_server_netconn_thread(void *arg) { struct netconn *conn, *newconn; err_t err; LWIP_UNUSED_ARG(arg); /* Create a new TCP connection handle */ conn = netconn_new(NETCONN_TCP); LWIP_ERROR("http_server: invalid conn", (conn != NULL), return;); /* Bind to port 80 (HTTP) with default IP address */ netconn_bind(conn, NULL, 80); /* Put the connection into LISTEN state */ netconn_listen(conn); do { err = netconn_accept(conn, &newconn); if (err == ERR_OK) { http_server_netconn_serve(newconn); netconn_delete(newconn); } } while(err == ERR_OK); LWIP_DEBUGF(HTTPD_DEBUG, ("http_server_netconn_thread: netconn_accept received error %d, shutting down", err)); netconn_close(conn); netconn_delete(conn); } /** Initialize the HTTP server (start its thread) */ void http_server_netconn_init() { sys_thread_new("http_server_netconn", http_server_netconn_thread, NULL, DEFAULT_THREAD_STACKSIZE, DEFAULT_THREAD_PRIO); } #endif /* LWIP_NETCONN*/ ocproxy-1.60/contrib/apps/httpserver/httpserver-netconn.h000066400000000000000000000002161303453231400237720ustar00rootroot00000000000000#ifndef LWIP_HTTPSERVER_NETCONN_H #define LWIP_HTTPSERVER_NETCONN_H void http_server_netconn_init(); #endif /* LWIP_HTTPSERVER_NETCONN_H */ ocproxy-1.60/contrib/apps/httpserver_raw/000077500000000000000000000000001303453231400206235ustar00rootroot00000000000000ocproxy-1.60/contrib/apps/httpserver_raw/fs.c000066400000000000000000000133121303453231400213770ustar00rootroot00000000000000/* * Copyright (c) 2001-2003 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #include "lwip/opt.h" #include "lwip/def.h" #include "fs.h" #include "fsdata.h" #include /** Set this to 1 to include "fsdata_custom.c" instead of "fsdata.c" for the * file system (to prevent changing the file included in CVS) */ #ifndef HTTPD_USE_CUSTOM_FSDATA #define HTTPD_USE_CUSTOM_FSDATA 0 #endif #if HTTPD_USE_CUSTOM_FSDATA #include "fsdata_custom.c" #else /* HTTPD_USE_CUSTOM_FSDATA */ #include "fsdata.c" #endif /* HTTPD_USE_CUSTOM_FSDATA */ /*-----------------------------------------------------------------------------------*/ #if LWIP_HTTPD_CUSTOM_FILES int fs_open_custom(struct fs_file *file, const char *name); void fs_close_custom(struct fs_file *file); #if LWIP_HTTPD_FS_ASYNC_READ u8_t fs_canread_custom(struct fs_file *file); u8_t fs_wait_read_custom(struct fs_file *file, fs_wait_cb callback_fn, void *callback_arg); #endif /* LWIP_HTTPD_FS_ASYNC_READ */ #endif /* LWIP_HTTPD_CUSTOM_FILES */ /*-----------------------------------------------------------------------------------*/ err_t fs_open(struct fs_file *file, const char *name) { const struct fsdata_file *f; if ((file == NULL) || (name == NULL)) { return ERR_ARG; } #if LWIP_HTTPD_CUSTOM_FILES if (fs_open_custom(file, name)) { file->is_custom_file = 1; return ERR_OK; } file->is_custom_file = 0; #endif /* LWIP_HTTPD_CUSTOM_FILES */ for (f = FS_ROOT; f != NULL; f = f->next) { if (!strcmp(name, (char *)f->name)) { file->data = (const char *)f->data; file->len = f->len; file->index = f->len; file->pextension = NULL; file->http_header_included = f->http_header_included; #if HTTPD_PRECALCULATED_CHECKSUM file->chksum_count = f->chksum_count; file->chksum = f->chksum; #endif /* HTTPD_PRECALCULATED_CHECKSUM */ #if LWIP_HTTPD_FILE_STATE file->state = fs_state_init(file, name); #endif /* #if LWIP_HTTPD_FILE_STATE */ return ERR_OK; } } /* file not found */ return ERR_VAL; } /*-----------------------------------------------------------------------------------*/ void fs_close(struct fs_file *file) { #if LWIP_HTTPD_CUSTOM_FILES if (file->is_custom_file) { fs_close_custom(file); } #endif /* LWIP_HTTPD_CUSTOM_FILES */ #if LWIP_HTTPD_FILE_STATE fs_state_free(file, file->state); #endif /* #if LWIP_HTTPD_FILE_STATE */ LWIP_UNUSED_ARG(file); } /*-----------------------------------------------------------------------------------*/ #if LWIP_HTTPD_DYNAMIC_FILE_READ #if LWIP_HTTPD_FS_ASYNC_READ int fs_read_async(struct fs_file *file, char *buffer, int count, fs_wait_cb callback_fn, void *callback_arg) #else /* LWIP_HTTPD_FS_ASYNC_READ */ int fs_read(struct fs_file *file, char *buffer, int count) #endif /* LWIP_HTTPD_FS_ASYNC_READ */ { int read; if(file->index == file->len) { return FS_READ_EOF; } #if LWIP_HTTPD_FS_ASYNC_READ #if LWIP_HTTPD_CUSTOM_FILES if (!fs_canread_custom(file)) { if (fs_wait_read_custom(file, callback_fn, callback_arg)) { return FS_READ_DELAYED; } } #else /* LWIP_HTTPD_CUSTOM_FILES */ LWIP_UNUSED_ARG(callback_fn); LWIP_UNUSED_ARG(callback_arg); #endif /* LWIP_HTTPD_CUSTOM_FILES */ #endif /* LWIP_HTTPD_FS_ASYNC_READ */ read = file->len - file->index; if(read > count) { read = count; } MEMCPY(buffer, (file->data + file->index), read); file->index += read; return(read); } #endif /* LWIP_HTTPD_DYNAMIC_FILE_READ */ /*-----------------------------------------------------------------------------------*/ #if LWIP_HTTPD_FS_ASYNC_READ int fs_is_file_ready(struct fs_file *file, fs_wait_cb callback_fn, void *callback_arg) { if (file != NULL) { #if LWIP_HTTPD_FS_ASYNC_READ #if LWIP_HTTPD_CUSTOM_FILES if (!fs_canread_custom(file)) { if (fs_wait_read_custom(file, callback_fn, callback_arg)) { return 0; } } #else /* LWIP_HTTPD_CUSTOM_FILES */ LWIP_UNUSED_ARG(callback_fn); LWIP_UNUSED_ARG(callback_arg); #endif /* LWIP_HTTPD_CUSTOM_FILES */ #endif /* LWIP_HTTPD_FS_ASYNC_READ */ } return 1; } #endif /* LWIP_HTTPD_FS_ASYNC_READ */ /*-----------------------------------------------------------------------------------*/ int fs_bytes_left(struct fs_file *file) { return file->len - file->index; } ocproxy-1.60/contrib/apps/httpserver_raw/fs.h000066400000000000000000000113031303453231400214020ustar00rootroot00000000000000/* * Copyright (c) 2001-2003 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #ifndef LWIP_FS_H #define LWIP_FS_H #include "lwip/opt.h" #include "lwip/err.h" /** Set this to 1 and provide the functions: * - "int fs_open_custom(struct fs_file *file, const char *name)" * Called first for every opened file to allow opening files * that are not included in fsdata(_custom).c * - "void fs_close_custom(struct fs_file *file)" * Called to free resources allocated by fs_open_custom(). */ #ifndef LWIP_HTTPD_CUSTOM_FILES #define LWIP_HTTPD_CUSTOM_FILES 0 #endif /** Set this to 1 to support fs_read() to dynamically read file data. * Without this (default=off), only one-block files are supported, * and the contents must be ready after fs_open(). */ #ifndef LWIP_HTTPD_DYNAMIC_FILE_READ #define LWIP_HTTPD_DYNAMIC_FILE_READ 0 #endif /** Set this to 1 to include an application state argument per file * that is opened. This allows to keep a state per connection/file. */ #ifndef LWIP_HTTPD_FILE_STATE #define LWIP_HTTPD_FILE_STATE 0 #endif /** HTTPD_PRECALCULATED_CHECKSUM==1: include precompiled checksums for * predefined (MSS-sized) chunks of the files to prevent having to calculate * the checksums at runtime. */ #ifndef HTTPD_PRECALCULATED_CHECKSUM #define HTTPD_PRECALCULATED_CHECKSUM 0 #endif /** LWIP_HTTPD_FS_ASYNC_READ==1: support asynchronous read operations * (fs_read_async returns FS_READ_DELAYED and calls a callback when finished). */ #ifndef LWIP_HTTPD_FS_ASYNC_READ #define LWIP_HTTPD_FS_ASYNC_READ 0 #endif #define FS_READ_EOF -1 #define FS_READ_DELAYED -2 #if HTTPD_PRECALCULATED_CHECKSUM struct fsdata_chksum { u32_t offset; u16_t chksum; u16_t len; }; #endif /* HTTPD_PRECALCULATED_CHECKSUM */ struct fs_file { const char *data; int len; int index; void *pextension; #if HTTPD_PRECALCULATED_CHECKSUM const struct fsdata_chksum *chksum; u16_t chksum_count; #endif /* HTTPD_PRECALCULATED_CHECKSUM */ u8_t http_header_included; #if LWIP_HTTPD_CUSTOM_FILES u8_t is_custom_file; #endif /* LWIP_HTTPD_CUSTOM_FILES */ #if LWIP_HTTPD_FILE_STATE void *state; #endif /* LWIP_HTTPD_FILE_STATE */ }; #if LWIP_HTTPD_FS_ASYNC_READ typedef void (*fs_wait_cb)(void *arg); #endif /* LWIP_HTTPD_FS_ASYNC_READ */ err_t fs_open(struct fs_file *file, const char *name); void fs_close(struct fs_file *file); #if LWIP_HTTPD_DYNAMIC_FILE_READ #if LWIP_HTTPD_FS_ASYNC_READ int fs_read_async(struct fs_file *file, char *buffer, int count, fs_wait_cb callback_fn, void *callback_arg); #else /* LWIP_HTTPD_FS_ASYNC_READ */ int fs_read(struct fs_file *file, char *buffer, int count); #endif /* LWIP_HTTPD_FS_ASYNC_READ */ #endif /* LWIP_HTTPD_DYNAMIC_FILE_READ */ #if LWIP_HTTPD_FS_ASYNC_READ int fs_is_file_ready(struct fs_file *file, fs_wait_cb callback_fn, void *callback_arg); #endif /* LWIP_HTTPD_FS_ASYNC_READ */ int fs_bytes_left(struct fs_file *file); #if LWIP_HTTPD_FILE_STATE /** This user-defined function is called when a file is opened. */ void *fs_state_init(struct fs_file *file, const char *name); /** This user-defined function is called when a file is closed. */ void fs_state_free(struct fs_file *file, void *state); #endif /* #if LWIP_HTTPD_FILE_STATE */ #endif /* LWIP_FS_H */ ocproxy-1.60/contrib/apps/httpserver_raw/fs/000077500000000000000000000000001303453231400212335ustar00rootroot00000000000000ocproxy-1.60/contrib/apps/httpserver_raw/fs/404.html000066400000000000000000000010401303453231400224230ustar00rootroot00000000000000 lwIP - A Lightweight TCP/IP Stack
SICS logo

lwIP - A Lightweight TCP/IP Stack

404 - Page not found

Sorry, the page you are requesting was not found on this server.

 
ocproxy-1.60/contrib/apps/httpserver_raw/fs/img/000077500000000000000000000000001303453231400220075ustar00rootroot00000000000000ocproxy-1.60/contrib/apps/httpserver_raw/fs/img/sics.gif000066400000000000000000000013241303453231400234370ustar00rootroot00000000000000GIF89aF"¥Ù+9jjj¿¿¿“““°°°¦¦¦€€€vvv...IIITTTŠŠŠ```Ʀ™½µ²Â«¡ÙA@ÕgUÀ°ªÕ^NÖPEÌ“}ȡ΋vÒ{eÑ„mÉ™†:::¸¸¸ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ,F"þ@pH,ȤrÉl:ŸÐ¨tJ­Z¯Ø¬v©@¾ƒâ`

øü‡é=F zz|C„x nQŠ„~y€‡‰‘z“ ™x–Ožy”ŸCœ£¤w£ N˜y ƒ¤¦–ªx„»¸Q„Cw¥B±²c » z DدLzG·€¢á}DÐꇓOàšIÎØyf ’)€¶À‘EqF¨\"Nè@$Ÿ>§XÔ“ ‘?èðˆ±!¢I†üRDà)!%P÷g%ýNš´¬úËRSŒòø’-:MI•IÛÄ…)ªç¤IQàS‘Õ)dôÇž "d¥0®«ž—SعýPï“Bt4èœ !ÉhxæU) VOL@Qq‚Àp!"…¾KDꤿ"µðQ8à"ì¬9"ÔÖ“D2‚Èüa³E .ƒ0Ð$p…”îSK2?˜Ó)°®Œ~hà`ZT°xis¢kWÊ=P½0K:Ô«_›=t'ˆ<%à¾zyE °‹ÚÊ€]`"LØW" ˜äV€€Å·Å‚ 6èàƒF(á„Vh¡A;ocproxy-1.60/contrib/apps/httpserver_raw/fs/index.html000066400000000000000000000032501303453231400232300ustar00rootroot00000000000000 lwIP - A Lightweight TCP/IP Stack
SICS logo

lwIP - A Lightweight TCP/IP Stack

The web page you are watching was served by a simple web server running on top of the lightweight TCP/IP stack lwIP.

lwIP is an open source implementation of the TCP/IP protocol suite that was originally written by Adam Dunkels of the Swedish Institute of Computer Science but now is being actively developed by a team of developers distributed world-wide. Since it's release, lwIP has spurred a lot of interest and has been ported to several platforms and operating systems. lwIP can be used either with or without an underlying OS.

The focus of the lwIP TCP/IP implementation is to reduce the RAM usage while still having a full scale TCP. This makes lwIP suitable for use in embedded systems with tens of kilobytes of free RAM and room for around 40 kilobytes of code ROM.

More information about lwIP can be found at the lwIP homepage at http://savannah.nongnu.org/projects/lwip/ or at the lwIP wiki at http://lwip.wikia.com/.

 
ocproxy-1.60/contrib/apps/httpserver_raw/fsdata.c000066400000000000000000000450111303453231400222320ustar00rootroot00000000000000#include "fs.h" #include "lwip/def.h" #include "fsdata.h" #define file_NULL (struct fsdata_file *) NULL static const unsigned int dummy_align__img_sics_gif = 0; static const unsigned char data__img_sics_gif[] = { /* /img/sics.gif (14 chars) */ 0x2f,0x69,0x6d,0x67,0x2f,0x73,0x69,0x63,0x73,0x2e,0x67,0x69,0x66,0x00,0x00,0x00, /* HTTP header */ /* "HTTP/1.0 200 OK " (17 bytes) */ 0x48,0x54,0x54,0x50,0x2f,0x31,0x2e,0x30,0x20,0x32,0x30,0x30,0x20,0x4f,0x4b,0x0d, 0x0a, /* "Server: lwIP/1.3.1 (http://savannah.nongnu.org/projects/lwip) " (63 bytes) */ 0x53,0x65,0x72,0x76,0x65,0x72,0x3a,0x20,0x6c,0x77,0x49,0x50,0x2f,0x31,0x2e,0x33, 0x2e,0x31,0x20,0x28,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x73,0x61,0x76,0x61,0x6e, 0x6e,0x61,0x68,0x2e,0x6e,0x6f,0x6e,0x67,0x6e,0x75,0x2e,0x6f,0x72,0x67,0x2f,0x70, 0x72,0x6f,0x6a,0x65,0x63,0x74,0x73,0x2f,0x6c,0x77,0x69,0x70,0x29,0x0d,0x0a, /* "Content-type: image/gif " (27 bytes) */ 0x43,0x6f,0x6e,0x74,0x65,0x6e,0x74,0x2d,0x74,0x79,0x70,0x65,0x3a,0x20,0x69,0x6d, 0x61,0x67,0x65,0x2f,0x67,0x69,0x66,0x0d,0x0a,0x0d,0x0a, /* raw file data (724 bytes) */ 0x47,0x49,0x46,0x38,0x39,0x61,0x46,0x00,0x22,0x00,0xa5,0x00,0x00,0xd9,0x2b,0x39, 0x6a,0x6a,0x6a,0xbf,0xbf,0xbf,0x93,0x93,0x93,0x0f,0x0f,0x0f,0xb0,0xb0,0xb0,0xa6, 0xa6,0xa6,0x80,0x80,0x80,0x76,0x76,0x76,0x1e,0x1e,0x1e,0x9d,0x9d,0x9d,0x2e,0x2e, 0x2e,0x49,0x49,0x49,0x54,0x54,0x54,0x8a,0x8a,0x8a,0x60,0x60,0x60,0xc6,0xa6,0x99, 0xbd,0xb5,0xb2,0xc2,0xab,0xa1,0xd9,0x41,0x40,0xd5,0x67,0x55,0xc0,0xb0,0xaa,0xd5, 0x5e,0x4e,0xd6,0x50,0x45,0xcc,0x93,0x7d,0xc8,0xa1,0x90,0xce,0x8b,0x76,0xd2,0x7b, 0x65,0xd1,0x84,0x6d,0xc9,0x99,0x86,0x3a,0x3a,0x3a,0x00,0x00,0x00,0xb8,0xb8,0xb8, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x2c,0x00,0x00, 0x00,0x00,0x46,0x00,0x22,0x00,0x00,0x06,0xfe,0x40,0x90,0x70,0x48,0x2c,0x1a,0x8f, 0xc8,0xa4,0x72,0xc9,0x6c,0x3a,0x9f,0xd0,0xa8,0x74,0x4a,0xad,0x5a,0xaf,0xd8,0xac, 0x76,0xa9,0x40,0x04,0xbe,0x83,0xe2,0x60,0x3c,0x50,0x20,0x0d,0x8e,0x6f,0x00,0x31, 0x28,0x1c,0x0d,0x07,0xb5,0xc3,0x60,0x75,0x24,0x3e,0xf8,0xfc,0x87,0x11,0x06,0xe9, 0x3d,0x46,0x07,0x0b,0x7a,0x7a,0x7c,0x43,0x06,0x1e,0x84,0x78,0x0b,0x07,0x6e,0x51, 0x01,0x8a,0x84,0x08,0x7e,0x79,0x80,0x87,0x89,0x91,0x7a,0x93,0x0a,0x04,0x99,0x78, 0x96,0x4f,0x03,0x9e,0x79,0x01,0x94,0x9f,0x43,0x9c,0xa3,0xa4,0x05,0x77,0xa3,0xa0, 0x4e,0x98,0x79,0x0b,0x1e,0x83,0xa4,0xa6,0x1f,0x96,0x05,0x9d,0xaa,0x78,0x01,0x07, 0x84,0x04,0x1e,0x1e,0xbb,0xb8,0x51,0x84,0x0e,0x43,0x05,0x07,0x77,0xa5,0x7f,0x42, 0xb1,0xb2,0x01,0x63,0x08,0x0d,0xbb,0x01,0x0c,0x7a,0x0d,0x44,0x0e,0xd8,0xaf,0x4c, 0x05,0x7a,0x04,0x47,0x07,0x07,0xb7,0x80,0xa2,0xe1,0x7d,0x44,0x05,0x01,0x04,0x01, 0xd0,0xea,0x87,0x93,0x4f,0xe0,0x9a,0x49,0xce,0xd8,0x79,0x04,0x66,0x20,0x15,0x10, 0x10,0x11,0x92,0x29,0x80,0xb6,0xc0,0x91,0x15,0x45,0x1e,0x90,0x19,0x71,0x46,0xa8, 0x5c,0x04,0x0e,0x00,0x22,0x4e,0xe8,0x40,0x24,0x9f,0x3e,0x04,0x06,0xa7,0x58,0xd4, 0x93,0xa0,0x1c,0x91,0x3f,0xe8,0xf0,0x88,0x03,0xb1,0x21,0xa2,0x49,0x00,0x19,0x86, 0xfc,0x52,0x44,0xe0,0x01,0x9d,0x29,0x21,0x15,0x25,0x50,0xf7,0x67,0x25,0x1e,0x06, 0xfd,0x4e,0x9a,0xb4,0x90,0xac,0x15,0xfa,0xcb,0x52,0x53,0x1e,0x8c,0xf2,0xf8,0x07, 0x92,0x2d,0x08,0x3a,0x4d,0x12,0x49,0x95,0x49,0xdb,0x14,0x04,0xc4,0x14,0x85,0x29, 0xaa,0xe7,0x01,0x08,0xa4,0x49,0x01,0x14,0x51,0xe0,0x53,0x91,0xd5,0x29,0x06,0x1a, 0x64,0x02,0xf4,0xc7,0x81,0x9e,0x05,0x20,0x22,0x64,0xa5,0x30,0xae,0xab,0x9e,0x97, 0x53,0xd8,0xb9,0xfd,0x50,0xef,0x93,0x02,0x42,0x74,0x34,0xe8,0x9c,0x20,0x21,0xc9, 0x01,0x68,0x78,0xe6,0x55,0x29,0x20,0x56,0x4f,0x4c,0x40,0x51,0x71,0x82,0xc0,0x70, 0x21,0x22,0x85,0xbe,0x4b,0x1c,0x44,0x05,0xea,0xa4,0x01,0xbf,0x22,0xb5,0xf0,0x1c, 0x06,0x51,0x38,0x8f,0xe0,0x22,0xec,0x18,0xac,0x39,0x22,0xd4,0xd6,0x93,0x44,0x01, 0x32,0x82,0xc8,0xfc,0x61,0xb3,0x01,0x45,0x0c,0x2e,0x83,0x30,0xd0,0x0e,0x17,0x24, 0x0f,0x70,0x85,0x94,0xee,0x05,0x05,0x53,0x4b,0x32,0x1b,0x3f,0x98,0xd3,0x1d,0x29, 0x81,0xb0,0xae,0x1e,0x8c,0x7e,0x68,0xe0,0x60,0x5a,0x54,0x8f,0xb0,0x78,0x69,0x73, 0x06,0xa2,0x00,0x6b,0x57,0xca,0x3d,0x11,0x50,0xbd,0x04,0x30,0x4b,0x3a,0xd4,0xab, 0x5f,0x1f,0x9b,0x3d,0x13,0x74,0x27,0x88,0x3c,0x25,0xe0,0x17,0xbe,0x7a,0x79,0x45, 0x0d,0x0c,0xb0,0x8b,0xda,0x90,0xca,0x80,0x06,0x5d,0x17,0x60,0x1c,0x22,0x4c,0xd8, 0x57,0x22,0x06,0x20,0x00,0x98,0x07,0x08,0xe4,0x56,0x80,0x80,0x1c,0xc5,0xb7,0xc5, 0x82,0x0c,0x36,0xe8,0xe0,0x83,0x10,0x46,0x28,0xe1,0x84,0x14,0x56,0x68,0xa1,0x10, 0x41,0x00,0x00,0x3b,}; static const unsigned int dummy_align__404_html = 1; static const unsigned char data__404_html[] = { /* /404.html (10 chars) */ 0x2f,0x34,0x30,0x34,0x2e,0x68,0x74,0x6d,0x6c,0x00,0x00,0x00, /* HTTP header */ /* "HTTP/1.0 404 File not found " (29 bytes) */ 0x48,0x54,0x54,0x50,0x2f,0x31,0x2e,0x30,0x20,0x34,0x30,0x34,0x20,0x46,0x69,0x6c, 0x65,0x20,0x6e,0x6f,0x74,0x20,0x66,0x6f,0x75,0x6e,0x64,0x0d,0x0a, /* "Server: lwIP/1.3.1 (http://savannah.nongnu.org/projects/lwip) " (63 bytes) */ 0x53,0x65,0x72,0x76,0x65,0x72,0x3a,0x20,0x6c,0x77,0x49,0x50,0x2f,0x31,0x2e,0x33, 0x2e,0x31,0x20,0x28,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x73,0x61,0x76,0x61,0x6e, 0x6e,0x61,0x68,0x2e,0x6e,0x6f,0x6e,0x67,0x6e,0x75,0x2e,0x6f,0x72,0x67,0x2f,0x70, 0x72,0x6f,0x6a,0x65,0x63,0x74,0x73,0x2f,0x6c,0x77,0x69,0x70,0x29,0x0d,0x0a, /* "Content-type: text/html " (27 bytes) */ 0x43,0x6f,0x6e,0x74,0x65,0x6e,0x74,0x2d,0x74,0x79,0x70,0x65,0x3a,0x20,0x74,0x65, 0x78,0x74,0x2f,0x68,0x74,0x6d,0x6c,0x0d,0x0a,0x0d,0x0a, /* raw file data (565 bytes) */ 0x3c,0x68,0x74,0x6d,0x6c,0x3e,0x0d,0x0a,0x3c,0x68,0x65,0x61,0x64,0x3e,0x3c,0x74, 0x69,0x74,0x6c,0x65,0x3e,0x6c,0x77,0x49,0x50,0x20,0x2d,0x20,0x41,0x20,0x4c,0x69, 0x67,0x68,0x74,0x77,0x65,0x69,0x67,0x68,0x74,0x20,0x54,0x43,0x50,0x2f,0x49,0x50, 0x20,0x53,0x74,0x61,0x63,0x6b,0x3c,0x2f,0x74,0x69,0x74,0x6c,0x65,0x3e,0x3c,0x2f, 0x68,0x65,0x61,0x64,0x3e,0x0d,0x0a,0x3c,0x62,0x6f,0x64,0x79,0x20,0x62,0x67,0x63, 0x6f,0x6c,0x6f,0x72,0x3d,0x22,0x77,0x68,0x69,0x74,0x65,0x22,0x20,0x74,0x65,0x78, 0x74,0x3d,0x22,0x62,0x6c,0x61,0x63,0x6b,0x22,0x3e,0x0d,0x0a,0x0d,0x0a,0x20,0x20, 0x20,0x20,0x3c,0x74,0x61,0x62,0x6c,0x65,0x20,0x77,0x69,0x64,0x74,0x68,0x3d,0x22, 0x31,0x30,0x30,0x25,0x22,0x3e,0x0d,0x0a,0x20,0x20,0x20,0x20,0x20,0x20,0x3c,0x74, 0x72,0x20,0x76,0x61,0x6c,0x69,0x67,0x6e,0x3d,0x22,0x74,0x6f,0x70,0x22,0x3e,0x3c, 0x74,0x64,0x20,0x77,0x69,0x64,0x74,0x68,0x3d,0x22,0x38,0x30,0x22,0x3e,0x09,0x20, 0x20,0x0d,0x0a,0x09,0x20,0x20,0x3c,0x61,0x20,0x68,0x72,0x65,0x66,0x3d,0x22,0x68, 0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77,0x77,0x77,0x2e,0x73,0x69,0x63,0x73,0x2e,0x73, 0x65,0x2f,0x22,0x3e,0x3c,0x69,0x6d,0x67,0x20,0x73,0x72,0x63,0x3d,0x22,0x2f,0x69, 0x6d,0x67,0x2f,0x73,0x69,0x63,0x73,0x2e,0x67,0x69,0x66,0x22,0x0d,0x0a,0x09,0x20, 0x20,0x62,0x6f,0x72,0x64,0x65,0x72,0x3d,0x22,0x30,0x22,0x20,0x61,0x6c,0x74,0x3d, 0x22,0x53,0x49,0x43,0x53,0x20,0x6c,0x6f,0x67,0x6f,0x22,0x20,0x74,0x69,0x74,0x6c, 0x65,0x3d,0x22,0x53,0x49,0x43,0x53,0x20,0x6c,0x6f,0x67,0x6f,0x22,0x3e,0x3c,0x2f, 0x61,0x3e,0x0d,0x0a,0x09,0x3c,0x2f,0x74,0x64,0x3e,0x3c,0x74,0x64,0x20,0x77,0x69, 0x64,0x74,0x68,0x3d,0x22,0x35,0x30,0x30,0x22,0x3e,0x09,0x20,0x20,0x0d,0x0a,0x09, 0x20,0x20,0x3c,0x68,0x31,0x3e,0x6c,0x77,0x49,0x50,0x20,0x2d,0x20,0x41,0x20,0x4c, 0x69,0x67,0x68,0x74,0x77,0x65,0x69,0x67,0x68,0x74,0x20,0x54,0x43,0x50,0x2f,0x49, 0x50,0x20,0x53,0x74,0x61,0x63,0x6b,0x3c,0x2f,0x68,0x31,0x3e,0x0d,0x0a,0x09,0x20, 0x20,0x3c,0x68,0x32,0x3e,0x34,0x30,0x34,0x20,0x2d,0x20,0x50,0x61,0x67,0x65,0x20, 0x6e,0x6f,0x74,0x20,0x66,0x6f,0x75,0x6e,0x64,0x3c,0x2f,0x68,0x32,0x3e,0x0d,0x0a, 0x09,0x20,0x20,0x3c,0x70,0x3e,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x53,0x6f,0x72, 0x72,0x79,0x2c,0x20,0x74,0x68,0x65,0x20,0x70,0x61,0x67,0x65,0x20,0x79,0x6f,0x75, 0x20,0x61,0x72,0x65,0x20,0x72,0x65,0x71,0x75,0x65,0x73,0x74,0x69,0x6e,0x67,0x20, 0x77,0x61,0x73,0x20,0x6e,0x6f,0x74,0x20,0x66,0x6f,0x75,0x6e,0x64,0x20,0x6f,0x6e, 0x20,0x74,0x68,0x69,0x73,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x73,0x65,0x72,0x76, 0x65,0x72,0x2e,0x20,0x0d,0x0a,0x09,0x20,0x20,0x3c,0x2f,0x70,0x3e,0x0d,0x0a,0x09, 0x3c,0x2f,0x74,0x64,0x3e,0x3c,0x74,0x64,0x3e,0x0d,0x0a,0x09,0x20,0x20,0x26,0x6e, 0x62,0x73,0x70,0x3b,0x0d,0x0a,0x09,0x3c,0x2f,0x74,0x64,0x3e,0x3c,0x2f,0x74,0x72, 0x3e,0x0d,0x0a,0x20,0x20,0x20,0x20,0x20,0x20,0x3c,0x2f,0x74,0x61,0x62,0x6c,0x65, 0x3e,0x0d,0x0a,0x3c,0x2f,0x62,0x6f,0x64,0x79,0x3e,0x0d,0x0a,0x3c,0x2f,0x68,0x74, 0x6d,0x6c,0x3e,0x0d,0x0a,}; static const unsigned int dummy_align__index_html = 2; static const unsigned char data__index_html[] = { /* /index.html (12 chars) */ 0x2f,0x69,0x6e,0x64,0x65,0x78,0x2e,0x68,0x74,0x6d,0x6c,0x00, /* HTTP header */ /* "HTTP/1.0 200 OK " (17 bytes) */ 0x48,0x54,0x54,0x50,0x2f,0x31,0x2e,0x30,0x20,0x32,0x30,0x30,0x20,0x4f,0x4b,0x0d, 0x0a, /* "Server: lwIP/1.3.1 (http://savannah.nongnu.org/projects/lwip) " (63 bytes) */ 0x53,0x65,0x72,0x76,0x65,0x72,0x3a,0x20,0x6c,0x77,0x49,0x50,0x2f,0x31,0x2e,0x33, 0x2e,0x31,0x20,0x28,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x73,0x61,0x76,0x61,0x6e, 0x6e,0x61,0x68,0x2e,0x6e,0x6f,0x6e,0x67,0x6e,0x75,0x2e,0x6f,0x72,0x67,0x2f,0x70, 0x72,0x6f,0x6a,0x65,0x63,0x74,0x73,0x2f,0x6c,0x77,0x69,0x70,0x29,0x0d,0x0a, /* "Content-type: text/html " (27 bytes) */ 0x43,0x6f,0x6e,0x74,0x65,0x6e,0x74,0x2d,0x74,0x79,0x70,0x65,0x3a,0x20,0x74,0x65, 0x78,0x74,0x2f,0x68,0x74,0x6d,0x6c,0x0d,0x0a,0x0d,0x0a, /* raw file data (1751 bytes) */ 0x3c,0x68,0x74,0x6d,0x6c,0x3e,0x0d,0x0a,0x3c,0x68,0x65,0x61,0x64,0x3e,0x3c,0x74, 0x69,0x74,0x6c,0x65,0x3e,0x6c,0x77,0x49,0x50,0x20,0x2d,0x20,0x41,0x20,0x4c,0x69, 0x67,0x68,0x74,0x77,0x65,0x69,0x67,0x68,0x74,0x20,0x54,0x43,0x50,0x2f,0x49,0x50, 0x20,0x53,0x74,0x61,0x63,0x6b,0x3c,0x2f,0x74,0x69,0x74,0x6c,0x65,0x3e,0x3c,0x2f, 0x68,0x65,0x61,0x64,0x3e,0x0d,0x0a,0x3c,0x62,0x6f,0x64,0x79,0x20,0x62,0x67,0x63, 0x6f,0x6c,0x6f,0x72,0x3d,0x22,0x77,0x68,0x69,0x74,0x65,0x22,0x20,0x74,0x65,0x78, 0x74,0x3d,0x22,0x62,0x6c,0x61,0x63,0x6b,0x22,0x3e,0x0d,0x0a,0x0d,0x0a,0x20,0x20, 0x20,0x20,0x3c,0x74,0x61,0x62,0x6c,0x65,0x20,0x77,0x69,0x64,0x74,0x68,0x3d,0x22, 0x31,0x30,0x30,0x25,0x22,0x3e,0x0d,0x0a,0x20,0x20,0x20,0x20,0x20,0x20,0x3c,0x74, 0x72,0x20,0x76,0x61,0x6c,0x69,0x67,0x6e,0x3d,0x22,0x74,0x6f,0x70,0x22,0x3e,0x3c, 0x74,0x64,0x20,0x77,0x69,0x64,0x74,0x68,0x3d,0x22,0x38,0x30,0x22,0x3e,0x09,0x20, 0x20,0x0d,0x0a,0x09,0x20,0x20,0x3c,0x61,0x20,0x68,0x72,0x65,0x66,0x3d,0x22,0x68, 0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77,0x77,0x77,0x2e,0x73,0x69,0x63,0x73,0x2e,0x73, 0x65,0x2f,0x22,0x3e,0x3c,0x69,0x6d,0x67,0x20,0x73,0x72,0x63,0x3d,0x22,0x2f,0x69, 0x6d,0x67,0x2f,0x73,0x69,0x63,0x73,0x2e,0x67,0x69,0x66,0x22,0x0d,0x0a,0x09,0x20, 0x20,0x62,0x6f,0x72,0x64,0x65,0x72,0x3d,0x22,0x30,0x22,0x20,0x61,0x6c,0x74,0x3d, 0x22,0x53,0x49,0x43,0x53,0x20,0x6c,0x6f,0x67,0x6f,0x22,0x20,0x74,0x69,0x74,0x6c, 0x65,0x3d,0x22,0x53,0x49,0x43,0x53,0x20,0x6c,0x6f,0x67,0x6f,0x22,0x3e,0x3c,0x2f, 0x61,0x3e,0x0d,0x0a,0x09,0x3c,0x2f,0x74,0x64,0x3e,0x3c,0x74,0x64,0x20,0x77,0x69, 0x64,0x74,0x68,0x3d,0x22,0x35,0x30,0x30,0x22,0x3e,0x09,0x20,0x20,0x0d,0x0a,0x09, 0x20,0x20,0x3c,0x68,0x31,0x3e,0x6c,0x77,0x49,0x50,0x20,0x2d,0x20,0x41,0x20,0x4c, 0x69,0x67,0x68,0x74,0x77,0x65,0x69,0x67,0x68,0x74,0x20,0x54,0x43,0x50,0x2f,0x49, 0x50,0x20,0x53,0x74,0x61,0x63,0x6b,0x3c,0x2f,0x68,0x31,0x3e,0x0d,0x0a,0x09,0x20, 0x20,0x3c,0x70,0x3e,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x54,0x68,0x65,0x20,0x77, 0x65,0x62,0x20,0x70,0x61,0x67,0x65,0x20,0x79,0x6f,0x75,0x20,0x61,0x72,0x65,0x20, 0x77,0x61,0x74,0x63,0x68,0x69,0x6e,0x67,0x20,0x77,0x61,0x73,0x20,0x73,0x65,0x72, 0x76,0x65,0x64,0x20,0x62,0x79,0x20,0x61,0x20,0x73,0x69,0x6d,0x70,0x6c,0x65,0x20, 0x77,0x65,0x62,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x73,0x65,0x72,0x76,0x65,0x72, 0x20,0x72,0x75,0x6e,0x6e,0x69,0x6e,0x67,0x20,0x6f,0x6e,0x20,0x74,0x6f,0x70,0x20, 0x6f,0x66,0x20,0x74,0x68,0x65,0x20,0x6c,0x69,0x67,0x68,0x74,0x77,0x65,0x69,0x67, 0x68,0x74,0x20,0x54,0x43,0x50,0x2f,0x49,0x50,0x20,0x73,0x74,0x61,0x63,0x6b,0x20, 0x3c,0x61,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x68,0x72,0x65,0x66,0x3d,0x22,0x68, 0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77,0x77,0x77,0x2e,0x73,0x69,0x63,0x73,0x2e,0x73, 0x65,0x2f,0x7e,0x61,0x64,0x61,0x6d,0x2f,0x6c,0x77,0x69,0x70,0x2f,0x22,0x3e,0x6c, 0x77,0x49,0x50,0x3c,0x2f,0x61,0x3e,0x2e,0x0d,0x0a,0x09,0x20,0x20,0x3c,0x2f,0x70, 0x3e,0x0d,0x0a,0x09,0x20,0x20,0x3c,0x70,0x3e,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20, 0x6c,0x77,0x49,0x50,0x20,0x69,0x73,0x20,0x61,0x6e,0x20,0x6f,0x70,0x65,0x6e,0x20, 0x73,0x6f,0x75,0x72,0x63,0x65,0x20,0x69,0x6d,0x70,0x6c,0x65,0x6d,0x65,0x6e,0x74, 0x61,0x74,0x69,0x6f,0x6e,0x20,0x6f,0x66,0x20,0x74,0x68,0x65,0x20,0x54,0x43,0x50, 0x2f,0x49,0x50,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x70,0x72,0x6f,0x74,0x6f,0x63, 0x6f,0x6c,0x20,0x73,0x75,0x69,0x74,0x65,0x20,0x74,0x68,0x61,0x74,0x20,0x77,0x61, 0x73,0x20,0x6f,0x72,0x69,0x67,0x69,0x6e,0x61,0x6c,0x6c,0x79,0x20,0x77,0x72,0x69, 0x74,0x74,0x65,0x6e,0x20,0x62,0x79,0x20,0x3c,0x61,0x0d,0x0a,0x09,0x20,0x20,0x20, 0x20,0x68,0x72,0x65,0x66,0x3d,0x22,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77,0x77, 0x77,0x2e,0x73,0x69,0x63,0x73,0x2e,0x73,0x65,0x2f,0x7e,0x61,0x64,0x61,0x6d,0x2f, 0x6c,0x77,0x69,0x70,0x2f,0x22,0x3e,0x41,0x64,0x61,0x6d,0x20,0x44,0x75,0x6e,0x6b, 0x65,0x6c,0x73,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x6f,0x66,0x20,0x74,0x68,0x65, 0x20,0x53,0x77,0x65,0x64,0x69,0x73,0x68,0x20,0x49,0x6e,0x73,0x74,0x69,0x74,0x75, 0x74,0x65,0x20,0x6f,0x66,0x20,0x43,0x6f,0x6d,0x70,0x75,0x74,0x65,0x72,0x20,0x53, 0x63,0x69,0x65,0x6e,0x63,0x65,0x3c,0x2f,0x61,0x3e,0x20,0x62,0x75,0x74,0x20,0x6e, 0x6f,0x77,0x20,0x69,0x73,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x62,0x65,0x69,0x6e, 0x67,0x20,0x61,0x63,0x74,0x69,0x76,0x65,0x6c,0x79,0x20,0x64,0x65,0x76,0x65,0x6c, 0x6f,0x70,0x65,0x64,0x20,0x62,0x79,0x20,0x61,0x20,0x74,0x65,0x61,0x6d,0x20,0x6f, 0x66,0x20,0x64,0x65,0x76,0x65,0x6c,0x6f,0x70,0x65,0x72,0x73,0x0d,0x0a,0x09,0x20, 0x20,0x20,0x20,0x64,0x69,0x73,0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x64,0x20,0x77, 0x6f,0x72,0x6c,0x64,0x2d,0x77,0x69,0x64,0x65,0x2e,0x20,0x53,0x69,0x6e,0x63,0x65, 0x20,0x69,0x74,0x27,0x73,0x20,0x72,0x65,0x6c,0x65,0x61,0x73,0x65,0x2c,0x20,0x6c, 0x77,0x49,0x50,0x20,0x68,0x61,0x73,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x73,0x70, 0x75,0x72,0x72,0x65,0x64,0x20,0x61,0x20,0x6c,0x6f,0x74,0x20,0x6f,0x66,0x20,0x69, 0x6e,0x74,0x65,0x72,0x65,0x73,0x74,0x20,0x61,0x6e,0x64,0x20,0x68,0x61,0x73,0x20, 0x62,0x65,0x65,0x6e,0x20,0x70,0x6f,0x72,0x74,0x65,0x64,0x20,0x74,0x6f,0x20,0x73, 0x65,0x76,0x65,0x72,0x61,0x6c,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x70,0x6c,0x61, 0x74,0x66,0x6f,0x72,0x6d,0x73,0x20,0x61,0x6e,0x64,0x20,0x6f,0x70,0x65,0x72,0x61, 0x74,0x69,0x6e,0x67,0x20,0x73,0x79,0x73,0x74,0x65,0x6d,0x73,0x2e,0x20,0x6c,0x77, 0x49,0x50,0x20,0x63,0x61,0x6e,0x20,0x62,0x65,0x20,0x75,0x73,0x65,0x64,0x20,0x65, 0x69,0x74,0x68,0x65,0x72,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x77,0x69,0x74,0x68, 0x20,0x6f,0x72,0x20,0x77,0x69,0x74,0x68,0x6f,0x75,0x74,0x20,0x61,0x6e,0x20,0x75, 0x6e,0x64,0x65,0x72,0x6c,0x79,0x69,0x6e,0x67,0x20,0x4f,0x53,0x2e,0x0d,0x0a,0x09, 0x20,0x20,0x3c,0x2f,0x70,0x3e,0x0d,0x0a,0x09,0x20,0x20,0x3c,0x70,0x3e,0x0d,0x0a, 0x09,0x20,0x20,0x20,0x20,0x54,0x68,0x65,0x20,0x66,0x6f,0x63,0x75,0x73,0x20,0x6f, 0x66,0x20,0x74,0x68,0x65,0x20,0x6c,0x77,0x49,0x50,0x20,0x54,0x43,0x50,0x2f,0x49, 0x50,0x20,0x69,0x6d,0x70,0x6c,0x65,0x6d,0x65,0x6e,0x74,0x61,0x74,0x69,0x6f,0x6e, 0x20,0x69,0x73,0x20,0x74,0x6f,0x20,0x72,0x65,0x64,0x75,0x63,0x65,0x0d,0x0a,0x09, 0x20,0x20,0x20,0x20,0x74,0x68,0x65,0x20,0x52,0x41,0x4d,0x20,0x75,0x73,0x61,0x67, 0x65,0x20,0x77,0x68,0x69,0x6c,0x65,0x20,0x73,0x74,0x69,0x6c,0x6c,0x20,0x68,0x61, 0x76,0x69,0x6e,0x67,0x20,0x61,0x20,0x66,0x75,0x6c,0x6c,0x20,0x73,0x63,0x61,0x6c, 0x65,0x20,0x54,0x43,0x50,0x2e,0x20,0x54,0x68,0x69,0x73,0x0d,0x0a,0x09,0x20,0x20, 0x20,0x20,0x6d,0x61,0x6b,0x65,0x73,0x20,0x6c,0x77,0x49,0x50,0x20,0x73,0x75,0x69, 0x74,0x61,0x62,0x6c,0x65,0x20,0x66,0x6f,0x72,0x20,0x75,0x73,0x65,0x20,0x69,0x6e, 0x20,0x65,0x6d,0x62,0x65,0x64,0x64,0x65,0x64,0x20,0x73,0x79,0x73,0x74,0x65,0x6d, 0x73,0x20,0x77,0x69,0x74,0x68,0x20,0x74,0x65,0x6e,0x73,0x0d,0x0a,0x09,0x20,0x20, 0x20,0x20,0x6f,0x66,0x20,0x6b,0x69,0x6c,0x6f,0x62,0x79,0x74,0x65,0x73,0x20,0x6f, 0x66,0x20,0x66,0x72,0x65,0x65,0x20,0x52,0x41,0x4d,0x20,0x61,0x6e,0x64,0x20,0x72, 0x6f,0x6f,0x6d,0x20,0x66,0x6f,0x72,0x20,0x61,0x72,0x6f,0x75,0x6e,0x64,0x20,0x34, 0x30,0x20,0x6b,0x69,0x6c,0x6f,0x62,0x79,0x74,0x65,0x73,0x0d,0x0a,0x09,0x20,0x20, 0x20,0x20,0x6f,0x66,0x20,0x63,0x6f,0x64,0x65,0x20,0x52,0x4f,0x4d,0x2e,0x0d,0x0a, 0x09,0x20,0x20,0x3c,0x2f,0x70,0x3e,0x0d,0x0a,0x09,0x20,0x20,0x3c,0x70,0x3e,0x0d, 0x0a,0x09,0x20,0x20,0x20,0x20,0x4d,0x6f,0x72,0x65,0x20,0x69,0x6e,0x66,0x6f,0x72, 0x6d,0x61,0x74,0x69,0x6f,0x6e,0x20,0x61,0x62,0x6f,0x75,0x74,0x20,0x6c,0x77,0x49, 0x50,0x20,0x63,0x61,0x6e,0x20,0x62,0x65,0x20,0x66,0x6f,0x75,0x6e,0x64,0x20,0x61, 0x74,0x20,0x74,0x68,0x65,0x20,0x6c,0x77,0x49,0x50,0x0d,0x0a,0x09,0x20,0x20,0x20, 0x20,0x68,0x6f,0x6d,0x65,0x70,0x61,0x67,0x65,0x20,0x61,0x74,0x20,0x3c,0x61,0x0d, 0x0a,0x09,0x20,0x20,0x20,0x20,0x68,0x72,0x65,0x66,0x3d,0x22,0x68,0x74,0x74,0x70, 0x3a,0x2f,0x2f,0x73,0x61,0x76,0x61,0x6e,0x6e,0x61,0x68,0x2e,0x6e,0x6f,0x6e,0x67, 0x6e,0x75,0x2e,0x6f,0x72,0x67,0x2f,0x70,0x72,0x6f,0x6a,0x65,0x63,0x74,0x73,0x2f, 0x6c,0x77,0x69,0x70,0x2f,0x22,0x3e,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x73,0x61, 0x76,0x61,0x6e,0x6e,0x61,0x68,0x2e,0x6e,0x6f,0x6e,0x67,0x6e,0x75,0x2e,0x6f,0x72, 0x67,0x2f,0x70,0x72,0x6f,0x6a,0x65,0x63,0x74,0x73,0x2f,0x6c,0x77,0x69,0x70,0x2f, 0x3c,0x2f,0x61,0x3e,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x6f,0x72,0x20,0x61,0x74, 0x20,0x74,0x68,0x65,0x20,0x6c,0x77,0x49,0x50,0x20,0x77,0x69,0x6b,0x69,0x20,0x61, 0x74,0x20,0x3c,0x61,0x0d,0x0a,0x09,0x20,0x20,0x20,0x20,0x68,0x72,0x65,0x66,0x3d, 0x22,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x6c,0x77,0x69,0x70,0x2e,0x77,0x69,0x6b, 0x69,0x61,0x2e,0x63,0x6f,0x6d,0x2f,0x22,0x3e,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f, 0x6c,0x77,0x69,0x70,0x2e,0x77,0x69,0x6b,0x69,0x61,0x2e,0x63,0x6f,0x6d,0x2f,0x3c, 0x2f,0x61,0x3e,0x2e,0x0d,0x0a,0x09,0x20,0x20,0x3c,0x2f,0x70,0x3e,0x0d,0x0a,0x09, 0x3c,0x2f,0x74,0x64,0x3e,0x3c,0x74,0x64,0x3e,0x0d,0x0a,0x09,0x20,0x20,0x26,0x6e, 0x62,0x73,0x70,0x3b,0x0d,0x0a,0x09,0x3c,0x2f,0x74,0x64,0x3e,0x3c,0x2f,0x74,0x72, 0x3e,0x0d,0x0a,0x20,0x20,0x20,0x20,0x20,0x20,0x3c,0x2f,0x74,0x61,0x62,0x6c,0x65, 0x3e,0x0d,0x0a,0x3c,0x2f,0x62,0x6f,0x64,0x79,0x3e,0x0d,0x0a,0x3c,0x2f,0x68,0x74, 0x6d,0x6c,0x3e,0x0d,0x0a,0x0d,0x0a,}; const struct fsdata_file file__img_sics_gif[] = { { file_NULL, data__img_sics_gif, data__img_sics_gif + 16, sizeof(data__img_sics_gif) - 16, 1, }}; const struct fsdata_file file__404_html[] = { { file__img_sics_gif, data__404_html, data__404_html + 12, sizeof(data__404_html) - 12, 1, }}; const struct fsdata_file file__index_html[] = { { file__404_html, data__index_html, data__index_html + 12, sizeof(data__index_html) - 12, 1, }}; #define FS_ROOT file__index_html #define FS_NUMFILES 3 ocproxy-1.60/contrib/apps/httpserver_raw/fsdata.h000066400000000000000000000037331303453231400222440ustar00rootroot00000000000000/* * Copyright (c) 2001-2003 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #ifndef LWIP_FSDATA_H #define LWIP_FSDATA_H #include "lwip/opt.h" #include "fs.h" struct fsdata_file { const struct fsdata_file *next; const unsigned char *name; const unsigned char *data; int len; u8_t http_header_included; #if HTTPD_PRECALCULATED_CHECKSUM u16_t chksum_count; const struct fsdata_chksum *chksum; #endif /* HTTPD_PRECALCULATED_CHECKSUM */ }; #endif /* LWIP_FSDATA_H */ ocproxy-1.60/contrib/apps/httpserver_raw/httpd.c000066400000000000000000002403221303453231400221150ustar00rootroot00000000000000/* * Copyright (c) 2001-2003 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * Simon Goldschmidt * */ /* This httpd supports for a * rudimentary server-side-include facility which will replace tags of the form * in any file whose extension is .shtml, .shtm or .ssi with * strings provided by an include handler whose pointer is provided to the * module via function http_set_ssi_handler(). * Additionally, a simple common * gateway interface (CGI) handling mechanism has been added to allow clients * to hook functions to particular request URIs. * * To enable SSI support, define label LWIP_HTTPD_SSI in lwipopts.h. * To enable CGI support, define label LWIP_HTTPD_CGI in lwipopts.h. * * By default, the server assumes that HTTP headers are already present in * each file stored in the file system. By defining LWIP_HTTPD_DYNAMIC_HEADERS in * lwipopts.h, this behavior can be changed such that the server inserts the * headers automatically based on the extension of the file being served. If * this mode is used, be careful to ensure that the file system image used * does not already contain the header information. * * File system images without headers can be created using the makefsfile * tool with the -h command line option. * * * Notes about valid SSI tags * -------------------------- * * The following assumptions are made about tags used in SSI markers: * * 1. No tag may contain '-' or whitespace characters within the tag name. * 2. Whitespace is allowed between the tag leadin "". * 3. The maximum tag name length is LWIP_HTTPD_MAX_TAG_NAME_LEN, currently 8 characters. * * Notes on CGI usage * ------------------ * * The simple CGI support offered here works with GET method requests only * and can handle up to 16 parameters encoded into the URI. The handler * function may not write directly to the HTTP output but must return a * filename that the HTTP server will send to the browser as a response to * the incoming CGI request. * * * * The list of supported file types is quite short, so if makefsdata complains * about an unknown extension, make sure to add it (and its doctype) to * the 'g_psHTTPHeaders' list. */ #include "httpd.h" #include "lwip/debug.h" #include "lwip/stats.h" #include "httpd_structs.h" #include "lwip/tcp.h" #include "fs.h" #include #include #if LWIP_TCP #ifndef HTTPD_DEBUG #define HTTPD_DEBUG LWIP_DBG_OFF #endif /** Set this to 1 and add the next line to lwippools.h to use a memp pool * for allocating struct http_state instead of the heap: * * LWIP_MEMPOOL(HTTPD_STATE, 20, 100, "HTTPD_STATE") */ #ifndef HTTPD_USE_MEM_POOL #define HTTPD_USE_MEM_POOL 0 #endif /** The server port for HTTPD to use */ #ifndef HTTPD_SERVER_PORT #define HTTPD_SERVER_PORT 80 #endif /** Maximum retries before the connection is aborted/closed. * - number of times pcb->poll is called -> default is 4*500ms = 2s; * - reset when pcb->sent is called */ #ifndef HTTPD_MAX_RETRIES #define HTTPD_MAX_RETRIES 4 #endif /** The poll delay is X*500ms */ #ifndef HTTPD_POLL_INTERVAL #define HTTPD_POLL_INTERVAL 4 #endif /** Priority for tcp pcbs created by HTTPD (very low by default). * Lower priorities get killed first when running out of memory. */ #ifndef HTTPD_TCP_PRIO #define HTTPD_TCP_PRIO TCP_PRIO_MIN #endif /** Set this to 1 to enable timing each file sent */ #ifndef LWIP_HTTPD_TIMING #define LWIP_HTTPD_TIMING 0 #endif #ifndef HTTPD_DEBUG_TIMING #define HTTPD_DEBUG_TIMING LWIP_DBG_OFF #endif /** Set this to 1 on platforms where strnstr is not available */ #ifndef LWIP_HTTPD_STRNSTR_PRIVATE #define LWIP_HTTPD_STRNSTR_PRIVATE 1 #endif /** Set this to one to show error pages when parsing a request fails instead of simply closing the connection. */ #ifndef LWIP_HTTPD_SUPPORT_EXTSTATUS #define LWIP_HTTPD_SUPPORT_EXTSTATUS 0 #endif /** Set this to 0 to drop support for HTTP/0.9 clients (to save some bytes) */ #ifndef LWIP_HTTPD_SUPPORT_V09 #define LWIP_HTTPD_SUPPORT_V09 1 #endif /** Set this to 1 to enable HTTP/1.1 persistent connections. * ATTENTION: If the generated file system includes HTTP headers, these must * include the "Connection: keep-alive" header (pass argument "-11" to makefsdata). */ #ifndef LWIP_HTTPD_SUPPORT_11_KEEPALIVE #define LWIP_HTTPD_SUPPORT_11_KEEPALIVE 0 #endif /** Set this to 1 to support HTTP request coming in in multiple packets/pbufs */ #ifndef LWIP_HTTPD_SUPPORT_REQUESTLIST #define LWIP_HTTPD_SUPPORT_REQUESTLIST 1 #endif #if LWIP_HTTPD_SUPPORT_REQUESTLIST /** Number of rx pbufs to enqueue to parse an incoming request (up to the first newline) */ #ifndef LWIP_HTTPD_REQ_QUEUELEN #define LWIP_HTTPD_REQ_QUEUELEN 5 #endif /** Number of (TCP payload-) bytes (in pbufs) to enqueue to parse and incoming request (up to the first double-newline) */ #ifndef LWIP_HTTPD_REQ_BUFSIZE #define LWIP_HTTPD_REQ_BUFSIZE LWIP_HTTPD_MAX_REQ_LENGTH #endif /** Defines the maximum length of a HTTP request line (up to the first CRLF, copied from pbuf into this a global buffer when pbuf- or packet-queues are received - otherwise the input pbuf is used directly) */ #ifndef LWIP_HTTPD_MAX_REQ_LENGTH #define LWIP_HTTPD_MAX_REQ_LENGTH LWIP_MIN(1023, (LWIP_HTTPD_REQ_QUEUELEN * PBUF_POOL_BUFSIZE)) #endif #endif /* LWIP_HTTPD_SUPPORT_REQUESTLIST */ /** Maximum length of the filename to send as response to a POST request, * filled in by the application when a POST is finished. */ #ifndef LWIP_HTTPD_POST_MAX_RESPONSE_URI_LEN #define LWIP_HTTPD_POST_MAX_RESPONSE_URI_LEN 63 #endif /** Set this to 0 to not send the SSI tag (default is on, so the tag will * be sent in the HTML page */ #ifndef LWIP_HTTPD_SSI_INCLUDE_TAG #define LWIP_HTTPD_SSI_INCLUDE_TAG 1 #endif /** Set this to 1 to call tcp_abort when tcp_close fails with memory error. * This can be used to prevent consuming all memory in situations where the * HTTP server has low priority compared to other communication. */ #ifndef LWIP_HTTPD_ABORT_ON_CLOSE_MEM_ERROR #define LWIP_HTTPD_ABORT_ON_CLOSE_MEM_ERROR 0 #endif /** Set this to 1 to kill the oldest connection when running out of * memory for 'struct http_state' or 'struct http_ssi_state'. * ATTENTION: This puts all connections on a linked list, so may be kind of slow. */ #ifndef LWIP_HTTPD_KILL_OLD_ON_CONNECTIONS_EXCEEDED #define LWIP_HTTPD_KILL_OLD_ON_CONNECTIONS_EXCEEDED 0 #endif /** Minimum length for a valid HTTP/0.9 request: "GET /\r\n" -> 7 bytes */ #define MIN_REQ_LEN 7 #define CRLF "\r\n" #define HTTP11_CONNECTIONKEEPALIVE "Connection: keep-alive" #if LWIP_HTTPD_SSI #define LWIP_HTTPD_IS_SSI(hs) ((hs)->ssi) #else /* LWIP_HTTPD_SSI */ #define LWIP_HTTPD_IS_SSI(hs) 0 #endif /* LWIP_HTTPD_SSI */ /** These defines check whether tcp_write has to copy data or not */ /** This was TI's check whether to let TCP copy data or not #define HTTP_IS_DATA_VOLATILE(hs) ((hs->file < (char *)0x20000000) ? 0 : TCP_WRITE_FLAG_COPY)*/ #ifndef HTTP_IS_DATA_VOLATILE #if LWIP_HTTPD_SSI /* Copy for SSI files, no copy for non-SSI files */ #define HTTP_IS_DATA_VOLATILE(hs) ((hs)->ssi ? TCP_WRITE_FLAG_COPY : 0) #else /* LWIP_HTTPD_SSI */ /** Default: don't copy if the data is sent from file-system directly */ #define HTTP_IS_DATA_VOLATILE(hs) (((hs->file != NULL) && (hs->handle != NULL) && (hs->file == \ (char*)hs->handle->data + hs->handle->len - hs->left)) \ ? 0 : TCP_WRITE_FLAG_COPY) #endif /* LWIP_HTTPD_SSI */ #endif /** Default: headers are sent from ROM */ #ifndef HTTP_IS_HDR_VOLATILE #define HTTP_IS_HDR_VOLATILE(hs, ptr) 0 #endif #if LWIP_HTTPD_SSI /** Default: Tags are sent from struct http_state and are therefore volatile */ #ifndef HTTP_IS_TAG_VOLATILE #define HTTP_IS_TAG_VOLATILE(ptr) TCP_WRITE_FLAG_COPY #endif #endif /* LWIP_HTTPD_SSI */ /* By default, the httpd is limited to send 2*pcb->mss to keep resource usage low when http is not an important protocol in the device. */ #ifndef HTTPD_LIMIT_SENDING_TO_2MSS #define HTTPD_LIMIT_SENDING_TO_2MSS 1 #endif /* Define this to a function that returns the maximum amount of data to enqueue. The function have this signature: u16_t fn(struct tcp_pcb* pcb); */ #ifndef HTTPD_MAX_WRITE_LEN #if HTTPD_LIMIT_SENDING_TO_2MSS #define HTTPD_MAX_WRITE_LEN(pcb) (2 * tcp_mss(pcb)) #endif #endif /* Return values for http_send_*() */ #define HTTP_DATA_TO_SEND_BREAK 2 #define HTTP_DATA_TO_SEND_CONTINUE 1 #define HTTP_NO_DATA_TO_SEND 0 #if HTTPD_USE_MEM_POOL #define HTTP_ALLOC_SSI_STATE() (struct http_ssi_state *)memp_malloc(MEMP_HTTPD_SSI_STATE) #define HTTP_ALLOC_HTTP_STATE() (struct http_state *)memp_malloc(MEMP_HTTPD_STATE) #else /* HTTPD_USE_MEM_POOL */ #define HTTP_ALLOC_SSI_STATE() (struct http_ssi_state *)mem_malloc(sizeof(struct http_ssi_state)) #define HTTP_ALLOC_HTTP_STATE() (struct http_state *)mem_malloc(sizeof(struct http_state)) #endif /* HTTPD_USE_MEM_POOL */ typedef struct { const char *name; u8_t shtml; } default_filename; const default_filename g_psDefaultFilenames[] = { {"/index.shtml", 1 }, {"/index.ssi", 1 }, {"/index.shtm", 1 }, {"/index.html", 0 }, {"/index.htm", 0 } }; #define NUM_DEFAULT_FILENAMES (sizeof(g_psDefaultFilenames) / \ sizeof(default_filename)) #if LWIP_HTTPD_SUPPORT_REQUESTLIST /** HTTP request is copied here from pbufs for simple parsing */ static char httpd_req_buf[LWIP_HTTPD_MAX_REQ_LENGTH+1]; #endif /* LWIP_HTTPD_SUPPORT_REQUESTLIST */ #if LWIP_HTTPD_SUPPORT_POST /** Filename for response file to send when POST is finished */ static char http_post_response_filename[LWIP_HTTPD_POST_MAX_RESPONSE_URI_LEN+1]; #endif /* LWIP_HTTPD_SUPPORT_POST */ #if LWIP_HTTPD_DYNAMIC_HEADERS /* The number of individual strings that comprise the headers sent before each * requested file. */ #define NUM_FILE_HDR_STRINGS 3 #endif /* LWIP_HTTPD_DYNAMIC_HEADERS */ #if LWIP_HTTPD_SSI #define HTTPD_LAST_TAG_PART 0xFFFF enum tag_check_state { TAG_NONE, /* Not processing an SSI tag */ TAG_LEADIN, /* Tag lead in "" being processed */ TAG_SENDING /* Sending tag replacement string */ }; struct http_ssi_state { const char *parsed; /* Pointer to the first unparsed byte in buf. */ #if !LWIP_HTTPD_SSI_INCLUDE_TAG const char *tag_started;/* Pointer to the first opening '<' of the tag. */ #endif /* !LWIP_HTTPD_SSI_INCLUDE_TAG */ const char *tag_end; /* Pointer to char after the closing '>' of the tag. */ u32_t parse_left; /* Number of unparsed bytes in buf. */ u16_t tag_index; /* Counter used by tag parsing state machine */ u16_t tag_insert_len; /* Length of insert in string tag_insert */ #if LWIP_HTTPD_SSI_MULTIPART u16_t tag_part; /* Counter passed to and changed by tag insertion function to insert multiple times */ #endif /* LWIP_HTTPD_SSI_MULTIPART */ u8_t tag_name_len; /* Length of the tag name in string tag_name */ char tag_name[LWIP_HTTPD_MAX_TAG_NAME_LEN + 1]; /* Last tag name extracted */ char tag_insert[LWIP_HTTPD_MAX_TAG_INSERT_LEN + 1]; /* Insert string for tag_name */ enum tag_check_state tag_state; /* State of the tag processor */ }; #endif /* LWIP_HTTPD_SSI */ struct http_state { #if LWIP_HTTPD_KILL_OLD_ON_CONNECTIONS_EXCEEDED struct http_state *next; #endif /* LWIP_HTTPD_KILL_OLD_ON_CONNECTIONS_EXCEEDED */ struct fs_file file_handle; struct fs_file *handle; char *file; /* Pointer to first unsent byte in buf. */ struct tcp_pcb *pcb; #if LWIP_HTTPD_SUPPORT_REQUESTLIST struct pbuf *req; #endif /* LWIP_HTTPD_SUPPORT_REQUESTLIST */ #if LWIP_HTTPD_DYNAMIC_FILE_READ char *buf; /* File read buffer. */ int buf_len; /* Size of file read buffer, buf. */ #endif /* LWIP_HTTPD_DYNAMIC_FILE_READ */ u32_t left; /* Number of unsent bytes in buf. */ u8_t retries; #if LWIP_HTTPD_SUPPORT_11_KEEPALIVE u8_t keepalive; #endif /* LWIP_HTTPD_SUPPORT_11_KEEPALIVE */ #if LWIP_HTTPD_SSI struct http_ssi_state *ssi; #endif /* LWIP_HTTPD_SSI */ #if LWIP_HTTPD_CGI char *params[LWIP_HTTPD_MAX_CGI_PARAMETERS]; /* Params extracted from the request URI */ char *param_vals[LWIP_HTTPD_MAX_CGI_PARAMETERS]; /* Values for each extracted param */ #endif /* LWIP_HTTPD_CGI */ #if LWIP_HTTPD_DYNAMIC_HEADERS const char *hdrs[NUM_FILE_HDR_STRINGS]; /* HTTP headers to be sent. */ u16_t hdr_pos; /* The position of the first unsent header byte in the current string */ u16_t hdr_index; /* The index of the hdr string currently being sent. */ #endif /* LWIP_HTTPD_DYNAMIC_HEADERS */ #if LWIP_HTTPD_TIMING u32_t time_started; #endif /* LWIP_HTTPD_TIMING */ #if LWIP_HTTPD_SUPPORT_POST u32_t post_content_len_left; #if LWIP_HTTPD_POST_MANUAL_WND u32_t unrecved_bytes; u8_t no_auto_wnd; u8_t post_finished; #endif /* LWIP_HTTPD_POST_MANUAL_WND */ #endif /* LWIP_HTTPD_SUPPORT_POST*/ }; static err_t http_close_conn(struct tcp_pcb *pcb, struct http_state *hs); static err_t http_close_or_abort_conn(struct tcp_pcb *pcb, struct http_state *hs, u8_t abort_conn); static err_t http_find_file(struct http_state *hs, const char *uri, int is_09); static err_t http_init_file(struct http_state *hs, struct fs_file *file, int is_09, const char *uri, u8_t tag_check); static err_t http_poll(void *arg, struct tcp_pcb *pcb); #if LWIP_HTTPD_FS_ASYNC_READ static void http_continue(void *connection); #endif /* LWIP_HTTPD_FS_ASYNC_READ */ #if LWIP_HTTPD_SSI /* SSI insert handler function pointer. */ tSSIHandler g_pfnSSIHandler = NULL; int g_iNumTags = 0; const char **g_ppcTags = NULL; #define LEN_TAG_LEAD_IN 5 const char * const g_pcTagLeadIn = ""; #endif /* LWIP_HTTPD_SSI */ #if LWIP_HTTPD_CGI /* CGI handler information */ const tCGI *g_pCGIs; int g_iNumCGIs; #endif /* LWIP_HTTPD_CGI */ #if LWIP_HTTPD_KILL_OLD_ON_CONNECTIONS_EXCEEDED /** global list of active HTTP connections, use to kill the oldest when running out of memory */ static struct http_state *http_connections; #endif /* LWIP_HTTPD_KILL_OLD_ON_CONNECTIONS_EXCEEDED */ #if LWIP_HTTPD_STRNSTR_PRIVATE /** Like strstr but does not need 'buffer' to be NULL-terminated */ static char* strnstr(const char* buffer, const char* token, size_t n) { const char* p; int tokenlen = (int)strlen(token); if (tokenlen == 0) { return (char *)buffer; } for (p = buffer; *p && (p + tokenlen <= buffer + n); p++) { if ((*p == *token) && (strncmp(p, token, tokenlen) == 0)) { return (char *)p; } } return NULL; } #endif /* LWIP_HTTPD_STRNSTR_PRIVATE */ #if LWIP_HTTPD_KILL_OLD_ON_CONNECTIONS_EXCEEDED static void http_kill_oldest_connection(u8_t ssi_required) { struct http_state *hs = http_connections; struct http_state *hs_free_next = NULL; while(hs && hs->next) { if (ssi_required) { if (hs->next->ssi != NULL) { hs_free_next = hs; } } else { hs_free_next = hs; } hs = hs->next; } if (hs_free_next != NULL) { LWIP_ASSERT("hs_free_next->next != NULL", hs_free_next->next != NULL); LWIP_ASSERT("hs_free_next->next->pcb != NULL", hs_free_next->next->pcb != NULL); /* send RST when killing a connection because of memory shortage */ http_close_or_abort_conn(hs_free_next->next->pcb, hs_free_next->next, 1); /* this also unlinks the http_state from the list */ } } #endif /* LWIP_HTTPD_KILL_OLD_ON_CONNECTIONS_EXCEEDED */ #if LWIP_HTTPD_SSI /** Allocate as struct http_ssi_state. */ static struct http_ssi_state* http_ssi_state_alloc(void) { struct http_ssi_state *ret = HTTP_ALLOC_SSI_STATE(); #if LWIP_HTTPD_KILL_OLD_ON_CONNECTIONS_EXCEEDED if (ret == NULL) { http_kill_oldest_connection(1); ret = HTTP_ALLOC_SSI_STATE(); } #endif /* LWIP_HTTPD_KILL_OLD_ON_CONNECTIONS_EXCEEDED */ if (ret != NULL) { memset(ret, 0, sizeof(struct http_ssi_state)); } return ret; } /** Free a struct http_ssi_state. */ static void http_ssi_state_free(struct http_ssi_state *ssi) { if (ssi != NULL) { #if HTTPD_USE_MEM_POOL memp_free(MEMP_HTTPD_SSI_STATE, ssi); #else /* HTTPD_USE_MEM_POOL */ mem_free(ssi); #endif /* HTTPD_USE_MEM_POOL */ } } #endif /* LWIP_HTTPD_SSI */ /** Initialize a struct http_state. */ static void http_state_init(struct http_state* hs) { /* Initialize the structure. */ memset(hs, 0, sizeof(struct http_state)); #if LWIP_HTTPD_DYNAMIC_HEADERS /* Indicate that the headers are not yet valid */ hs->hdr_index = NUM_FILE_HDR_STRINGS; #endif /* LWIP_HTTPD_DYNAMIC_HEADERS */ } /** Allocate a struct http_state. */ static struct http_state* http_state_alloc(void) { struct http_state *ret = HTTP_ALLOC_HTTP_STATE(); #if LWIP_HTTPD_KILL_OLD_ON_CONNECTIONS_EXCEEDED if (ret == NULL) { http_kill_oldest_connection(0); ret = HTTP_ALLOC_HTTP_STATE(); } #endif /* LWIP_HTTPD_KILL_OLD_ON_CONNECTIONS_EXCEEDED */ if (ret != NULL) { http_state_init(ret); #if LWIP_HTTPD_KILL_OLD_ON_CONNECTIONS_EXCEEDED /* add the connection to the list */ if (http_connections == NULL) { http_connections = ret; } else { struct http_state *last; for(last = http_connections; last->next != NULL; last = last->next); LWIP_ASSERT("last != NULL", last != NULL); last->next = ret; } #endif /* LWIP_HTTPD_KILL_OLD_ON_CONNECTIONS_EXCEEDED */ } return ret; } /** Free a struct http_state. * Also frees the file data if dynamic. */ static void http_state_eof(struct http_state *hs) { if(hs->handle) { #if LWIP_HTTPD_TIMING u32_t ms_needed = sys_now() - hs->time_started; u32_t needed = LWIP_MAX(1, (ms_needed/100)); LWIP_DEBUGF(HTTPD_DEBUG_TIMING, ("httpd: needed %"U32_F" ms to send file of %d bytes -> %"U32_F" bytes/sec\n", ms_needed, hs->handle->len, ((((u32_t)hs->handle->len) * 10) / needed))); #endif /* LWIP_HTTPD_TIMING */ fs_close(hs->handle); hs->handle = NULL; } #if LWIP_HTTPD_DYNAMIC_FILE_READ if (hs->buf != NULL) { mem_free(hs->buf); hs->buf = NULL; } #endif /* LWIP_HTTPD_DYNAMIC_FILE_READ */ #if LWIP_HTTPD_SSI if (hs->ssi) { http_ssi_state_free(hs->ssi); hs->ssi = NULL; } #endif /* LWIP_HTTPD_SSI */ } /** Free a struct http_state. * Also frees the file data if dynamic. */ static void http_state_free(struct http_state *hs) { if (hs != NULL) { http_state_eof(hs); #if LWIP_HTTPD_KILL_OLD_ON_CONNECTIONS_EXCEEDED /* take the connection off the list */ if (http_connections) { if (http_connections == hs) { http_connections = hs->next; } else { struct http_state *last; for(last = http_connections; last->next != NULL; last = last->next) { if (last->next == hs) { last->next = hs->next; break; } } } } #endif /* LWIP_HTTPD_KILL_OLD_ON_CONNECTIONS_EXCEEDED */ #if HTTPD_USE_MEM_POOL memp_free(MEMP_HTTPD_STATE, hs); #else /* HTTPD_USE_MEM_POOL */ mem_free(hs); #endif /* HTTPD_USE_MEM_POOL */ } } /** Call tcp_write() in a loop trying smaller and smaller length * * @param pcb tcp_pcb to send * @param ptr Data to send * @param length Length of data to send (in/out: on return, contains the * amount of data sent) * @param apiflags directly passed to tcp_write * @return the return value of tcp_write */ static err_t http_write(struct tcp_pcb *pcb, const void* ptr, u16_t *length, u8_t apiflags) { u16_t len, max_len; err_t err; LWIP_ASSERT("length != NULL", length != NULL); len = *length; if (len == 0) { return ERR_OK; } /* We cannot send more data than space available in the send buffer. */ max_len = tcp_sndbuf(pcb); if (max_len < len) { len = max_len; } #ifdef HTTPD_MAX_WRITE_LEN /* Additional limitation: e.g. don't enqueue more than 2*mss at once */ max_len = HTTPD_MAX_WRITE_LEN(pcb); if(len > max_len) { len = max_len; } #endif /* HTTPD_MAX_WRITE_LEN */ do { LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("Trying go send %d bytes\n", len)); err = tcp_write(pcb, ptr, len, apiflags); if (err == ERR_MEM) { if ((tcp_sndbuf(pcb) == 0) || (tcp_sndqueuelen(pcb) >= TCP_SND_QUEUELEN)) { /* no need to try smaller sizes */ len = 1; } else { len /= 2; } LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("Send failed, trying less (%d bytes)\n", len)); } } while ((err == ERR_MEM) && (len > 1)); if (err == ERR_OK) { LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("Sent %d bytes\n", len)); *length = len; } else { LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("Send failed with err %d (\"%s\")\n", err, lwip_strerr(err))); *length = 0; } return err; } /** * The connection shall be actively closed (using RST to close from fault states). * Reset the sent- and recv-callbacks. * * @param pcb the tcp pcb to reset callbacks * @param hs connection state to free */ static err_t http_close_or_abort_conn(struct tcp_pcb *pcb, struct http_state *hs, u8_t abort_conn) { err_t err; LWIP_DEBUGF(HTTPD_DEBUG, ("Closing connection %p\n", (void*)pcb)); #if LWIP_HTTPD_SUPPORT_POST if (hs != NULL) { if ((hs->post_content_len_left != 0) #if LWIP_HTTPD_POST_MANUAL_WND || ((hs->no_auto_wnd != 0) && (hs->unrecved_bytes != 0)) #endif /* LWIP_HTTPD_POST_MANUAL_WND */ ) { /* make sure the post code knows that the connection is closed */ http_post_response_filename[0] = 0; httpd_post_finished(hs, http_post_response_filename, LWIP_HTTPD_POST_MAX_RESPONSE_URI_LEN); } } #endif /* LWIP_HTTPD_SUPPORT_POST*/ tcp_arg(pcb, NULL); tcp_recv(pcb, NULL); tcp_err(pcb, NULL); tcp_poll(pcb, NULL, 0); tcp_sent(pcb, NULL); if (hs != NULL) { http_state_free(hs); } if (abort_conn) { tcp_abort(pcb); return ERR_OK; } err = tcp_close(pcb); if (err != ERR_OK) { LWIP_DEBUGF(HTTPD_DEBUG, ("Error %d closing %p\n", err, (void*)pcb)); /* error closing, try again later in poll */ tcp_poll(pcb, http_poll, HTTPD_POLL_INTERVAL); } return err; } /** * The connection shall be actively closed. * Reset the sent- and recv-callbacks. * * @param pcb the tcp pcb to reset callbacks * @param hs connection state to free */ static err_t http_close_conn(struct tcp_pcb *pcb, struct http_state *hs) { return http_close_or_abort_conn(pcb, hs, 0); } /** End of file: either close the connection (Connection: close) or * close the file (Connection: keep-alive) */ static void http_eof(struct tcp_pcb *pcb, struct http_state *hs) { /* HTTP/1.1 persistent connection? (Not supported for SSI) */ #if LWIP_HTTPD_SUPPORT_11_KEEPALIVE if (hs->keepalive && !LWIP_HTTPD_IS_SSI(hs)) { http_state_eof(hs); http_state_init(hs); hs->keepalive = 1; } else #endif /* LWIP_HTTPD_SUPPORT_11_KEEPALIVE */ { http_close_conn(pcb, hs); } } #if LWIP_HTTPD_CGI /** * Extract URI parameters from the parameter-part of an URI in the form * "test.cgi?x=y" @todo: better explanation! * Pointers to the parameters are stored in hs->param_vals. * * @param hs http connection state * @param params pointer to the NULL-terminated parameter string from the URI * @return number of parameters extracted */ static int extract_uri_parameters(struct http_state *hs, char *params) { char *pair; char *equals; int loop; /* If we have no parameters at all, return immediately. */ if(!params || (params[0] == '\0')) { return(0); } /* Get a pointer to our first parameter */ pair = params; /* Parse up to LWIP_HTTPD_MAX_CGI_PARAMETERS from the passed string and ignore the * remainder (if any) */ for(loop = 0; (loop < LWIP_HTTPD_MAX_CGI_PARAMETERS) && pair; loop++) { /* Save the name of the parameter */ hs->params[loop] = pair; /* Remember the start of this name=value pair */ equals = pair; /* Find the start of the next name=value pair and replace the delimiter * with a 0 to terminate the previous pair string. */ pair = strchr(pair, '&'); if(pair) { *pair = '\0'; pair++; } else { /* We didn't find a new parameter so find the end of the URI and * replace the space with a '\0' */ pair = strchr(equals, ' '); if(pair) { *pair = '\0'; } /* Revert to NULL so that we exit the loop as expected. */ pair = NULL; } /* Now find the '=' in the previous pair, replace it with '\0' and save * the parameter value string. */ equals = strchr(equals, '='); if(equals) { *equals = '\0'; hs->param_vals[loop] = equals + 1; } else { hs->param_vals[loop] = NULL; } } return loop; } #endif /* LWIP_HTTPD_CGI */ #if LWIP_HTTPD_SSI /** * Insert a tag (found in an shtml in the form of "" into the file. * The tag's name is stored in ssi->tag_name (NULL-terminated), the replacement * should be written to hs->tag_insert (up to a length of LWIP_HTTPD_MAX_TAG_INSERT_LEN). * The amount of data written is stored to ssi->tag_insert_len. * * @todo: return tag_insert_len - maybe it can be removed from struct http_state? * * @param hs http connection state */ static void get_tag_insert(struct http_state *hs) { int loop; size_t len; struct http_ssi_state *ssi; LWIP_ASSERT("hs != NULL", hs != NULL); ssi = hs->ssi; LWIP_ASSERT("ssi != NULL", ssi != NULL); #if LWIP_HTTPD_SSI_MULTIPART u16_t current_tag_part = ssi->tag_part; ssi->tag_part = HTTPD_LAST_TAG_PART; #endif /* LWIP_HTTPD_SSI_MULTIPART */ if(g_pfnSSIHandler && g_ppcTags && g_iNumTags) { /* Find this tag in the list we have been provided. */ for(loop = 0; loop < g_iNumTags; loop++) { if(strcmp(ssi->tag_name, g_ppcTags[loop]) == 0) { ssi->tag_insert_len = g_pfnSSIHandler(loop, ssi->tag_insert, LWIP_HTTPD_MAX_TAG_INSERT_LEN #if LWIP_HTTPD_SSI_MULTIPART , current_tag_part, &ssi->tag_part #endif /* LWIP_HTTPD_SSI_MULTIPART */ #if LWIP_HTTPD_FILE_STATE , hs->handle->state #endif /* LWIP_HTTPD_FILE_STATE */ ); return; } } } /* If we drop out, we were asked to serve a page which contains tags that * we don't have a handler for. Merely echo back the tags with an error * marker. */ #define UNKNOWN_TAG1_TEXT "***UNKNOWN TAG " #define UNKNOWN_TAG1_LEN 18 #define UNKNOWN_TAG2_TEXT "***" #define UNKNOWN_TAG2_LEN 7 len = LWIP_MIN(sizeof(ssi->tag_name), LWIP_MIN(strlen(ssi->tag_name), LWIP_HTTPD_MAX_TAG_INSERT_LEN - (UNKNOWN_TAG1_LEN + UNKNOWN_TAG2_LEN))); MEMCPY(ssi->tag_insert, UNKNOWN_TAG1_TEXT, UNKNOWN_TAG1_LEN); MEMCPY(&ssi->tag_insert[UNKNOWN_TAG1_LEN], ssi->tag_name, len); MEMCPY(&ssi->tag_insert[UNKNOWN_TAG1_LEN + len], UNKNOWN_TAG2_TEXT, UNKNOWN_TAG2_LEN); ssi->tag_insert[UNKNOWN_TAG1_LEN + len + UNKNOWN_TAG2_LEN] = 0; len = strlen(ssi->tag_insert); LWIP_ASSERT("len <= 0xffff", len <= 0xffff); ssi->tag_insert_len = (u16_t)len; } #endif /* LWIP_HTTPD_SSI */ #if LWIP_HTTPD_DYNAMIC_HEADERS /** * Generate the relevant HTTP headers for the given filename and write * them into the supplied buffer. */ static void get_http_headers(struct http_state *pState, char *pszURI) { unsigned int iLoop; char *pszWork; char *pszExt; char *pszVars; /* Ensure that we initialize the loop counter. */ iLoop = 0; /* In all cases, the second header we send is the server identification so set it here. */ pState->hdrs[1] = g_psHTTPHeaderStrings[HTTP_HDR_SERVER]; /* Is this a normal file or the special case we use to send back the default "404: Page not found" response? */ if (pszURI == NULL) { pState->hdrs[0] = g_psHTTPHeaderStrings[HTTP_HDR_NOT_FOUND]; pState->hdrs[2] = g_psHTTPHeaderStrings[DEFAULT_404_HTML]; /* Set up to send the first header string. */ pState->hdr_index = 0; pState->hdr_pos = 0; return; } else { /* We are dealing with a particular filename. Look for one other special case. We assume that any filename with "404" in it must be indicative of a 404 server error whereas all other files require the 200 OK header. */ if (strstr(pszURI, "404")) { pState->hdrs[0] = g_psHTTPHeaderStrings[HTTP_HDR_NOT_FOUND]; } else if (strstr(pszURI, "400")) { pState->hdrs[0] = g_psHTTPHeaderStrings[HTTP_HDR_BAD_REQUEST]; } else if (strstr(pszURI, "501")) { pState->hdrs[0] = g_psHTTPHeaderStrings[HTTP_HDR_NOT_IMPL]; } else { pState->hdrs[0] = g_psHTTPHeaderStrings[HTTP_HDR_OK]; } /* Determine if the URI has any variables and, if so, temporarily remove them. */ pszVars = strchr(pszURI, '?'); if(pszVars) { *pszVars = '\0'; } /* Get a pointer to the file extension. We find this by looking for the last occurrence of "." in the filename passed. */ pszExt = NULL; pszWork = strchr(pszURI, '.'); while(pszWork) { pszExt = pszWork + 1; pszWork = strchr(pszExt, '.'); } /* Now determine the content type and add the relevant header for that. */ for(iLoop = 0; (iLoop < NUM_HTTP_HEADERS) && pszExt; iLoop++) { /* Have we found a matching extension? */ if(!strcmp(g_psHTTPHeaders[iLoop].extension, pszExt)) { pState->hdrs[2] = g_psHTTPHeaderStrings[g_psHTTPHeaders[iLoop].headerIndex]; break; } } /* Reinstate the parameter marker if there was one in the original URI. */ if(pszVars) { *pszVars = '?'; } } /* Does the URL passed have any file extension? If not, we assume it is a special-case URL used for control state notification and we do not send any HTTP headers with the response. */ if(!pszExt) { /* Force the header index to a value indicating that all headers have already been sent. */ pState->hdr_index = NUM_FILE_HDR_STRINGS; } else { /* Did we find a matching extension? */ if(iLoop == NUM_HTTP_HEADERS) { /* No - use the default, plain text file type. */ pState->hdrs[2] = g_psHTTPHeaderStrings[HTTP_HDR_DEFAULT_TYPE]; } /* Set up to send the first header string. */ pState->hdr_index = 0; pState->hdr_pos = 0; } } /** Sub-function of http_send(): send dynamic headers * * @returns: - HTTP_NO_DATA_TO_SEND: no new data has been enqueued * - HTTP_DATA_TO_SEND_CONTINUE: continue with sending HTTP body * - HTTP_DATA_TO_SEND_BREAK: data has been enqueued, headers pending, * so don't send HTTP body yet */ static u8_t http_send_headers(struct tcp_pcb *pcb, struct http_state *hs) { err_t err; u16_t len; u8_t data_to_send = HTTP_NO_DATA_TO_SEND; u16_t hdrlen, sendlen; /* How much data can we send? */ len = tcp_sndbuf(pcb); sendlen = len; while(len && (hs->hdr_index < NUM_FILE_HDR_STRINGS) && sendlen) { const void *ptr; u16_t old_sendlen; /* How much do we have to send from the current header? */ hdrlen = (u16_t)strlen(hs->hdrs[hs->hdr_index]); /* How much of this can we send? */ sendlen = (len < (hdrlen - hs->hdr_pos)) ? len : (hdrlen - hs->hdr_pos); /* Send this amount of data or as much as we can given memory * constraints. */ ptr = (const void *)(hs->hdrs[hs->hdr_index] + hs->hdr_pos); old_sendlen = sendlen; err = http_write(pcb, ptr, &sendlen, HTTP_IS_HDR_VOLATILE(hs, ptr)); if ((err == ERR_OK) && (old_sendlen != sendlen)) { /* Remember that we added some more data to be transmitted. */ data_to_send = HTTP_DATA_TO_SEND_CONTINUE; } /* Fix up the header position for the next time round. */ hs->hdr_pos += sendlen; len -= sendlen; /* Have we finished sending this string? */ if(hs->hdr_pos == hdrlen) { /* Yes - move on to the next one */ hs->hdr_index++; hs->hdr_pos = 0; } } /* If we get here and there are still header bytes to send, we send * the header information we just wrote immediately. If there are no * more headers to send, but we do have file data to send, drop through * to try to send some file data too. */ if((hs->hdr_index < NUM_FILE_HDR_STRINGS) || !hs->file) { LWIP_DEBUGF(HTTPD_DEBUG, ("tcp_output\n")); return HTTP_DATA_TO_SEND_BREAK; } return data_to_send; } #endif /* LWIP_HTTPD_DYNAMIC_HEADERS */ /** Sub-function of http_send(): end-of-file (or block) is reached, * either close the file or read the next block (if supported). * * @returns: 0 if the file is finished or no data has been read * 1 if the file is not finished and data has been read */ static u8_t http_check_eof(struct tcp_pcb *pcb, struct http_state *hs) { #if LWIP_HTTPD_DYNAMIC_FILE_READ int count; #endif /* LWIP_HTTPD_DYNAMIC_FILE_READ */ /* Do we have a valid file handle? */ if (hs->handle == NULL) { /* No - close the connection. */ http_eof(pcb, hs); return 0; } if (fs_bytes_left(hs->handle) <= 0) { /* We reached the end of the file so this request is done. */ LWIP_DEBUGF(HTTPD_DEBUG, ("End of file.\n")); http_eof(pcb, hs); return 0; } #if LWIP_HTTPD_DYNAMIC_FILE_READ /* Do we already have a send buffer allocated? */ if(hs->buf) { /* Yes - get the length of the buffer */ count = hs->buf_len; } else { /* We don't have a send buffer so allocate one up to 2mss bytes long. */ #ifdef HTTPD_MAX_WRITE_LEN count = HTTPD_MAX_WRITE_LEN(pcb); #else /* HTTPD_MAX_WRITE_LEN */ count = 2 * tcp_mss(pcb); #endif /* HTTPD_MAX_WRITE_LEN */ do { hs->buf = (char*)mem_malloc((mem_size_t)count); if (hs->buf != NULL) { hs->buf_len = count; break; } count = count / 2; } while (count > 100); /* Did we get a send buffer? If not, return immediately. */ if (hs->buf == NULL) { LWIP_DEBUGF(HTTPD_DEBUG, ("No buff\n")); return 0; } } /* Read a block of data from the file. */ LWIP_DEBUGF(HTTPD_DEBUG, ("Trying to read %d bytes.\n", count)); #if LWIP_HTTPD_FS_ASYNC_READ count = fs_read_async(hs->handle, hs->buf, count, http_continue, hs); #else /* LWIP_HTTPD_FS_ASYNC_READ */ count = fs_read(hs->handle, hs->buf, count); #endif /* LWIP_HTTPD_FS_ASYNC_READ */ if (count < 0) { if (count == FS_READ_DELAYED) { /* Delayed read, wait for FS to unblock us */ return 0; } /* We reached the end of the file so this request is done. * @todo: don't close here for HTTP/1.1? */ LWIP_DEBUGF(HTTPD_DEBUG, ("End of file.\n")); http_eof(pcb, hs); return 0; } /* Set up to send the block of data we just read */ LWIP_DEBUGF(HTTPD_DEBUG, ("Read %d bytes.\n", count)); hs->left = count; hs->file = hs->buf; #if LWIP_HTTPD_SSI if (hs->ssi) { hs->ssi->parse_left = count; hs->ssi->parsed = hs->buf; } #endif /* LWIP_HTTPD_SSI */ #else /* LWIP_HTTPD_DYNAMIC_FILE_READ */ LWIP_ASSERT("SSI and DYNAMIC_HEADERS turned off but eof not reached", 0); #endif /* LWIP_HTTPD_SSI || LWIP_HTTPD_DYNAMIC_HEADERS */ return 1; } /** Sub-function of http_send(): This is the normal send-routine for non-ssi files * * @returns: - 1: data has been written (so call tcp_ouput) * - 0: no data has been written (no need to call tcp_output) */ static u8_t http_send_data_nonssi(struct tcp_pcb *pcb, struct http_state *hs) { err_t err; u16_t len; u8_t data_to_send = 0; /* We are not processing an SHTML file so no tag checking is necessary. * Just send the data as we received it from the file. */ len = (u16_t)LWIP_MIN(hs->left, 0xffff); err = http_write(pcb, hs->file, &len, HTTP_IS_DATA_VOLATILE(hs)); if (err == ERR_OK) { data_to_send = 1; hs->file += len; hs->left -= len; } return data_to_send; } #if LWIP_HTTPD_SSI /** Sub-function of http_send(): This is the send-routine for ssi files * * @returns: - 1: data has been written (so call tcp_ouput) * - 0: no data has been written (no need to call tcp_output) */ static u8_t http_send_data_ssi(struct tcp_pcb *pcb, struct http_state *hs) { err_t err = ERR_OK; u16_t len; u8_t data_to_send = 0; struct http_ssi_state *ssi = hs->ssi; LWIP_ASSERT("ssi != NULL", ssi != NULL); /* We are processing an SHTML file so need to scan for tags and replace * them with insert strings. We need to be careful here since a tag may * straddle the boundary of two blocks read from the file and we may also * have to split the insert string between two tcp_write operations. */ /* How much data could we send? */ len = tcp_sndbuf(pcb); /* Do we have remaining data to send before parsing more? */ if(ssi->parsed > hs->file) { len = (u16_t)LWIP_MIN(ssi->parsed - hs->file, 0xffff); err = http_write(pcb, hs->file, &len, HTTP_IS_DATA_VOLATILE(hs)); if (err == ERR_OK) { data_to_send = 1; hs->file += len; hs->left -= len; } /* If the send buffer is full, return now. */ if(tcp_sndbuf(pcb) == 0) { return data_to_send; } } LWIP_DEBUGF(HTTPD_DEBUG, ("State %d, %d left\n", ssi->tag_state, (int)ssi->parse_left)); /* We have sent all the data that was already parsed so continue parsing * the buffer contents looking for SSI tags. */ while((ssi->parse_left) && (err == ERR_OK)) { if (len == 0) { return data_to_send; } switch(ssi->tag_state) { case TAG_NONE: /* We are not currently processing an SSI tag so scan for the * start of the lead-in marker. */ if(*ssi->parsed == g_pcTagLeadIn[0]) { /* We found what could be the lead-in for a new tag so change * state appropriately. */ ssi->tag_state = TAG_LEADIN; ssi->tag_index = 1; #if !LWIP_HTTPD_SSI_INCLUDE_TAG ssi->tag_started = ssi->parsed; #endif /* !LWIP_HTTPD_SSI_INCLUDE_TAG */ } /* Move on to the next character in the buffer */ ssi->parse_left--; ssi->parsed++; break; case TAG_LEADIN: /* We are processing the lead-in marker, looking for the start of * the tag name. */ /* Have we reached the end of the leadin? */ if(ssi->tag_index == LEN_TAG_LEAD_IN) { ssi->tag_index = 0; ssi->tag_state = TAG_FOUND; } else { /* Have we found the next character we expect for the tag leadin? */ if(*ssi->parsed == g_pcTagLeadIn[ssi->tag_index]) { /* Yes - move to the next one unless we have found the complete * leadin, in which case we start looking for the tag itself */ ssi->tag_index++; } else { /* We found an unexpected character so this is not a tag. Move * back to idle state. */ ssi->tag_state = TAG_NONE; } /* Move on to the next character in the buffer */ ssi->parse_left--; ssi->parsed++; } break; case TAG_FOUND: /* We are reading the tag name, looking for the start of the * lead-out marker and removing any whitespace found. */ /* Remove leading whitespace between the tag leading and the first * tag name character. */ if((ssi->tag_index == 0) && ((*ssi->parsed == ' ') || (*ssi->parsed == '\t') || (*ssi->parsed == '\n') || (*ssi->parsed == '\r'))) { /* Move on to the next character in the buffer */ ssi->parse_left--; ssi->parsed++; break; } /* Have we found the end of the tag name? This is signalled by * us finding the first leadout character or whitespace */ if((*ssi->parsed == g_pcTagLeadOut[0]) || (*ssi->parsed == ' ') || (*ssi->parsed == '\t') || (*ssi->parsed == '\n') || (*ssi->parsed == '\r')) { if(ssi->tag_index == 0) { /* We read a zero length tag so ignore it. */ ssi->tag_state = TAG_NONE; } else { /* We read a non-empty tag so go ahead and look for the * leadout string. */ ssi->tag_state = TAG_LEADOUT; LWIP_ASSERT("ssi->tag_index <= 0xff", ssi->tag_index <= 0xff); ssi->tag_name_len = (u8_t)ssi->tag_index; ssi->tag_name[ssi->tag_index] = '\0'; if(*ssi->parsed == g_pcTagLeadOut[0]) { ssi->tag_index = 1; } else { ssi->tag_index = 0; } } } else { /* This character is part of the tag name so save it */ if(ssi->tag_index < LWIP_HTTPD_MAX_TAG_NAME_LEN) { ssi->tag_name[ssi->tag_index++] = *ssi->parsed; } else { /* The tag was too long so ignore it. */ ssi->tag_state = TAG_NONE; } } /* Move on to the next character in the buffer */ ssi->parse_left--; ssi->parsed++; break; /* We are looking for the end of the lead-out marker. */ case TAG_LEADOUT: /* Remove leading whitespace between the tag leading and the first * tag leadout character. */ if((ssi->tag_index == 0) && ((*ssi->parsed == ' ') || (*ssi->parsed == '\t') || (*ssi->parsed == '\n') || (*ssi->parsed == '\r'))) { /* Move on to the next character in the buffer */ ssi->parse_left--; ssi->parsed++; break; } /* Have we found the next character we expect for the tag leadout? */ if(*ssi->parsed == g_pcTagLeadOut[ssi->tag_index]) { /* Yes - move to the next one unless we have found the complete * leadout, in which case we need to call the client to process * the tag. */ /* Move on to the next character in the buffer */ ssi->parse_left--; ssi->parsed++; if(ssi->tag_index == (LEN_TAG_LEAD_OUT - 1)) { /* Call the client to ask for the insert string for the * tag we just found. */ #if LWIP_HTTPD_SSI_MULTIPART ssi->tag_part = 0; /* start with tag part 0 */ #endif /* LWIP_HTTPD_SSI_MULTIPART */ get_tag_insert(hs); /* Next time through, we are going to be sending data * immediately, either the end of the block we start * sending here or the insert string. */ ssi->tag_index = 0; ssi->tag_state = TAG_SENDING; ssi->tag_end = ssi->parsed; #if !LWIP_HTTPD_SSI_INCLUDE_TAG ssi->parsed = ssi->tag_started; #endif /* !LWIP_HTTPD_SSI_INCLUDE_TAG*/ /* If there is any unsent data in the buffer prior to the * tag, we need to send it now. */ if (ssi->tag_end > hs->file) { /* How much of the data can we send? */ #if LWIP_HTTPD_SSI_INCLUDE_TAG len = (u16_t)LWIP_MIN(ssi->tag_end - hs->file, 0xffff); #else /* LWIP_HTTPD_SSI_INCLUDE_TAG*/ /* we would include the tag in sending */ len = (u16_t)LWIP_MIN(ssi->tag_started - hs->file, 0xffff); #endif /* LWIP_HTTPD_SSI_INCLUDE_TAG*/ err = http_write(pcb, hs->file, &len, HTTP_IS_DATA_VOLATILE(hs)); if (err == ERR_OK) { data_to_send = 1; #if !LWIP_HTTPD_SSI_INCLUDE_TAG if(ssi->tag_started <= hs->file) { /* pretend to have sent the tag, too */ len += ssi->tag_end - ssi->tag_started; } #endif /* !LWIP_HTTPD_SSI_INCLUDE_TAG*/ hs->file += len; hs->left -= len; } } } else { ssi->tag_index++; } } else { /* We found an unexpected character so this is not a tag. Move * back to idle state. */ ssi->parse_left--; ssi->parsed++; ssi->tag_state = TAG_NONE; } break; /* * We have found a valid tag and are in the process of sending * data as a result of that discovery. We send either remaining data * from the file prior to the insert point or the insert string itself. */ case TAG_SENDING: /* Do we have any remaining file data to send from the buffer prior * to the tag? */ if(ssi->tag_end > hs->file) { /* How much of the data can we send? */ #if LWIP_HTTPD_SSI_INCLUDE_TAG len = (u16_t)LWIP_MIN(ssi->tag_end - hs->file, 0xffff); #else /* LWIP_HTTPD_SSI_INCLUDE_TAG*/ LWIP_ASSERT("hs->started >= hs->file", ssi->tag_started >= hs->file); /* we would include the tag in sending */ len = (u16_t)LWIP_MIN(ssi->tag_started - hs->file, 0xffff); #endif /* LWIP_HTTPD_SSI_INCLUDE_TAG*/ if (len != 0) { err = http_write(pcb, hs->file, &len, HTTP_IS_DATA_VOLATILE(hs)); } else { err = ERR_OK; } if (err == ERR_OK) { data_to_send = 1; #if !LWIP_HTTPD_SSI_INCLUDE_TAG if(ssi->tag_started <= hs->file) { /* pretend to have sent the tag, too */ len += ssi->tag_end - ssi->tag_started; } #endif /* !LWIP_HTTPD_SSI_INCLUDE_TAG*/ hs->file += len; hs->left -= len; } } else { #if LWIP_HTTPD_SSI_MULTIPART if(ssi->tag_index >= ssi->tag_insert_len) { /* Did the last SSIHandler have more to send? */ if (ssi->tag_part != HTTPD_LAST_TAG_PART) { /* If so, call it again */ ssi->tag_index = 0; get_tag_insert(hs); } } #endif /* LWIP_HTTPD_SSI_MULTIPART */ /* Do we still have insert data left to send? */ if(ssi->tag_index < ssi->tag_insert_len) { /* We are sending the insert string itself. How much of the * insert can we send? */ len = (ssi->tag_insert_len - ssi->tag_index); /* Note that we set the copy flag here since we only have a * single tag insert buffer per connection. If we don't do * this, insert corruption can occur if more than one insert * is processed before we call tcp_output. */ err = http_write(pcb, &(ssi->tag_insert[ssi->tag_index]), &len, HTTP_IS_TAG_VOLATILE(hs)); if (err == ERR_OK) { data_to_send = 1; ssi->tag_index += len; /* Don't return here: keep on sending data */ } } else { #if LWIP_HTTPD_SSI_MULTIPART if (ssi->tag_part == HTTPD_LAST_TAG_PART) #endif /* LWIP_HTTPD_SSI_MULTIPART */ { /* We have sent all the insert data so go back to looking for * a new tag. */ LWIP_DEBUGF(HTTPD_DEBUG, ("Everything sent.\n")); ssi->tag_index = 0; ssi->tag_state = TAG_NONE; #if !LWIP_HTTPD_SSI_INCLUDE_TAG ssi->parsed = ssi->tag_end; #endif /* !LWIP_HTTPD_SSI_INCLUDE_TAG*/ } } break; } } } /* If we drop out of the end of the for loop, this implies we must have * file data to send so send it now. In TAG_SENDING state, we've already * handled this so skip the send if that's the case. */ if((ssi->tag_state != TAG_SENDING) && (ssi->parsed > hs->file)) { len = (u16_t)LWIP_MIN(ssi->parsed - hs->file, 0xffff); err = http_write(pcb, hs->file, &len, HTTP_IS_DATA_VOLATILE(hs)); if (err == ERR_OK) { data_to_send = 1; hs->file += len; hs->left -= len; } } return data_to_send; } #endif /* LWIP_HTTPD_SSI */ /** * Try to send more data on this pcb. * * @param pcb the pcb to send data * @param hs connection state */ static u8_t http_send(struct tcp_pcb *pcb, struct http_state *hs) { u8_t data_to_send = HTTP_NO_DATA_TO_SEND; LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("http_send: pcb=%p hs=%p left=%d\n", (void*)pcb, (void*)hs, hs != NULL ? (int)hs->left : 0)); #if LWIP_HTTPD_SUPPORT_POST && LWIP_HTTPD_POST_MANUAL_WND if (hs->unrecved_bytes != 0) { return 0; } #endif /* LWIP_HTTPD_SUPPORT_POST && LWIP_HTTPD_POST_MANUAL_WND */ /* If we were passed a NULL state structure pointer, ignore the call. */ if (hs == NULL) { return 0; } #if LWIP_HTTPD_FS_ASYNC_READ /* Check if we are allowed to read from this file. (e.g. SSI might want to delay sending until data is available) */ if (!fs_is_file_ready(hs->handle, http_continue, hs)) { return 0; } #endif /* LWIP_HTTPD_FS_ASYNC_READ */ #if LWIP_HTTPD_DYNAMIC_HEADERS /* Do we have any more header data to send for this file? */ if(hs->hdr_index < NUM_FILE_HDR_STRINGS) { data_to_send = http_send_headers(pcb, hs); if (data_to_send != HTTP_DATA_TO_SEND_CONTINUE) { return data_to_send; } } #endif /* LWIP_HTTPD_DYNAMIC_HEADERS */ /* Have we run out of file data to send? If so, we need to read the next * block from the file. */ if (hs->left == 0) { if (!http_check_eof(pcb, hs)) { return 0; } } #if LWIP_HTTPD_SSI if(hs->ssi) { data_to_send = http_send_data_ssi(pcb, hs); } else #endif /* LWIP_HTTPD_SSI */ { data_to_send = http_send_data_nonssi(pcb, hs); } if((hs->left == 0) && (fs_bytes_left(hs->handle) <= 0)) { /* We reached the end of the file so this request is done. * This adds the FIN flag right into the last data segment. */ LWIP_DEBUGF(HTTPD_DEBUG, ("End of file.\n")); http_eof(pcb, hs); return 0; } LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("send_data end.\n")); return data_to_send; } #if LWIP_HTTPD_SUPPORT_EXTSTATUS /** Initialize a http connection with a file to send for an error message * * @param hs http connection state * @param error_nr HTTP error number * @return ERR_OK if file was found and hs has been initialized correctly * another err_t otherwise */ static err_t http_find_error_file(struct http_state *hs, u16_t error_nr) { const char *uri1, *uri2, *uri3; err_t err; if (error_nr == 501) { uri1 = "/501.html"; uri2 = "/501.htm"; uri3 = "/501.shtml"; } else { /* 400 (bad request is the default) */ uri1 = "/400.html"; uri2 = "/400.htm"; uri3 = "/400.shtml"; } err = fs_open(&hs->file_handle, uri1); if (err != ERR_OK) { err = fs_open(&hs->file_handle, uri2); if (err != ERR_OK) { err = fs_open(&hs->file_handle, uri3); if (err != ERR_OK) { LWIP_DEBUGF(HTTPD_DEBUG, ("Error page for error %"U16_F" not found\n", error_nr)); return ERR_ARG; } } } return http_init_file(hs, &hs->file_handle, 0, NULL, 0); } #else /* LWIP_HTTPD_SUPPORT_EXTSTATUS */ #define http_find_error_file(hs, error_nr) ERR_ARG #endif /* LWIP_HTTPD_SUPPORT_EXTSTATUS */ /** * Get the file struct for a 404 error page. * Tries some file names and returns NULL if none found. * * @param uri pointer that receives the actual file name URI * @return file struct for the error page or NULL no matching file was found */ static struct fs_file * http_get_404_file(struct http_state *hs, const char **uri) { err_t err; *uri = "/404.html"; err = fs_open(&hs->file_handle, *uri); if (err != ERR_OK) { /* 404.html doesn't exist. Try 404.htm instead. */ *uri = "/404.htm"; err = fs_open(&hs->file_handle, *uri); if (err != ERR_OK) { /* 404.htm doesn't exist either. Try 404.shtml instead. */ *uri = "/404.shtml"; err = fs_open(&hs->file_handle, *uri); if (err != ERR_OK) { /* 404.htm doesn't exist either. Indicate to the caller that it should * send back a default 404 page. */ *uri = NULL; return NULL; } } } return &hs->file_handle; } #if LWIP_HTTPD_SUPPORT_POST static err_t http_handle_post_finished(struct http_state *hs) { #if LWIP_HTTPD_POST_MANUAL_WND /* Prevent multiple calls to httpd_post_finished, since it might have already been called before from httpd_post_data_recved(). */ if (hs->post_finished) { return ERR_OK; } hs->post_finished = 1; #endif /* LWIP_HTTPD_POST_MANUAL_WND */ /* application error or POST finished */ /* NULL-terminate the buffer */ http_post_response_filename[0] = 0; httpd_post_finished(hs, http_post_response_filename, LWIP_HTTPD_POST_MAX_RESPONSE_URI_LEN); return http_find_file(hs, http_post_response_filename, 0); } /** Pass received POST body data to the application and correctly handle * returning a response document or closing the connection. * ATTENTION: The application is responsible for the pbuf now, so don't free it! * * @param hs http connection state * @param p pbuf to pass to the application * @return ERR_OK if passed successfully, another err_t if the response file * hasn't been found (after POST finished) */ static err_t http_post_rxpbuf(struct http_state *hs, struct pbuf *p) { err_t err; /* adjust remaining Content-Length */ if (hs->post_content_len_left < p->tot_len) { hs->post_content_len_left = 0; } else { hs->post_content_len_left -= p->tot_len; } err = httpd_post_receive_data(hs, p); if (err != ERR_OK) { /* Ignore remaining content in case of application error */ hs->post_content_len_left = 0; } if (hs->post_content_len_left == 0) { #if LWIP_HTTPD_SUPPORT_POST && LWIP_HTTPD_POST_MANUAL_WND if (hs->unrecved_bytes != 0) { return ERR_OK; } #endif /* LWIP_HTTPD_SUPPORT_POST && LWIP_HTTPD_POST_MANUAL_WND */ /* application error or POST finished */ return http_handle_post_finished(hs); } return ERR_OK; } /** Handle a post request. Called from http_parse_request when method 'POST' * is found. * * @param p The input pbuf (containing the POST header and body). * @param hs The http connection state. * @param data HTTP request (header and part of body) from input pbuf(s). * @param data_len Size of 'data'. * @param uri The HTTP URI parsed from input pbuf(s). * @param uri_end Pointer to the end of 'uri' (here, the rest of the HTTP * header starts). * @return ERR_OK: POST correctly parsed and accepted by the application. * ERR_INPROGRESS: POST not completely parsed (no error yet) * another err_t: Error parsing POST or denied by the application */ static err_t http_post_request(struct pbuf **inp, struct http_state *hs, char *data, u16_t data_len, char *uri, char *uri_end) { err_t err; /* search for end-of-header (first double-CRLF) */ char* crlfcrlf = strnstr(uri_end + 1, CRLF CRLF, data_len - (uri_end + 1 - data)); if (crlfcrlf != NULL) { /* search for "Content-Length: " */ #define HTTP_HDR_CONTENT_LEN "Content-Length: " #define HTTP_HDR_CONTENT_LEN_LEN 16 #define HTTP_HDR_CONTENT_LEN_DIGIT_MAX_LEN 10 char *scontent_len = strnstr(uri_end + 1, HTTP_HDR_CONTENT_LEN, crlfcrlf - (uri_end + 1)); if (scontent_len != NULL) { char *scontent_len_end = strnstr(scontent_len + HTTP_HDR_CONTENT_LEN_LEN, CRLF, HTTP_HDR_CONTENT_LEN_DIGIT_MAX_LEN); if (scontent_len_end != NULL) { int content_len; char *conten_len_num = scontent_len + HTTP_HDR_CONTENT_LEN_LEN; content_len = atoi(conten_len_num); if (content_len > 0) { /* adjust length of HTTP header passed to application */ const char *hdr_start_after_uri = uri_end + 1; u16_t hdr_len = LWIP_MIN(data_len, crlfcrlf + 4 - data); u16_t hdr_data_len = LWIP_MIN(data_len, crlfcrlf + 4 - hdr_start_after_uri); u8_t post_auto_wnd = 1; http_post_response_filename[0] = 0; err = httpd_post_begin(hs, uri, hdr_start_after_uri, hdr_data_len, content_len, http_post_response_filename, LWIP_HTTPD_POST_MAX_RESPONSE_URI_LEN, &post_auto_wnd); if (err == ERR_OK) { /* try to pass in data of the first pbuf(s) */ struct pbuf *q = *inp; u16_t start_offset = hdr_len; #if LWIP_HTTPD_POST_MANUAL_WND hs->no_auto_wnd = !post_auto_wnd; #endif /* LWIP_HTTPD_POST_MANUAL_WND */ /* set the Content-Length to be received for this POST */ hs->post_content_len_left = (u32_t)content_len; /* get to the pbuf where the body starts */ while((q != NULL) && (q->len <= start_offset)) { struct pbuf *head = q; start_offset -= q->len; q = q->next; /* free the head pbuf */ head->next = NULL; pbuf_free(head); } *inp = NULL; if (q != NULL) { /* hide the remaining HTTP header */ pbuf_header(q, -(s16_t)start_offset); #if LWIP_HTTPD_POST_MANUAL_WND if (!post_auto_wnd) { /* already tcp_recved() this data... */ hs->unrecved_bytes = q->tot_len; } #endif /* LWIP_HTTPD_POST_MANUAL_WND */ return http_post_rxpbuf(hs, q); } else { return ERR_OK; } } else { /* return file passed from application */ return http_find_file(hs, http_post_response_filename, 0); } } else { LWIP_DEBUGF(HTTPD_DEBUG, ("POST received invalid Content-Length: %s\n", conten_len_num)); return ERR_ARG; } } } /* If we come here, headers are fully received (double-crlf), but Content-Length was not included. Since this is currently the only supported method, we have to fail in this case! */ LWIP_DEBUGF(HTTPD_DEBUG, ("Error when parsing Content-Length\n")); return ERR_ARG; } /* if we come here, the POST is incomplete */ #if LWIP_HTTPD_SUPPORT_REQUESTLIST return ERR_INPROGRESS; #else /* LWIP_HTTPD_SUPPORT_REQUESTLIST */ return ERR_ARG; #endif /* LWIP_HTTPD_SUPPORT_REQUESTLIST */ } #if LWIP_HTTPD_POST_MANUAL_WND /** A POST implementation can call this function to update the TCP window. * This can be used to throttle data reception (e.g. when received data is * programmed to flash and data is received faster than programmed). * * @param connection A connection handle passed to httpd_post_begin for which * httpd_post_finished has *NOT* been called yet! * @param recved_len Length of data received (for window update) */ void httpd_post_data_recved(void *connection, u16_t recved_len) { struct http_state *hs = (struct http_state*)connection; if (hs != NULL) { if (hs->no_auto_wnd) { u16_t len = recved_len; if (hs->unrecved_bytes >= recved_len) { hs->unrecved_bytes -= recved_len; } else { LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_LEVEL_WARNING, ("httpd_post_data_recved: recved_len too big\n")); len = (u16_t)hs->unrecved_bytes; hs->unrecved_bytes = 0; } if (hs->pcb != NULL) { if (len != 0) { tcp_recved(hs->pcb, len); } if ((hs->post_content_len_left == 0) && (hs->unrecved_bytes == 0)) { /* finished handling POST */ http_handle_post_finished(hs); http_send(hs->pcb, hs); } } } } } #endif /* LWIP_HTTPD_POST_MANUAL_WND */ #endif /* LWIP_HTTPD_SUPPORT_POST */ #if LWIP_HTTPD_FS_ASYNC_READ /** Try to send more data if file has been blocked before * This is a callback function passed to fs_read_async(). */ static void http_continue(void *connection) { struct http_state *hs = (struct http_state*)connection; if (hs && (hs->pcb) && (hs->handle)) { LWIP_ASSERT("hs->pcb != NULL", hs->pcb != NULL); LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("httpd_continue: try to send more data\n")); if (http_send(hs->pcb, hs)) { /* If we wrote anything to be sent, go ahead and send it now. */ LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("tcp_output\n")); tcp_output(hs->pcb); } } } #endif /* LWIP_HTTPD_FS_ASYNC_READ */ /** * When data has been received in the correct state, try to parse it * as a HTTP request. * * @param p the received pbuf * @param hs the connection state * @param pcb the tcp_pcb which received this packet * @return ERR_OK if request was OK and hs has been initialized correctly * ERR_INPROGRESS if request was OK so far but not fully received * another err_t otherwise */ static err_t http_parse_request(struct pbuf **inp, struct http_state *hs, struct tcp_pcb *pcb) { char *data; char *crlf; u16_t data_len; struct pbuf *p = *inp; #if LWIP_HTTPD_SUPPORT_REQUESTLIST u16_t clen; #endif /* LWIP_HTTPD_SUPPORT_REQUESTLIST */ #if LWIP_HTTPD_SUPPORT_POST err_t err; #endif /* LWIP_HTTPD_SUPPORT_POST */ LWIP_UNUSED_ARG(pcb); /* only used for post */ LWIP_ASSERT("p != NULL", p != NULL); LWIP_ASSERT("hs != NULL", hs != NULL); if ((hs->handle != NULL) || (hs->file != NULL)) { LWIP_DEBUGF(HTTPD_DEBUG, ("Received data while sending a file\n")); /* already sending a file */ /* @todo: abort? */ return ERR_USE; } #if LWIP_HTTPD_SUPPORT_REQUESTLIST LWIP_DEBUGF(HTTPD_DEBUG, ("Received %"U16_F" bytes\n", p->tot_len)); /* first check allowed characters in this pbuf? */ /* enqueue the pbuf */ if (hs->req == NULL) { LWIP_DEBUGF(HTTPD_DEBUG, ("First pbuf\n")); hs->req = p; } else { LWIP_DEBUGF(HTTPD_DEBUG, ("pbuf enqueued\n")); pbuf_cat(hs->req, p); } if (hs->req->next != NULL) { data_len = LWIP_MIN(hs->req->tot_len, LWIP_HTTPD_MAX_REQ_LENGTH); pbuf_copy_partial(hs->req, httpd_req_buf, data_len, 0); data = httpd_req_buf; } else #endif /* LWIP_HTTPD_SUPPORT_REQUESTLIST */ { data = (char *)p->payload; data_len = p->len; if (p->len != p->tot_len) { LWIP_DEBUGF(HTTPD_DEBUG, ("Warning: incomplete header due to chained pbufs\n")); } } /* received enough data for minimal request? */ if (data_len >= MIN_REQ_LEN) { /* wait for CRLF before parsing anything */ crlf = strnstr(data, CRLF, data_len); if (crlf != NULL) { #if LWIP_HTTPD_SUPPORT_POST int is_post = 0; #endif /* LWIP_HTTPD_SUPPORT_POST */ int is_09 = 0; char *sp1, *sp2; u16_t left_len, uri_len; LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("CRLF received, parsing request\n")); /* parse method */ if (!strncmp(data, "GET ", 4)) { sp1 = data + 3; /* received GET request */ LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("Received GET request\"\n")); #if LWIP_HTTPD_SUPPORT_POST } else if (!strncmp(data, "POST ", 5)) { /* store request type */ is_post = 1; sp1 = data + 4; /* received GET request */ LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("Received POST request\n")); #endif /* LWIP_HTTPD_SUPPORT_POST */ } else { /* null-terminate the METHOD (pbuf is freed anyway wen returning) */ data[4] = 0; /* unsupported method! */ LWIP_DEBUGF(HTTPD_DEBUG, ("Unsupported request method (not implemented): \"%s\"\n", data)); return http_find_error_file(hs, 501); } /* if we come here, method is OK, parse URI */ left_len = data_len - ((sp1 +1) - data); sp2 = strnstr(sp1 + 1, " ", left_len); #if LWIP_HTTPD_SUPPORT_V09 if (sp2 == NULL) { /* HTTP 0.9: respond with correct protocol version */ sp2 = strnstr(sp1 + 1, CRLF, left_len); is_09 = 1; #if LWIP_HTTPD_SUPPORT_POST if (is_post) { /* HTTP/0.9 does not support POST */ goto badrequest; } #endif /* LWIP_HTTPD_SUPPORT_POST */ } #endif /* LWIP_HTTPD_SUPPORT_V09 */ uri_len = sp2 - (sp1 + 1); if ((sp2 != 0) && (sp2 > sp1)) { /* wait for CRLFCRLF (indicating end of HTTP headers) before parsing anything */ if (strnstr(data, CRLF CRLF, data_len) != NULL) { char *uri = sp1 + 1; #if LWIP_HTTPD_SUPPORT_11_KEEPALIVE if (!is_09 && strnstr(data, HTTP11_CONNECTIONKEEPALIVE, data_len)) { hs->keepalive = 1; } #endif /* LWIP_HTTPD_SUPPORT_11_KEEPALIVE */ /* null-terminate the METHOD (pbuf is freed anyway wen returning) */ *sp1 = 0; uri[uri_len] = 0; LWIP_DEBUGF(HTTPD_DEBUG, ("Received \"%s\" request for URI: \"%s\"\n", data, uri)); #if LWIP_HTTPD_SUPPORT_POST if (is_post) { #if LWIP_HTTPD_SUPPORT_REQUESTLIST struct pbuf **q = &hs->req; #else /* LWIP_HTTPD_SUPPORT_REQUESTLIST */ struct pbuf **q = inp; #endif /* LWIP_HTTPD_SUPPORT_REQUESTLIST */ err = http_post_request(q, hs, data, data_len, uri, sp2); if (err != ERR_OK) { /* restore header for next try */ *sp1 = ' '; *sp2 = ' '; uri[uri_len] = ' '; } if (err == ERR_ARG) { goto badrequest; } return err; } else #endif /* LWIP_HTTPD_SUPPORT_POST */ { return http_find_file(hs, uri, is_09); } } } else { LWIP_DEBUGF(HTTPD_DEBUG, ("invalid URI\n")); } } } #if LWIP_HTTPD_SUPPORT_REQUESTLIST clen = pbuf_clen(hs->req); if ((hs->req->tot_len <= LWIP_HTTPD_REQ_BUFSIZE) && (clen <= LWIP_HTTPD_REQ_QUEUELEN)) { /* request not fully received (too short or CRLF is missing) */ return ERR_INPROGRESS; } else #endif /* LWIP_HTTPD_SUPPORT_REQUESTLIST */ { #if LWIP_HTTPD_SUPPORT_POST badrequest: #endif /* LWIP_HTTPD_SUPPORT_POST */ LWIP_DEBUGF(HTTPD_DEBUG, ("bad request\n")); /* could not parse request */ return http_find_error_file(hs, 400); } } /** Try to find the file specified by uri and, if found, initialize hs * accordingly. * * @param hs the connection state * @param uri the HTTP header URI * @param is_09 1 if the request is HTTP/0.9 (no HTTP headers in response) * @return ERR_OK if file was found and hs has been initialized correctly * another err_t otherwise */ static err_t http_find_file(struct http_state *hs, const char *uri, int is_09) { size_t loop; struct fs_file *file = NULL; char *params; err_t err; #if LWIP_HTTPD_CGI int i; int count; #endif /* LWIP_HTTPD_CGI */ #if !LWIP_HTTPD_SSI const #endif /* !LWIP_HTTPD_SSI */ /* By default, assume we will not be processing server-side-includes tags */ u8_t tag_check = 0; /* Have we been asked for the default root file? */ if((uri[0] == '/') && (uri[1] == 0)) { /* Try each of the configured default filenames until we find one that exists. */ for (loop = 0; loop < NUM_DEFAULT_FILENAMES; loop++) { LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("Looking for %s...\n", g_psDefaultFilenames[loop].name)); err = fs_open(&hs->file_handle, (char *)g_psDefaultFilenames[loop].name); uri = (char *)g_psDefaultFilenames[loop].name; if(err == ERR_OK) { file = &hs->file_handle; LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("Opened.\n")); #if LWIP_HTTPD_SSI tag_check = g_psDefaultFilenames[loop].shtml; #endif /* LWIP_HTTPD_SSI */ break; } } if (file == NULL) { /* None of the default filenames exist so send back a 404 page */ file = http_get_404_file(hs, &uri); #if LWIP_HTTPD_SSI tag_check = 0; #endif /* LWIP_HTTPD_SSI */ } } else { /* No - we've been asked for a specific file. */ /* First, isolate the base URI (without any parameters) */ params = (char *)strchr(uri, '?'); if (params != NULL) { /* URI contains parameters. NULL-terminate the base URI */ *params = '\0'; params++; } #if LWIP_HTTPD_CGI /* Does the base URI we have isolated correspond to a CGI handler? */ if (g_iNumCGIs && g_pCGIs) { for (i = 0; i < g_iNumCGIs; i++) { if (strcmp(uri, g_pCGIs[i].pcCGIName) == 0) { /* * We found a CGI that handles this URI so extract the * parameters and call the handler. */ count = extract_uri_parameters(hs, params); uri = g_pCGIs[i].pfnCGIHandler(i, count, hs->params, hs->param_vals); break; } } } #endif /* LWIP_HTTPD_CGI */ LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("Opening %s\n", uri)); err = fs_open(&hs->file_handle, uri); if (err == ERR_OK) { file = &hs->file_handle; } else { file = http_get_404_file(hs, &uri); } #if LWIP_HTTPD_SSI if (file != NULL) { /* See if we have been asked for an shtml file and, if so, enable tag checking. */ tag_check = 0; for (loop = 0; loop < NUM_SHTML_EXTENSIONS; loop++) { if (strstr(uri, g_pcSSIExtensions[loop])) { tag_check = 1; break; } } } #endif /* LWIP_HTTPD_SSI */ } return http_init_file(hs, file, is_09, uri, tag_check); } /** Initialize a http connection with a file to send (if found). * Called by http_find_file and http_find_error_file. * * @param hs http connection state * @param file file structure to send (or NULL if not found) * @param is_09 1 if the request is HTTP/0.9 (no HTTP headers in response) * @param uri the HTTP header URI * @param tag_check enable SSI tag checking * @return ERR_OK if file was found and hs has been initialized correctly * another err_t otherwise */ static err_t http_init_file(struct http_state *hs, struct fs_file *file, int is_09, const char *uri, u8_t tag_check) { if (file != NULL) { /* file opened, initialise struct http_state */ #if LWIP_HTTPD_SSI if (tag_check) { struct http_ssi_state *ssi = http_ssi_state_alloc(); if (ssi != NULL) { ssi->tag_index = 0; ssi->tag_state = TAG_NONE; ssi->parsed = file->data; ssi->parse_left = file->len; ssi->tag_end = file->data; hs->ssi = ssi; } } #else /* LWIP_HTTPD_SSI */ LWIP_UNUSED_ARG(tag_check); #endif /* LWIP_HTTPD_SSI */ hs->handle = file; hs->file = (char*)file->data; LWIP_ASSERT("File length must be positive!", (file->len >= 0)); hs->left = file->len; hs->retries = 0; #if LWIP_HTTPD_TIMING hs->time_started = sys_now(); #endif /* LWIP_HTTPD_TIMING */ #if !LWIP_HTTPD_DYNAMIC_HEADERS LWIP_ASSERT("HTTP headers not included in file system", hs->handle->http_header_included); #endif /* !LWIP_HTTPD_DYNAMIC_HEADERS */ #if LWIP_HTTPD_SUPPORT_V09 if (hs->handle->http_header_included && is_09) { /* HTTP/0.9 responses are sent without HTTP header, search for the end of the header. */ char *file_start = strnstr(hs->file, CRLF CRLF, hs->left); if (file_start != NULL) { size_t diff = file_start + 4 - hs->file; hs->file += diff; hs->left -= (u32_t)diff; } } #endif /* LWIP_HTTPD_SUPPORT_V09*/ } else { hs->handle = NULL; hs->file = NULL; hs->left = 0; hs->retries = 0; } #if LWIP_HTTPD_DYNAMIC_HEADERS /* Determine the HTTP headers to send based on the file extension of * the requested URI. */ if ((hs->handle == NULL) || !hs->handle->http_header_included) { get_http_headers(hs, (char*)uri); } #else /* LWIP_HTTPD_DYNAMIC_HEADERS */ LWIP_UNUSED_ARG(uri); #endif /* LWIP_HTTPD_DYNAMIC_HEADERS */ return ERR_OK; } /** * The pcb had an error and is already deallocated. * The argument might still be valid (if != NULL). */ static void http_err(void *arg, err_t err) { struct http_state *hs = (struct http_state *)arg; LWIP_UNUSED_ARG(err); LWIP_DEBUGF(HTTPD_DEBUG, ("http_err: %s", lwip_strerr(err))); if (hs != NULL) { http_state_free(hs); } } /** * Data has been sent and acknowledged by the remote host. * This means that more data can be sent. */ static err_t http_sent(void *arg, struct tcp_pcb *pcb, u16_t len) { struct http_state *hs = (struct http_state *)arg; LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("http_sent %p\n", (void*)pcb)); LWIP_UNUSED_ARG(len); if (hs == NULL) { return ERR_OK; } hs->retries = 0; http_send(pcb, hs); return ERR_OK; } /** * The poll function is called every 2nd second. * If there has been no data sent (which resets the retries) in 8 seconds, close. * If the last portion of a file has not been sent in 2 seconds, close. * * This could be increased, but we don't want to waste resources for bad connections. */ static err_t http_poll(void *arg, struct tcp_pcb *pcb) { struct http_state *hs = (struct http_state *)arg; LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("http_poll: pcb=%p hs=%p pcb_state=%s\n", (void*)pcb, (void*)hs, tcp_debug_state_str(pcb->state))); if (hs == NULL) { err_t closed; /* arg is null, close. */ LWIP_DEBUGF(HTTPD_DEBUG, ("http_poll: arg is NULL, close\n")); closed = http_close_conn(pcb, NULL); LWIP_UNUSED_ARG(closed); #if LWIP_HTTPD_ABORT_ON_CLOSE_MEM_ERROR if (closed == ERR_MEM) { tcp_abort(pcb); return ERR_ABRT; } #endif /* LWIP_HTTPD_ABORT_ON_CLOSE_MEM_ERROR */ return ERR_OK; } else { hs->retries++; if (hs->retries == HTTPD_MAX_RETRIES) { LWIP_DEBUGF(HTTPD_DEBUG, ("http_poll: too many retries, close\n")); http_close_conn(pcb, hs); return ERR_OK; } /* If this connection has a file open, try to send some more data. If * it has not yet received a GET request, don't do this since it will * cause the connection to close immediately. */ if(hs && (hs->handle)) { LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("http_poll: try to send more data\n")); if(http_send(pcb, hs)) { /* If we wrote anything to be sent, go ahead and send it now. */ LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("tcp_output\n")); tcp_output(pcb); } } } return ERR_OK; } /** * Data has been received on this pcb. * For HTTP 1.0, this should normally only happen once (if the request fits in one packet). */ static err_t http_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err) { err_t parsed = ERR_ABRT; struct http_state *hs = (struct http_state *)arg; LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("http_recv: pcb=%p pbuf=%p err=%s\n", (void*)pcb, (void*)p, lwip_strerr(err))); if ((err != ERR_OK) || (p == NULL) || (hs == NULL)) { /* error or closed by other side? */ if (p != NULL) { /* Inform TCP that we have taken the data. */ tcp_recved(pcb, p->tot_len); pbuf_free(p); } if (hs == NULL) { /* this should not happen, only to be robust */ LWIP_DEBUGF(HTTPD_DEBUG, ("Error, http_recv: hs is NULL, close\n")); } http_close_conn(pcb, hs); return ERR_OK; } #if LWIP_HTTPD_SUPPORT_POST && LWIP_HTTPD_POST_MANUAL_WND if (hs->no_auto_wnd) { hs->unrecved_bytes += p->tot_len; } else #endif /* LWIP_HTTPD_SUPPORT_POST && LWIP_HTTPD_POST_MANUAL_WND */ { /* Inform TCP that we have taken the data. */ tcp_recved(pcb, p->tot_len); } #if LWIP_HTTPD_SUPPORT_POST if (hs->post_content_len_left > 0) { /* reset idle counter when POST data is received */ hs->retries = 0; /* this is data for a POST, pass the complete pbuf to the application */ http_post_rxpbuf(hs, p); /* pbuf is passed to the application, don't free it! */ if (hs->post_content_len_left == 0) { /* all data received, send response or close connection */ http_send(pcb, hs); } return ERR_OK; } else #endif /* LWIP_HTTPD_SUPPORT_POST */ { if (hs->handle == NULL) { parsed = http_parse_request(&p, hs, pcb); LWIP_ASSERT("http_parse_request: unexpected return value", parsed == ERR_OK || parsed == ERR_INPROGRESS ||parsed == ERR_ARG || parsed == ERR_USE); } else { LWIP_DEBUGF(HTTPD_DEBUG, ("http_recv: already sending data\n")); } #if LWIP_HTTPD_SUPPORT_REQUESTLIST if (parsed != ERR_INPROGRESS) { /* request fully parsed or error */ if (hs->req != NULL) { pbuf_free(hs->req); hs->req = NULL; } } #else /* LWIP_HTTPD_SUPPORT_REQUESTLIST */ if (p != NULL) { /* pbuf not passed to application, free it now */ pbuf_free(p); } #endif /* LWIP_HTTPD_SUPPORT_REQUESTLIST */ if (parsed == ERR_OK) { #if LWIP_HTTPD_SUPPORT_POST if (hs->post_content_len_left == 0) #endif /* LWIP_HTTPD_SUPPORT_POST */ { LWIP_DEBUGF(HTTPD_DEBUG | LWIP_DBG_TRACE, ("http_recv: data %p len %"S32_F"\n", hs->file, hs->left)); http_send(pcb, hs); } } else if (parsed == ERR_ARG) { /* @todo: close on ERR_USE? */ http_close_conn(pcb, hs); } } return ERR_OK; } /** * A new incoming connection has been accepted. */ static err_t http_accept(void *arg, struct tcp_pcb *pcb, err_t err) { struct http_state *hs; struct tcp_pcb_listen *lpcb = (struct tcp_pcb_listen*)arg; LWIP_UNUSED_ARG(err); LWIP_DEBUGF(HTTPD_DEBUG, ("http_accept %p / %p\n", (void*)pcb, arg)); /* Decrease the listen backlog counter */ tcp_accepted(lpcb); /* Set priority */ tcp_setprio(pcb, HTTPD_TCP_PRIO); /* Allocate memory for the structure that holds the state of the connection - initialized by that function. */ hs = http_state_alloc(); if (hs == NULL) { LWIP_DEBUGF(HTTPD_DEBUG, ("http_accept: Out of memory, RST\n")); return ERR_MEM; } hs->pcb = pcb; /* Tell TCP that this is the structure we wish to be passed for our callbacks. */ tcp_arg(pcb, hs); /* Set up the various callback functions */ tcp_recv(pcb, http_recv); tcp_err(pcb, http_err); tcp_poll(pcb, http_poll, HTTPD_POLL_INTERVAL); tcp_sent(pcb, http_sent); return ERR_OK; } /** * Initialize the httpd with the specified local address. */ static void httpd_init_addr(ip_addr_t *local_addr) { struct tcp_pcb *pcb; err_t err; pcb = tcp_new(); LWIP_ASSERT("httpd_init: tcp_new failed", pcb != NULL); tcp_setprio(pcb, HTTPD_TCP_PRIO); /* set SOF_REUSEADDR here to explicitly bind httpd to multiple interfaces */ err = tcp_bind(pcb, local_addr, HTTPD_SERVER_PORT); LWIP_ASSERT("httpd_init: tcp_bind failed", err == ERR_OK); pcb = tcp_listen(pcb); LWIP_ASSERT("httpd_init: tcp_listen failed", pcb != NULL); /* initialize callback arg and accept callback */ tcp_arg(pcb, pcb); tcp_accept(pcb, http_accept); } /** * Initialize the httpd: set up a listening PCB and bind it to the defined port */ void httpd_init(void) { #if HTTPD_USE_MEM_POOL LWIP_ASSERT("memp_sizes[MEMP_HTTPD_STATE] >= sizeof(http_state)", memp_sizes[MEMP_HTTPD_STATE] >= sizeof(http_state)); LWIP_ASSERT("memp_sizes[MEMP_HTTPD_SSI_STATE] >= sizeof(http_ssi_state)", memp_sizes[MEMP_HTTPD_SSI_STATE] >= sizeof(http_ssi_state)); #endif LWIP_DEBUGF(HTTPD_DEBUG, ("httpd_init\n")); httpd_init_addr(IP_ADDR_ANY); } #if LWIP_HTTPD_SSI /** * Set the SSI handler function. * * @param ssi_handler the SSI handler function * @param tags an array of SSI tag strings to search for in SSI-enabled files * @param num_tags number of tags in the 'tags' array */ void http_set_ssi_handler(tSSIHandler ssi_handler, const char **tags, int num_tags) { LWIP_DEBUGF(HTTPD_DEBUG, ("http_set_ssi_handler\n")); LWIP_ASSERT("no ssi_handler given", ssi_handler != NULL); LWIP_ASSERT("no tags given", tags != NULL); LWIP_ASSERT("invalid number of tags", num_tags > 0); g_pfnSSIHandler = ssi_handler; g_ppcTags = tags; g_iNumTags = num_tags; } #endif /* LWIP_HTTPD_SSI */ #if LWIP_HTTPD_CGI /** * Set an array of CGI filenames/handler functions * * @param cgis an array of CGI filenames/handler functions * @param num_handlers number of elements in the 'cgis' array */ void http_set_cgi_handlers(const tCGI *cgis, int num_handlers) { LWIP_ASSERT("no cgis given", cgis != NULL); LWIP_ASSERT("invalid number of handlers", num_handlers > 0); g_pCGIs = cgis; g_iNumCGIs = num_handlers; } #endif /* LWIP_HTTPD_CGI */ #endif /* LWIP_TCP */ ocproxy-1.60/contrib/apps/httpserver_raw/httpd.h000066400000000000000000000233301303453231400221200ustar00rootroot00000000000000/* * Copyright (c) 2001-2003 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * * This version of the file has been modified by Texas Instruments to offer * simple server-side-include (SSI) and Common Gateway Interface (CGI) * capability. */ #ifndef LWIP_HTTPD_H #define LWIP_HTTPD_H #include "lwip/opt.h" #include "lwip/err.h" #include "lwip/pbuf.h" /** Set this to 1 to support CGI */ #ifndef LWIP_HTTPD_CGI #define LWIP_HTTPD_CGI 0 #endif /** Set this to 1 to support SSI (Server-Side-Includes) */ #ifndef LWIP_HTTPD_SSI #define LWIP_HTTPD_SSI 0 #endif /** Set this to 1 to support HTTP POST */ #ifndef LWIP_HTTPD_SUPPORT_POST #define LWIP_HTTPD_SUPPORT_POST 0 #endif #if LWIP_HTTPD_CGI /* * Function pointer for a CGI script handler. * * This function is called each time the HTTPD server is asked for a file * whose name was previously registered as a CGI function using a call to * http_set_cgi_handler. The iIndex parameter provides the index of the * CGI within the ppcURLs array passed to http_set_cgi_handler. Parameters * pcParam and pcValue provide access to the parameters provided along with * the URI. iNumParams provides a count of the entries in the pcParam and * pcValue arrays. Each entry in the pcParam array contains the name of a * parameter with the corresponding entry in the pcValue array containing the * value for that parameter. Note that pcParam may contain multiple elements * with the same name if, for example, a multi-selection list control is used * in the form generating the data. * * The function should return a pointer to a character string which is the * path and filename of the response that is to be sent to the connected * browser, for example "/thanks.htm" or "/response/error.ssi". * * The maximum number of parameters that will be passed to this function via * iNumParams is defined by LWIP_HTTPD_MAX_CGI_PARAMETERS. Any parameters in the incoming * HTTP request above this number will be discarded. * * Requests intended for use by this CGI mechanism must be sent using the GET * method (which encodes all parameters within the URI rather than in a block * later in the request). Attempts to use the POST method will result in the * request being ignored. * */ typedef const char *(*tCGIHandler)(int iIndex, int iNumParams, char *pcParam[], char *pcValue[]); /* * Structure defining the base filename (URL) of a CGI and the associated * function which is to be called when that URL is requested. */ typedef struct { const char *pcCGIName; tCGIHandler pfnCGIHandler; } tCGI; void http_set_cgi_handlers(const tCGI *pCGIs, int iNumHandlers); /* The maximum number of parameters that the CGI handler can be sent. */ #ifndef LWIP_HTTPD_MAX_CGI_PARAMETERS #define LWIP_HTTPD_MAX_CGI_PARAMETERS 16 #endif #endif /* LWIP_HTTPD_CGI */ #if LWIP_HTTPD_SSI /** LWIP_HTTPD_SSI_MULTIPART==1: SSI handler function is called with 2 more * arguments indicating a counter for insert string that are too long to be * inserted at once: the SSI handler function must then set 'next_tag_part' * which will be passed back to it in the next call. */ #ifndef LWIP_HTTPD_SSI_MULTIPART #define LWIP_HTTPD_SSI_MULTIPART 0 #endif /* * Function pointer for the SSI tag handler callback. * * This function will be called each time the HTTPD server detects a tag of the * form in a .shtml, .ssi or .shtm file where "name" appears as * one of the tags supplied to http_set_ssi_handler in the ppcTags array. The * returned insert string, which will be appended after the the string * "" in file sent back to the client,should be written to pointer * pcInsert. iInsertLen contains the size of the buffer pointed to by * pcInsert. The iIndex parameter provides the zero-based index of the tag as * found in the ppcTags array and identifies the tag that is to be processed. * * The handler returns the number of characters written to pcInsert excluding * any terminating NULL or a negative number to indicate a failure (tag not * recognized, for example). * * Note that the behavior of this SSI mechanism is somewhat different from the * "normal" SSI processing as found in, for example, the Apache web server. In * this case, the inserted text is appended following the SSI tag rather than * replacing the tag entirely. This allows for an implementation that does not * require significant additional buffering of output data yet which will still * offer usable SSI functionality. One downside to this approach is when * attempting to use SSI within JavaScript. The SSI tag is structured to * resemble an HTML comment but this syntax does not constitute a comment * within JavaScript and, hence, leaving the tag in place will result in * problems in these cases. To work around this, any SSI tag which needs to * output JavaScript code must do so in an encapsulated way, sending the whole * HTML section as a single include. */ typedef u16_t (*tSSIHandler)(int iIndex, char *pcInsert, int iInsertLen #if LWIP_HTTPD_SSI_MULTIPART , u16_t current_tag_part, u16_t *next_tag_part #endif /* LWIP_HTTPD_SSI_MULTIPART */ #if LWIP_HTTPD_FILE_STATE , void *connection_state #endif /* LWIP_HTTPD_FILE_STATE */ ); void http_set_ssi_handler(tSSIHandler pfnSSIHandler, const char **ppcTags, int iNumTags); /* The maximum length of the string comprising the tag name */ #ifndef LWIP_HTTPD_MAX_TAG_NAME_LEN #define LWIP_HTTPD_MAX_TAG_NAME_LEN 8 #endif /* The maximum length of string that can be returned to replace any given tag */ #ifndef LWIP_HTTPD_MAX_TAG_INSERT_LEN #define LWIP_HTTPD_MAX_TAG_INSERT_LEN 192 #endif #endif /* LWIP_HTTPD_SSI */ #if LWIP_HTTPD_SUPPORT_POST /* These functions must be implemented by the application */ /** Called when a POST request has been received. The application can decide * whether to accept it or not. * * @param connection Unique connection identifier, valid until httpd_post_end * is called. * @param uri The HTTP header URI receiving the POST request. * @param http_request The raw HTTP request (the first packet, normally). * @param http_request_len Size of 'http_request'. * @param content_len Content-Length from HTTP header. * @param response_uri Filename of response file, to be filled when denying the * request * @param response_uri_len Size of the 'response_uri' buffer. * @param post_auto_wnd Set this to 0 to let the callback code handle window * updates by calling 'httpd_post_data_recved' (to throttle rx speed) * default is 1 (httpd handles window updates automatically) * @return ERR_OK: Accept the POST request, data may be passed in * another err_t: Deny the POST request, send back 'bad request'. */ err_t httpd_post_begin(void *connection, const char *uri, const char *http_request, u16_t http_request_len, int content_len, char *response_uri, u16_t response_uri_len, u8_t *post_auto_wnd); /** Called for each pbuf of data that has been received for a POST. * ATTENTION: The application is responsible for freeing the pbufs passed in! * * @param connection Unique connection identifier. * @param p Received data. * @return ERR_OK: Data accepted. * another err_t: Data denied, http_post_get_response_uri will be called. */ err_t httpd_post_receive_data(void *connection, struct pbuf *p); /** Called when all data is received or when the connection is closed. * The application must return the filename/URI of a file to send in response * to this POST request. If the response_uri buffer is untouched, a 404 * response is returned. * * @param connection Unique connection identifier. * @param response_uri Filename of response file, to be filled when denying the request * @param response_uri_len Size of the 'response_uri' buffer. */ void httpd_post_finished(void *connection, char *response_uri, u16_t response_uri_len); #ifndef LWIP_HTTPD_POST_MANUAL_WND #define LWIP_HTTPD_POST_MANUAL_WND 0 #endif #if LWIP_HTTPD_POST_MANUAL_WND void httpd_post_data_recved(void *connection, u16_t recved_len); #endif /* LWIP_HTTPD_POST_MANUAL_WND */ #endif /* LWIP_HTTPD_SUPPORT_POST */ void httpd_init(void); #endif /* LWIP_HTTPD_H */ ocproxy-1.60/contrib/apps/httpserver_raw/httpd_structs.h000066400000000000000000000110071303453231400237050ustar00rootroot00000000000000#ifndef LWIP_HTTPD_STRUCTS_H #define LWIP_HTTPD_STRUCTS_H #include "httpd.h" /** This string is passed in the HTTP header as "Server: " */ #ifndef HTTPD_SERVER_AGENT #define HTTPD_SERVER_AGENT "lwIP/1.3.1 (http://savannah.nongnu.org/projects/lwip)" #endif /** Set this to 1 if you want to include code that creates HTTP headers * at runtime. Default is off: HTTP headers are then created statically * by the makefsdata tool. Static headers mean smaller code size, but * the (readonly) fsdata will grow a bit as every file includes the HTTP * header. */ #ifndef LWIP_HTTPD_DYNAMIC_HEADERS #define LWIP_HTTPD_DYNAMIC_HEADERS 0 #endif #if LWIP_HTTPD_DYNAMIC_HEADERS /** This struct is used for a list of HTTP header strings for various * filename extensions. */ typedef struct { const char *extension; int headerIndex; } tHTTPHeader; /** A list of strings used in HTTP headers */ static const char * const g_psHTTPHeaderStrings[] = { "Content-type: text/html\r\n\r\n", "Content-type: text/html\r\nExpires: Fri, 10 Apr 2008 14:00:00 GMT\r\nPragma: no-cache\r\n\r\n", "Content-type: image/gif\r\n\r\n", "Content-type: image/png\r\n\r\n", "Content-type: image/jpeg\r\n\r\n", "Content-type: image/bmp\r\n\r\n", "Content-type: image/x-icon\r\n\r\n", "Content-type: application/octet-stream\r\n\r\n", "Content-type: application/x-javascript\r\n\r\n", "Content-type: application/x-javascript\r\n\r\n", "Content-type: text/css\r\n\r\n", "Content-type: application/x-shockwave-flash\r\n\r\n", "Content-type: text/xml\r\n\r\n", "Content-type: text/plain\r\n\r\n", "HTTP/1.0 200 OK\r\n", "HTTP/1.0 404 File not found\r\n", "HTTP/1.0 400 Bad Request\r\n", "HTTP/1.0 501 Not Implemented\r\n", "HTTP/1.1 200 OK\r\n", "HTTP/1.1 404 File not found\r\n", "HTTP/1.1 400 Bad Request\r\n", "HTTP/1.1 501 Not Implemented\r\n", "Content-Length: ", "Connection: Close\r\n", "Connection: keep-alive\r\n", "Server: "HTTPD_SERVER_AGENT"\r\n", "\r\n

404: The requested file cannot be found.

\r\n" }; /* Indexes into the g_psHTTPHeaderStrings array */ #define HTTP_HDR_HTML 0 /* text/html */ #define HTTP_HDR_SSI 1 /* text/html Expires... */ #define HTTP_HDR_GIF 2 /* image/gif */ #define HTTP_HDR_PNG 3 /* image/png */ #define HTTP_HDR_JPG 4 /* image/jpeg */ #define HTTP_HDR_BMP 5 /* image/bmp */ #define HTTP_HDR_ICO 6 /* image/x-icon */ #define HTTP_HDR_APP 7 /* application/octet-stream */ #define HTTP_HDR_JS 8 /* application/x-javascript */ #define HTTP_HDR_RA 9 /* application/x-javascript */ #define HTTP_HDR_CSS 10 /* text/css */ #define HTTP_HDR_SWF 11 /* application/x-shockwave-flash */ #define HTTP_HDR_XML 12 /* text/xml */ #define HTTP_HDR_DEFAULT_TYPE 13 /* text/plain */ #define HTTP_HDR_OK 14 /* 200 OK */ #define HTTP_HDR_NOT_FOUND 15 /* 404 File not found */ #define HTTP_HDR_BAD_REQUEST 16 /* 400 Bad request */ #define HTTP_HDR_NOT_IMPL 17 /* 501 Not Implemented */ #define HTTP_HDR_OK_11 18 /* 200 OK */ #define HTTP_HDR_NOT_FOUND_11 19 /* 404 File not found */ #define HTTP_HDR_BAD_REQUEST_11 20 /* 400 Bad request */ #define HTTP_HDR_NOT_IMPL_11 21 /* 501 Not Implemented */ #define HTTP_HDR_CONTENT_LENGTH 22 /* Content-Length: (HTTP 1.1)*/ #define HTTP_HDR_CONN_CLOSE 23 /* Connection: Close (HTTP 1.1) */ #define HTTP_HDR_CONN_KEEPALIVE 24 /* Connection: keep-alive (HTTP 1.1) */ #define HTTP_HDR_SERVER 25 /* Server: HTTPD_SERVER_AGENT */ #define DEFAULT_404_HTML 26 /* default 404 body */ /** A list of extension-to-HTTP header strings */ const static tHTTPHeader g_psHTTPHeaders[] = { { "html", HTTP_HDR_HTML}, { "htm", HTTP_HDR_HTML}, { "shtml",HTTP_HDR_SSI}, { "shtm", HTTP_HDR_SSI}, { "ssi", HTTP_HDR_SSI}, { "gif", HTTP_HDR_GIF}, { "png", HTTP_HDR_PNG}, { "jpg", HTTP_HDR_JPG}, { "bmp", HTTP_HDR_BMP}, { "ico", HTTP_HDR_ICO}, { "class",HTTP_HDR_APP}, { "cls", HTTP_HDR_APP}, { "js", HTTP_HDR_JS}, { "ram", HTTP_HDR_RA}, { "css", HTTP_HDR_CSS}, { "swf", HTTP_HDR_SWF}, { "xml", HTTP_HDR_XML}, { "xsl", HTTP_HDR_XML} }; #define NUM_HTTP_HEADERS (sizeof(g_psHTTPHeaders) / sizeof(tHTTPHeader)) #endif /* LWIP_HTTPD_DYNAMIC_HEADERS */ #if LWIP_HTTPD_SSI static const char * const g_pcSSIExtensions[] = { ".shtml", ".shtm", ".ssi", ".xml" }; #define NUM_SHTML_EXTENSIONS (sizeof(g_pcSSIExtensions) / sizeof(const char *)) #endif /* LWIP_HTTPD_SSI */ #endif /* LWIP_HTTPD_STRUCTS_H */ ocproxy-1.60/contrib/apps/httpserver_raw/makefsdata/000077500000000000000000000000001303453231400227235ustar00rootroot00000000000000ocproxy-1.60/contrib/apps/httpserver_raw/makefsdata/makefsdata000066400000000000000000000050351303453231400247510ustar00rootroot00000000000000#!/usr/bin/perl open(OUTPUT, "> fsdata.c"); chdir("fs"); open(FILES, "find . -type f |"); while($file = ) { # Do not include files in CVS directories nor backup files. if($file =~ /(CVS|~)/) { next; } chop($file); open(HEADER, "> /tmp/header") || die $!; if($file =~ /404/) { print(HEADER "HTTP/1.0 404 File not found\r\n"); } else { print(HEADER "HTTP/1.0 200 OK\r\n"); } print(HEADER "Server: lwIP/pre-0.6 (http://www.sics.se/~adam/lwip/)\r\n"); if($file =~ /\.html$/) { print(HEADER "Content-type: text/html\r\n"); } elsif($file =~ /\.gif$/) { print(HEADER "Content-type: image/gif\r\n"); } elsif($file =~ /\.png$/) { print(HEADER "Content-type: image/png\r\n"); } elsif($file =~ /\.jpg$/) { print(HEADER "Content-type: image/jpeg\r\n"); } elsif($file =~ /\.class$/) { print(HEADER "Content-type: application/octet-stream\r\n"); } elsif($file =~ /\.ram$/) { print(HEADER "Content-type: audio/x-pn-realaudio\r\n"); } else { print(HEADER "Content-type: text/plain\r\n"); } print(HEADER "\r\n"); close(HEADER); unless($file =~ /\.plain$/ || $file =~ /cgi/) { system("cat /tmp/header $file > /tmp/file"); } else { system("cp $file /tmp/file"); } open(FILE, "/tmp/file"); unlink("/tmp/file"); unlink("/tmp/header"); $file =~ s/\.//; $fvar = $file; $fvar =~ s-/-_-g; $fvar =~ s-\.-_-g; print(OUTPUT "static const unsigned char data".$fvar."[] = {\n"); print(OUTPUT "\t/* $file */\n\t"); for($j = 0; $j < length($file); $j++) { printf(OUTPUT "%#02x, ", unpack("C", substr($file, $j, 1))); } printf(OUTPUT "0,\n"); $i = 0; while(read(FILE, $data, 1)) { if($i == 0) { print(OUTPUT "\t"); } printf(OUTPUT "%#02x, ", unpack("C", $data)); $i++; if($i == 10) { print(OUTPUT "\n"); $i = 0; } } print(OUTPUT "};\n\n"); close(FILE); push(@fvars, $fvar); push(@files, $file); } for($i = 0; $i < @fvars; $i++) { $file = $files[$i]; $fvar = $fvars[$i]; if($i == 0) { $prevfile = "NULL"; } else { $prevfile = "file" . $fvars[$i - 1]; } print(OUTPUT "const struct fsdata_file file".$fvar."[] = {{$prevfile, data$fvar, "); print(OUTPUT "data$fvar + ". (length($file) + 1) .", "); print(OUTPUT "sizeof(data$fvar) - ". (length($file) + 1) ."}};\n\n"); } print(OUTPUT "#define FS_ROOT file$fvars[$i - 1]\n\n"); print(OUTPUT "#define FS_NUMFILES $i\n"); ocproxy-1.60/contrib/apps/httpserver_raw/makefsdata/makefsdata.c000066400000000000000000000557411303453231400252030ustar00rootroot00000000000000/** * makefsdata: Converts a directory structure for use with the lwIP httpd. * * This file is part of the lwIP TCP/IP stack. * * Author: Jim Pettinato * Simon Goldschmidt * * @todo: * - take TCP_MSS, LWIP_TCP_TIMESTAMPS and * PAYLOAD_ALIGN_TYPE/PAYLOAD_ALIGNMENT as arguments */ #include #include #ifdef WIN32 #define WIN32_LEAN_AND_MEAN #include "windows.h" #else #include #endif #include #include /* Compatibility defines Win32 vs. DOS */ #ifdef WIN32 #define FIND_T WIN32_FIND_DATAA #define FIND_T_FILENAME(fInfo) (fInfo.cFileName) #define FIND_T_IS_DIR(fInfo) ((fInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0) #define FIND_T_IS_FILE(fInfo) ((fInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) #define FIND_RET_T HANDLE #define FINDFIRST_FILE(path, result) FindFirstFileA(path, result) #define FINDFIRST_DIR(path, result) FindFirstFileA(path, result) #define FINDNEXT(ff_res, result) FindNextFileA(ff_res, result) #define FINDFIRST_SUCCEEDED(ret) (ret != INVALID_HANDLE_VALUE) #define FINDNEXT_SUCCEEDED(ret) (ret == TRUE) #define GETCWD(path, len) GetCurrentDirectoryA(len, path) #define CHDIR(path) SetCurrentDirectoryA(path) #define CHDIR_SUCCEEDED(ret) (ret == TRUE) #else #define FIND_T struct ffblk #define FIND_T_FILENAME(fInfo) (fInfo.ff_name) #define FIND_T_IS_DIR(fInfo) ((fInfo.ff_attrib & FA_DIREC) == FA_DIREC) #define FIND_T_IS_FILE(fInfo) (1) #define FIND_RET_T int #define FINDFIRST_FILE(path, result) findfirst(path, result, FA_ARCH) #define FINDFIRST_DIR(path, result) findfirst(path, result, FA_DIREC) #define FINDNEXT(ff_res, result) FindNextFileA(ff_res, result) #define FINDFIRST_SUCCEEDED(ret) (ret == 0) #define FINDNEXT_SUCCEEDED(ret) (ret == 0) #define GETCWD(path, len) getcwd(path, len) #define CHDIR(path) chdir(path) #define CHDIR_SUCCEEDED(ret) (ret == 0) #endif #define NEWLINE "\r\n" #define NEWLINE_LEN 2 /* define this to get the header variables we use to build HTTP headers */ #define LWIP_HTTPD_DYNAMIC_HEADERS 1 #define LWIP_HTTPD_SSI 1 #include "../httpd_structs.h" #include "../core/inet_chksum.c" #include "../core/def.c" /** (Your server name here) */ const char *serverID = "Server: "HTTPD_SERVER_AGENT"\r\n"; /* change this to suit your MEM_ALIGNMENT */ #define PAYLOAD_ALIGNMENT 4 /* set this to 0 to prevent aligning payload */ #define ALIGN_PAYLOAD 1 /* define this to a type that has the required alignment */ #define PAYLOAD_ALIGN_TYPE "unsigned int" static int payload_alingment_dummy_counter = 0; #define HEX_BYTES_PER_LINE 16 #define MAX_PATH_LEN 256 #define COPY_BUFSIZE 10240 struct file_entry { struct file_entry* next; const char* filename_c; }; int process_sub(FILE *data_file, FILE *struct_file); int process_file(FILE *data_file, FILE *struct_file, const char *filename); int file_write_http_header(FILE *data_file, const char *filename, int file_size, u16_t *http_hdr_len, u16_t *http_hdr_chksum); int file_put_ascii(FILE *file, const char *ascii_string, int len, int *i); int s_put_ascii(char *buf, const char *ascii_string, int len, int *i); void concat_files(const char *file1, const char *file2, const char *targetfile); int check_path(char* path, size_t size); static unsigned char file_buffer_raw[COPY_BUFSIZE]; /* 5 bytes per char + 3 bytes per line */ static char file_buffer_c[COPY_BUFSIZE * 5 + ((COPY_BUFSIZE / HEX_BYTES_PER_LINE) * 3)]; char curSubdir[MAX_PATH_LEN]; char lastFileVar[MAX_PATH_LEN]; char hdr_buf[4096]; unsigned char processSubs = 1; unsigned char includeHttpHeader = 1; unsigned char useHttp11 = 0; unsigned char supportSsi = 1; unsigned char precalcChksum = 0; struct file_entry* first_file = NULL; struct file_entry* last_file = NULL; int main(int argc, char *argv[]) { char path[MAX_PATH_LEN]; char appPath[MAX_PATH_LEN]; FILE *data_file; FILE *struct_file; int filesProcessed; int i; char targetfile[MAX_PATH_LEN]; strcpy(targetfile, "fsdata.c"); memset(path, 0, sizeof(path)); memset(appPath, 0, sizeof(appPath)); printf(NEWLINE " makefsdata - HTML to C source converter" NEWLINE); printf(" by Jim Pettinato - circa 2003 " NEWLINE); printf(" extended by Simon Goldschmidt - 2009 " NEWLINE NEWLINE); strcpy(path, "fs"); for(i = 1; i < argc; i++) { if (argv[i][0] == '-') { if (strstr(argv[i], "-s")) { processSubs = 0; } else if (strstr(argv[i], "-e")) { includeHttpHeader = 0; } else if (strstr(argv[i], "-11")) { useHttp11 = 1; } else if (strstr(argv[i], "-nossi")) { supportSsi = 0; } else if (strstr(argv[i], "-c")) { precalcChksum = 1; } else if((argv[i][1] == 'f') && (argv[i][2] == ':')) { strncpy(targetfile, &argv[i][3], sizeof(targetfile) - 1); targetfile[sizeof(targetfile) - 1] = 0; printf("Writing to file \"%s\"\n", targetfile); } } else { strncpy(path, argv[i], sizeof(path)-1); path[sizeof(path)-1] = 0; } } if(!check_path(path, sizeof(path))) { printf("Invalid path: \"%s\"." NEWLINE, path); exit(-1); } GETCWD(appPath, MAX_PATH_LEN); /* if command line param or subdir named 'fs' not found spout usage verbiage */ if (!CHDIR_SUCCEEDED(CHDIR(path))) { /* if no subdir named 'fs' (or the one which was given) exists, spout usage verbiage */ printf(" Failed to open directory \"%s\"." NEWLINE NEWLINE, path); printf(" Usage: htmlgen [targetdir] [-s] [-i] [-f:]" NEWLINE NEWLINE); printf(" targetdir: relative or absolute path to files to convert" NEWLINE); printf(" switch -s: toggle processing of subdirectories (default is on)" NEWLINE); printf(" switch -e: exclude HTTP header from file (header is created at runtime, default is off)" NEWLINE); printf(" switch -11: include HTTP 1.1 header (1.0 is default)" NEWLINE); printf(" switch -nossi: no support for SSI (cannot calculate Content-Length for SSI)" NEWLINE); printf(" switch -c: precalculate checksums for all pages (default is off)" NEWLINE); printf(" switch -f: target filename (default is \"fsdata.c\")" NEWLINE); printf(" if targetdir not specified, htmlgen will attempt to" NEWLINE); printf(" process files in subdirectory 'fs'" NEWLINE); exit(-1); } CHDIR(appPath); printf("HTTP %sheader will %s statically included." NEWLINE, (includeHttpHeader ? (useHttp11 ? "1.1 " : "1.0 ") : ""), (includeHttpHeader ? "be" : "not be")); sprintf(curSubdir, ""); /* start off in web page's root directory - relative paths */ printf(" Processing all files in directory %s", path); if (processSubs) { printf(" and subdirectories..." NEWLINE NEWLINE); } else { printf("..." NEWLINE NEWLINE); } data_file = fopen("fsdata.tmp", "wb"); if (data_file == NULL) { printf("Failed to create file \"fsdata.tmp\"\n"); exit(-1); } struct_file = fopen("fshdr.tmp", "wb"); if (struct_file == NULL) { printf("Failed to create file \"fshdr.tmp\"\n"); fclose(data_file); exit(-1); } CHDIR(path); fprintf(data_file, "#include \"fs.h\"" NEWLINE); fprintf(data_file, "#include \"lwip/def.h\"" NEWLINE); fprintf(data_file, "#include \"fsdata.h\"" NEWLINE NEWLINE NEWLINE); fprintf(data_file, "#define file_NULL (struct fsdata_file *) NULL" NEWLINE NEWLINE NEWLINE); sprintf(lastFileVar, "NULL"); filesProcessed = process_sub(data_file, struct_file); /* data_file now contains all of the raw data.. now append linked list of * file header structs to allow embedded app to search for a file name */ fprintf(data_file, NEWLINE NEWLINE); fprintf(struct_file, "#define FS_ROOT file_%s" NEWLINE, lastFileVar); fprintf(struct_file, "#define FS_NUMFILES %d" NEWLINE NEWLINE, filesProcessed); fclose(data_file); fclose(struct_file); CHDIR(appPath); /* append struct_file to data_file */ printf(NEWLINE "Creating target file..." NEWLINE NEWLINE); concat_files("fsdata.tmp", "fshdr.tmp", targetfile); /* if succeeded, delete the temporary files */ if (remove("fsdata.tmp") != 0) { printf("Warning: failed to delete fsdata.tmp\n"); } if (remove("fshdr.tmp") != 0) { printf("Warning: failed to delete fshdr.tmp\n"); } printf(NEWLINE "Processed %d files - done." NEWLINE NEWLINE, filesProcessed); while (first_file != NULL) { struct file_entry* fe = first_file; first_file = fe->next; free(fe); } return 0; } int check_path(char* path, size_t size) { size_t slen; if (path[0] == 0) { /* empty */ return 0; } slen = strlen(path); if (slen >= size) { /* not NULL-terminated */ return 0; } while ((slen > 0) && ((path[slen] == '\\') || (path[slen] == '/'))) { /* path should not end with trailing backslash */ path[slen] = 0; slen--; } if (slen == 0) { return 0; } return 1; } static void copy_file(const char *filename_in, FILE *fout) { FILE *fin; size_t len; fin = fopen(filename_in, "rb"); if (fin == NULL) { printf("Failed to open file \"%s\"\n", filename_in); exit(-1); } while((len = fread(file_buffer_raw, 1, COPY_BUFSIZE, fin)) > 0) { fwrite(file_buffer_raw, 1, len, fout); } fclose(fin); } void concat_files(const char *file1, const char *file2, const char *targetfile) { FILE *fout; fout = fopen(targetfile, "wb"); if (fout == NULL) { printf("Failed to open file \"%s\"\n", targetfile); exit(-1); } copy_file(file1, fout); copy_file(file2, fout); fclose(fout); } int process_sub(FILE *data_file, FILE *struct_file) { FIND_T fInfo; FIND_RET_T fret; int filesProcessed = 0; if (processSubs) { /* process subs recursively */ size_t sublen = strlen(curSubdir); size_t freelen = sizeof(curSubdir) - sublen - 1; LWIP_ASSERT("sublen < sizeof(curSubdir)", sublen < sizeof(curSubdir)); fret = FINDFIRST_DIR("*", &fInfo); if (FINDFIRST_SUCCEEDED(fret)) { do { const char *curName = FIND_T_FILENAME(fInfo); if ((curName[0] == '.') || (strcmp(curName, "CVS") == 0)) { continue; } if (!FIND_T_IS_DIR(fInfo)) { continue; } if (freelen > 0) { CHDIR(curName); strncat(curSubdir, "/", freelen); strncat(curSubdir, curName, freelen - 1); curSubdir[sizeof(curSubdir) - 1] = 0; printf(NEWLINE "processing subdirectory %s/..." NEWLINE, curSubdir); filesProcessed += process_sub(data_file, struct_file); CHDIR(".."); curSubdir[sublen] = 0; } else { printf("WARNING: cannot process sub due to path length restrictions: \"%s/%s\"\n", curSubdir, curName); } } while (FINDNEXT_SUCCEEDED(FINDNEXT(fret, &fInfo))); } } fret = FINDFIRST_FILE("*.*", &fInfo); if (FINDFIRST_SUCCEEDED(fret)) { /* at least one file in directory */ do { if (FIND_T_IS_FILE(fInfo)) { const char *curName = FIND_T_FILENAME(fInfo); printf("processing %s/%s..." NEWLINE, curSubdir, curName); if (process_file(data_file, struct_file, curName) < 0) { printf(NEWLINE "Error... aborting" NEWLINE); return -1; } filesProcessed++; } } while (FINDNEXT_SUCCEEDED(FINDNEXT(fret, &fInfo))); } return filesProcessed; } int get_file_size(const char* filename) { FILE *inFile; int file_size = -1; inFile = fopen(filename, "rb"); if (inFile == NULL) { printf("Failed to open file \"%s\"\n", filename); exit(-1); } fseek(inFile, 0, SEEK_END); file_size = ftell(inFile); fclose(inFile); return file_size; } void process_file_data(const char *filename, FILE *data_file) { FILE *source_file; size_t len, written, i, src_off=0; source_file = fopen(filename, "rb"); if (source_file == NULL) { printf("Failed to open file \"%s\"\n", filename); exit(-1); } do { size_t off = 0; len = fread(file_buffer_raw, 1, COPY_BUFSIZE, source_file); if (len > 0) { for (i = 0; i < len; i++) { sprintf(&file_buffer_c[off], "0x%02.2x,", file_buffer_raw[i]); off += 5; if ((++src_off % HEX_BYTES_PER_LINE) == 0) { memcpy(&file_buffer_c[off], NEWLINE, NEWLINE_LEN); off += NEWLINE_LEN; } } written = fwrite(file_buffer_c, 1, off, data_file); } } while(len > 0); fclose(source_file); } int write_checksums(FILE *struct_file, const char *filename, const char *varname, u16_t hdr_len, u16_t hdr_chksum) { int chunk_size = TCP_MSS; int offset; size_t len; int i = 0; FILE *f; #if LWIP_TCP_TIMESTAMPS /* when timestamps are used, usable space is 12 bytes less per segment */ chunk_size -= 12; #endif fprintf(struct_file, "#if HTTPD_PRECALCULATED_CHECKSUM" NEWLINE); fprintf(struct_file, "const struct fsdata_chksum chksums_%s[] = {" NEWLINE, varname); memset(file_buffer_raw, 0xab, sizeof(file_buffer_raw)); f = fopen(filename, "rb"); if (f == NULL) { printf("Failed to open file \"%s\"\n", filename); exit(-1); } if (hdr_len > 0) { /* add checksum for HTTP header */ fprintf(struct_file, "{%d, 0x%04x, %d}," NEWLINE, 0, hdr_chksum, hdr_len); i++; } for (offset = hdr_len; ; offset += len) { unsigned short chksum; len = fread(file_buffer_raw, 1, chunk_size, f); if (len == 0) { break; } chksum = ~inet_chksum(file_buffer_raw, (u16_t)len); /* add checksum for data */ fprintf(struct_file, "{%d, 0x%04x, %d}," NEWLINE, offset, chksum, len); i++; } fclose(f); fprintf(struct_file, "};" NEWLINE); fprintf(struct_file, "#endif /* HTTPD_PRECALCULATED_CHECKSUM */" NEWLINE); return i; } static int is_valid_char_for_c_var(char x) { if (((x >= 'A') && (x <= 'Z')) || ((x >= 'a') && (x <= 'z')) || ((x >= '0') && (x <= '9')) || (x == '_')) { return 1; } return 0; } static void fix_filename_for_c(char* qualifiedName, size_t max_len) { struct file_entry* f; size_t len = strlen(qualifiedName); char *new_name = malloc(len + 2); int filename_ok; int cnt = 0; size_t i; if (len + 3 == max_len) { printf("File name too long: \"%s\"\n", qualifiedName); exit(-1); } strcpy(new_name, qualifiedName); for (i = 0; i < len; i++) { if (!is_valid_char_for_c_var(new_name[i])) { new_name[i] = '_'; } } do { filename_ok = 1; for (f = first_file; f != NULL; f = f->next) { if (!strcmp(f->filename_c, new_name)) { filename_ok = 0; cnt++; // try next unique file name sprintf(&new_name[len], "%d", cnt); break; } } } while (!filename_ok && (cnt < 999)); if (!filename_ok) { printf("Failed to get unique file name: \"%s\"\n", qualifiedName); exit(-1); } strcpy(qualifiedName, new_name); free(new_name); } static void register_filename(const char* qualifiedName) { struct file_entry* fe = malloc(sizeof(struct file_entry)); fe->filename_c = strdup(qualifiedName); fe->next = NULL; if (first_file == NULL) { first_file = last_file = fe; } else { last_file->next = fe; last_file = fe; } } int process_file(FILE *data_file, FILE *struct_file, const char *filename) { char varname[MAX_PATH_LEN]; int i = 0; char qualifiedName[MAX_PATH_LEN]; int file_size; u16_t http_hdr_chksum = 0; u16_t http_hdr_len = 0; int chksum_count = 0; /* create qualified name (TODO: prepend slash or not?) */ sprintf(qualifiedName,"%s/%s", curSubdir, filename); /* create C variable name */ strcpy(varname, qualifiedName); /* convert slashes & dots to underscores */ fix_filename_for_c(varname, MAX_PATH_LEN); register_filename(varname); #if ALIGN_PAYLOAD /* to force even alignment of array */ fprintf(data_file, "static const " PAYLOAD_ALIGN_TYPE " dummy_align_%s = %d;" NEWLINE, varname, payload_alingment_dummy_counter++); #endif /* ALIGN_PAYLOAD */ fprintf(data_file, "static const unsigned char data_%s[] = {" NEWLINE, varname); /* encode source file name (used by file system, not returned to browser) */ fprintf(data_file, "/* %s (%d chars) */" NEWLINE, qualifiedName, strlen(qualifiedName)+1); file_put_ascii(data_file, qualifiedName, strlen(qualifiedName)+1, &i); #if ALIGN_PAYLOAD /* pad to even number of bytes to assure payload is on aligned boundary */ while(i % PAYLOAD_ALIGNMENT != 0) { fprintf(data_file, "0x%02.2x,", 0); i++; } #endif /* ALIGN_PAYLOAD */ fprintf(data_file, NEWLINE); file_size = get_file_size(filename); if (includeHttpHeader) { file_write_http_header(data_file, filename, file_size, &http_hdr_len, &http_hdr_chksum); } if (precalcChksum) { chksum_count = write_checksums(struct_file, filename, varname, http_hdr_len, http_hdr_chksum); } /* build declaration of struct fsdata_file in temp file */ fprintf(struct_file, "const struct fsdata_file file_%s[] = { {" NEWLINE, varname); fprintf(struct_file, "file_%s," NEWLINE, lastFileVar); fprintf(struct_file, "data_%s," NEWLINE, varname); fprintf(struct_file, "data_%s + %d," NEWLINE, varname, i); fprintf(struct_file, "sizeof(data_%s) - %d," NEWLINE, varname, i); fprintf(struct_file, "%d," NEWLINE, includeHttpHeader); if (precalcChksum) { fprintf(struct_file, "#if HTTPD_PRECALCULATED_CHECKSUM" NEWLINE); fprintf(struct_file, "%d, chksums_%s," NEWLINE, chksum_count, varname); fprintf(struct_file, "#endif /* HTTPD_PRECALCULATED_CHECKSUM */" NEWLINE); } fprintf(struct_file, "}};" NEWLINE NEWLINE); strcpy(lastFileVar, varname); /* write actual file contents */ i = 0; fprintf(data_file, NEWLINE "/* raw file data (%d bytes) */" NEWLINE, file_size); process_file_data(filename, data_file); fprintf(data_file, "};" NEWLINE NEWLINE); return 0; } int file_write_http_header(FILE *data_file, const char *filename, int file_size, u16_t *http_hdr_len, u16_t *http_hdr_chksum) { int i = 0; int response_type = HTTP_HDR_OK; int file_type = HTTP_HDR_DEFAULT_TYPE; const char *cur_string; size_t cur_len; int written = 0; size_t hdr_len = 0; u16_t acc; const char *file_ext; int j; u8_t keepalive = useHttp11; if (keepalive) { size_t loop; for (loop = 0; loop < NUM_SHTML_EXTENSIONS; loop++) { if (strstr(filename, g_pcSSIExtensions[loop])) { /* no keepalive connection for SSI files */ keepalive = 0; } } } memset(hdr_buf, 0, sizeof(hdr_buf)); if (useHttp11) { response_type = HTTP_HDR_OK_11; } fprintf(data_file, NEWLINE "/* HTTP header */"); if (strstr(filename, "404") == filename) { response_type = HTTP_HDR_NOT_FOUND; if (useHttp11) { response_type = HTTP_HDR_NOT_FOUND_11; } } else if (strstr(filename, "400") == filename) { response_type = HTTP_HDR_BAD_REQUEST; if (useHttp11) { response_type = HTTP_HDR_BAD_REQUEST_11; } } else if (strstr(filename, "501") == filename) { response_type = HTTP_HDR_NOT_IMPL; if (useHttp11) { response_type = HTTP_HDR_NOT_IMPL_11; } } cur_string = g_psHTTPHeaderStrings[response_type]; cur_len = strlen(cur_string); fprintf(data_file, NEWLINE "/* \"%s\" (%d bytes) */" NEWLINE, cur_string, cur_len); written += file_put_ascii(data_file, cur_string, cur_len, &i); i = 0; if (precalcChksum) { memcpy(&hdr_buf[hdr_len], cur_string, cur_len); hdr_len += cur_len; } cur_string = serverID; cur_len = strlen(cur_string); fprintf(data_file, NEWLINE "/* \"%s\" (%d bytes) */" NEWLINE, cur_string, cur_len); written += file_put_ascii(data_file, cur_string, cur_len, &i); i = 0; if (precalcChksum) { memcpy(&hdr_buf[hdr_len], cur_string, cur_len); hdr_len += cur_len; } file_ext = filename; if (file_ext != NULL) { while(strstr(file_ext, ".") != NULL) { file_ext = strstr(file_ext, "."); file_ext++; } } if((file_ext == NULL) || (*file_ext == 0)) { printf("failed to get extension for file \"%s\", using default.\n", filename); } else { for(j = 0; j < NUM_HTTP_HEADERS; j++) { if(!strcmp(file_ext, g_psHTTPHeaders[j].extension)) { file_type = g_psHTTPHeaders[j].headerIndex; break; } } if (j >= NUM_HTTP_HEADERS) { printf("failed to get file type for extension \"%s\", using default.\n", file_ext); file_type = HTTP_HDR_DEFAULT_TYPE; } } if (useHttp11) { char intbuf[MAX_PATH_LEN]; int content_len = file_size; memset(intbuf, 0, sizeof(intbuf)); if (!keepalive) { content_len *= 2; } { cur_string = g_psHTTPHeaderStrings[HTTP_HDR_CONTENT_LENGTH]; cur_len = strlen(cur_string); fprintf(data_file, NEWLINE "/* \"%s%d\r\n\" (%d+ bytes) */" NEWLINE, cur_string, content_len, cur_len+2); written += file_put_ascii(data_file, cur_string, cur_len, &i); if (precalcChksum) { memcpy(&hdr_buf[hdr_len], cur_string, cur_len); hdr_len += cur_len; } _itoa(content_len, intbuf, 10); strcat(intbuf, "\r\n"); cur_len = strlen(intbuf); written += file_put_ascii(data_file, intbuf, cur_len, &i); i = 0; if (precalcChksum) { memcpy(&hdr_buf[hdr_len], intbuf, cur_len); hdr_len += cur_len; } } if (keepalive) { cur_string = g_psHTTPHeaderStrings[HTTP_HDR_CONN_KEEPALIVE]; } else { cur_string = g_psHTTPHeaderStrings[HTTP_HDR_CONN_CLOSE]; } cur_len = strlen(cur_string); fprintf(data_file, NEWLINE "/* \"%s\" (%d bytes) */" NEWLINE, cur_string, cur_len); written += file_put_ascii(data_file, cur_string, cur_len, &i); i = 0; if (precalcChksum) { memcpy(&hdr_buf[hdr_len], cur_string, cur_len); hdr_len += cur_len; } } cur_string = g_psHTTPHeaderStrings[file_type]; cur_len = strlen(cur_string); fprintf(data_file, NEWLINE "/* \"%s\" (%d bytes) */" NEWLINE, cur_string, cur_len); written += file_put_ascii(data_file, cur_string, cur_len, &i); i = 0; if (precalcChksum) { memcpy(&hdr_buf[hdr_len], cur_string, cur_len); hdr_len += cur_len; LWIP_ASSERT("hdr_len <= 0xffff", hdr_len <= 0xffff); LWIP_ASSERT("strlen(hdr_buf) == hdr_len", strlen(hdr_buf) == hdr_len); acc = ~inet_chksum(hdr_buf, (u16_t)hdr_len); *http_hdr_len = (u16_t)hdr_len; *http_hdr_chksum = acc; } return written; } int file_put_ascii(FILE *file, const char* ascii_string, int len, int *i) { int x; for(x = 0; x < len; x++) { unsigned char cur = ascii_string[x]; fprintf(file, "0x%02.2x,", cur); if ((++(*i) % HEX_BYTES_PER_LINE) == 0) { fprintf(file, NEWLINE); } } return len; } int s_put_ascii(char *buf, const char *ascii_string, int len, int *i) { int x; int idx = 0; for(x = 0; x < len; x++) { unsigned char cur = ascii_string[x]; sprintf(&buf[idx], "0x%02.2x,", cur); idx += 5; if ((++(*i) % HEX_BYTES_PER_LINE) == 0) { sprintf(&buf[idx], NEWLINE); idx += NEWLINE_LEN; } } return len; } ocproxy-1.60/contrib/apps/httpserver_raw/makefsdata/readme.txt000066400000000000000000000011611303453231400247200ustar00rootroot00000000000000This directory contains a script ('makefsdata') to create C code suitable for httpd for given html pages (or other files) in a directory. There is also a plain C console application doing the same and extended a bit. Usage: htmlgen [targetdir] [-s] [-i]s targetdir: relative or absolute path to files to convert switch -s: toggle processing of subdirectories (default is on) switch -e: exclude HTTP header from file (header is created at runtime, default is on) switch -11: include HTTP 1.1 header (1.0 is default) if targetdir not specified, makefsdata will attempt to process files in subdirectory 'fs'. ocproxy-1.60/contrib/apps/netbios/000077500000000000000000000000001303453231400172075ustar00rootroot00000000000000ocproxy-1.60/contrib/apps/netbios/netbios.c000066400000000000000000000252351303453231400210250ustar00rootroot00000000000000/** * @file * NetBIOS name service sample * */ /* * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * */ #include "lwip/opt.h" #if LWIP_UDP /* don't build if not configured for use in lwipopts.h */ #include "lwip/udp.h" #include "lwip/netif.h" #include /** This is an example implementation of a NetBIOS name server. * It responds to name queries for a configurable name. * Name resolving is not supported. * * Note that the device doesn't broadcast it's own name so can't * detect duplicate names! */ /** NetBIOS name of LWIP device * This must be uppercase until NETBIOS_STRCMP() is defined to a string * comparision function that is case insensitive. * If you want to use the netif's hostname, use this (with LWIP_NETIF_HOSTNAME): * (ip_current_netif() != NULL ? ip_current_netif()->hostname != NULL ? ip_current_netif()->hostname : "" : "") */ #ifndef NETBIOS_LWIP_NAME #define NETBIOS_LWIP_NAME "NETBIOSLWIPDEV" #endif /** Since there's no standard function for case-insensitive string comparision, * we need another define here: * define this to stricmp() for windows or strcasecmp() for linux. * If not defined, comparision is case sensitive and NETBIOS_LWIP_NAME must be * uppercase */ #ifndef NETBIOS_STRCMP #define NETBIOS_STRCMP(str1, str2) strcmp(str1, str2) #endif /** default port number for "NetBIOS Name service */ #define NETBIOS_PORT 137 /** size of a NetBIOS name */ #define NETBIOS_NAME_LEN 16 /** The Time-To-Live for NetBIOS name responds (in seconds) * Default is 300000 seconds (3 days, 11 hours, 20 minutes) */ #define NETBIOS_NAME_TTL 300000 /** NetBIOS header flags */ #define NETB_HFLAG_RESPONSE 0x8000U #define NETB_HFLAG_OPCODE 0x7800U #define NETB_HFLAG_OPCODE_NAME_QUERY 0x0000U #define NETB_HFLAG_AUTHORATIVE 0x0400U #define NETB_HFLAG_TRUNCATED 0x0200U #define NETB_HFLAG_RECURS_DESIRED 0x0100U #define NETB_HFLAG_RECURS_AVAILABLE 0x0080U #define NETB_HFLAG_BROADCAST 0x0010U #define NETB_HFLAG_REPLYCODE 0x0008U #define NETB_HFLAG_REPLYCODE_NOERROR 0x0000U /** NetBIOS name flags */ #define NETB_NFLAG_UNIQUE 0x8000U #define NETB_NFLAG_NODETYPE 0x6000U #define NETB_NFLAG_NODETYPE_HNODE 0x6000U #define NETB_NFLAG_NODETYPE_MNODE 0x4000U #define NETB_NFLAG_NODETYPE_PNODE 0x2000U #define NETB_NFLAG_NODETYPE_BNODE 0x0000U /** NetBIOS message header */ #ifdef PACK_STRUCT_USE_INCLUDES # include "arch/bpstruct.h" #endif PACK_STRUCT_BEGIN struct netbios_hdr { PACK_STRUCT_FIELD(u16_t trans_id); PACK_STRUCT_FIELD(u16_t flags); PACK_STRUCT_FIELD(u16_t questions); PACK_STRUCT_FIELD(u16_t answerRRs); PACK_STRUCT_FIELD(u16_t authorityRRs); PACK_STRUCT_FIELD(u16_t additionalRRs); } PACK_STRUCT_STRUCT; PACK_STRUCT_END #ifdef PACK_STRUCT_USE_INCLUDES # include "arch/epstruct.h" #endif /** NetBIOS message name part */ #ifdef PACK_STRUCT_USE_INCLUDES # include "arch/bpstruct.h" #endif PACK_STRUCT_BEGIN struct netbios_name_hdr { PACK_STRUCT_FIELD(u8_t nametype); PACK_STRUCT_FIELD(u8_t encname[(NETBIOS_NAME_LEN*2)+1]); PACK_STRUCT_FIELD(u16_t type); PACK_STRUCT_FIELD(u16_t cls); PACK_STRUCT_FIELD(u32_t ttl); PACK_STRUCT_FIELD(u16_t datalen); PACK_STRUCT_FIELD(u16_t flags); PACK_STRUCT_FIELD(ip_addr_p_t addr); } PACK_STRUCT_STRUCT; PACK_STRUCT_END #ifdef PACK_STRUCT_USE_INCLUDES # include "arch/epstruct.h" #endif /** NetBIOS message */ #ifdef PACK_STRUCT_USE_INCLUDES # include "arch/bpstruct.h" #endif PACK_STRUCT_BEGIN struct netbios_resp { struct netbios_hdr resp_hdr; struct netbios_name_hdr resp_name; } PACK_STRUCT_STRUCT; PACK_STRUCT_END #ifdef PACK_STRUCT_USE_INCLUDES # include "arch/epstruct.h" #endif /** NetBIOS decoding name */ static int netbios_name_decoding( char *name_enc, char *name_dec, int name_dec_len) { char *pname; char cname; char cnbname; int index = 0; LWIP_UNUSED_ARG(name_dec_len); /* Start decoding netbios name. */ pname = name_enc; for (;;) { /* Every two characters of the first level-encoded name * turn into one character in the decoded name. */ cname = *pname; if (cname == '\0') break; /* no more characters */ if (cname == '.') break; /* scope ID follows */ if (cname < 'A' || cname > 'Z') { /* Not legal. */ return -1; } cname -= 'A'; cnbname = cname << 4; pname++; cname = *pname; if (cname == '\0' || cname == '.') { /* No more characters in the name - but we're in * the middle of a pair. Not legal. */ return -1; } if (cname < 'A' || cname > 'Z') { /* Not legal. */ return -1; } cname -= 'A'; cnbname |= cname; pname++; /* Do we have room to store the character? */ if (index < NETBIOS_NAME_LEN) { /* Yes - store the character. */ name_dec[index++] = (cnbname!=' '?cnbname:'\0'); } } return 0; } #if 0 /* function currently unused */ /** NetBIOS encoding name */ static int netbios_name_encoding(char *name_enc, char *name_dec, int name_dec_len) { char *pname; char cname; unsigned char ucname; int index = 0; /* Start encoding netbios name. */ pname = name_enc; for (;;) { /* Every two characters of the first level-encoded name * turn into one character in the decoded name. */ cname = *pname; if (cname == '\0') break; /* no more characters */ if (cname == '.') break; /* scope ID follows */ if ((cname < 'A' || cname > 'Z') && (cname < '0' || cname > '9')) { /* Not legal. */ return -1; } /* Do we have room to store the character? */ if (index >= name_dec_len) { return -1; } /* Yes - store the character. */ ucname = cname; name_dec[index++] = ('A'+((ucname>>4) & 0x0F)); name_dec[index++] = ('A'+( ucname & 0x0F)); pname++; } /* Fill with "space" coding */ for (;indexpayload; struct netbios_name_hdr* netbios_name_hdr = (struct netbios_name_hdr*)(netbios_hdr+1); /* we only answer if we got a default interface */ if (netif_default != NULL) { /* @todo: do we need to check answerRRs/authorityRRs/additionalRRs? */ /* if the packet is a NetBIOS name query question */ if (((netbios_hdr->flags & PP_NTOHS(NETB_HFLAG_OPCODE)) == PP_NTOHS(NETB_HFLAG_OPCODE_NAME_QUERY)) && ((netbios_hdr->flags & PP_NTOHS(NETB_HFLAG_RESPONSE)) == 0) && (netbios_hdr->questions == PP_NTOHS(1))) { /* decode the NetBIOS name */ netbios_name_decoding( (char*)(netbios_name_hdr->encname), netbios_name, sizeof(netbios_name)); /* if the packet is for us */ if (NETBIOS_STRCMP(netbios_name, NETBIOS_LWIP_NAME) == 0) { struct pbuf *q; struct netbios_resp *resp; q = pbuf_alloc(PBUF_TRANSPORT, sizeof(struct netbios_resp), PBUF_RAM); if (q != NULL) { resp = (struct netbios_resp*)q->payload; /* prepare NetBIOS header response */ resp->resp_hdr.trans_id = netbios_hdr->trans_id; resp->resp_hdr.flags = PP_HTONS(NETB_HFLAG_RESPONSE | NETB_HFLAG_OPCODE_NAME_QUERY | NETB_HFLAG_AUTHORATIVE | NETB_HFLAG_RECURS_DESIRED); resp->resp_hdr.questions = 0; resp->resp_hdr.answerRRs = PP_HTONS(1); resp->resp_hdr.authorityRRs = 0; resp->resp_hdr.additionalRRs = 0; /* prepare NetBIOS header datas */ MEMCPY( resp->resp_name.encname, netbios_name_hdr->encname, sizeof(netbios_name_hdr->encname)); resp->resp_name.nametype = netbios_name_hdr->nametype; resp->resp_name.type = netbios_name_hdr->type; resp->resp_name.cls = netbios_name_hdr->cls; resp->resp_name.ttl = PP_HTONL(NETBIOS_NAME_TTL); resp->resp_name.datalen = PP_HTONS(sizeof(resp->resp_name.flags)+sizeof(resp->resp_name.addr)); resp->resp_name.flags = PP_HTONS(NETB_NFLAG_NODETYPE_BNODE); ip_addr_copy(resp->resp_name.addr, netif_default->ip_addr); /* send the NetBIOS response */ udp_sendto(upcb, q, addr, port); /* free the "reference" pbuf */ pbuf_free(q); } } } } /* free the pbuf */ pbuf_free(p); } } void netbios_init(void) { struct udp_pcb *pcb; LWIP_ASSERT("NetBIOS name is too long!", strlen(NETBIOS_LWIP_NAME) < NETBIOS_NAME_LEN); pcb = udp_new(); if (pcb != NULL) { /* we have to be allowed to send broadcast packets! */ pcb->so_options |= SOF_BROADCAST; udp_bind(pcb, IP_ADDR_ANY, NETBIOS_PORT); udp_recv(pcb, netbios_recv, pcb); } } #endif /* LWIP_UDP */ ocproxy-1.60/contrib/apps/netbios/netbios.h000066400000000000000000000001451303453231400210230ustar00rootroot00000000000000#ifndef LWIP_NETBIOS_H #define LWIP_NETBIOS_H void netbios_init(void); #endif /* LWIP_NETBIOS_H */ ocproxy-1.60/contrib/apps/netio/000077500000000000000000000000001303453231400166625ustar00rootroot00000000000000ocproxy-1.60/contrib/apps/netio/netio.c000066400000000000000000000016541303453231400201520ustar00rootroot00000000000000#include "netio.h" #include "lwip/opt.h" #include "lwip/tcp.h" /* See http://www.nwlab.net/art/netio/netio.html to get the netio tool */ #if LWIP_TCP static err_t netio_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err) { LWIP_UNUSED_ARG(arg); if (err == ERR_OK && p != NULL) { tcp_recved(pcb, p->tot_len); pbuf_free(p); } else { pbuf_free(p); } if (err == ERR_OK && p == NULL) { tcp_arg(pcb, NULL); tcp_sent(pcb, NULL); tcp_recv(pcb, NULL); tcp_close(pcb); } return ERR_OK; } static err_t netio_accept(void *arg, struct tcp_pcb *pcb, err_t err) { LWIP_UNUSED_ARG(arg); LWIP_UNUSED_ARG(err); tcp_arg(pcb, NULL); tcp_sent(pcb, NULL); tcp_recv(pcb, netio_recv); return ERR_OK; } void netio_init(void) { struct tcp_pcb *pcb; pcb = tcp_new(); tcp_bind(pcb, IP_ADDR_ANY, 18767); pcb = tcp_listen(pcb); tcp_accept(pcb, netio_accept); } #endif /* LWIP_TCP */ ocproxy-1.60/contrib/apps/netio/netio.h000066400000000000000000000001351303453231400201500ustar00rootroot00000000000000#ifndef LWIP_NETIO_H #define LWIP_NETIO_H void netio_init(void); #endif /* LWIP_NETIO_H */ ocproxy-1.60/contrib/apps/ping/000077500000000000000000000000001303453231400165015ustar00rootroot00000000000000ocproxy-1.60/contrib/apps/ping/ping.c000066400000000000000000000211031303453231400175770ustar00rootroot00000000000000/** * @file * Ping sender module * */ /* * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * */ /** * This is an example of a "ping" sender (with raw API and socket API). * It can be used as a start point to maintain opened a network connection, or * like a network "watchdog" for your device. * */ #include "lwip/opt.h" #if LWIP_RAW /* don't build if not configured for use in lwipopts.h */ #include "ping.h" #include "lwip/mem.h" #include "lwip/raw.h" #include "lwip/icmp.h" #include "lwip/netif.h" #include "lwip/sys.h" #include "lwip/timers.h" #include "lwip/inet_chksum.h" #if PING_USE_SOCKETS #include "lwip/sockets.h" #include "lwip/inet.h" #endif /* PING_USE_SOCKETS */ /** * PING_DEBUG: Enable debugging for PING. */ #ifndef PING_DEBUG #define PING_DEBUG LWIP_DBG_ON #endif /** ping target - should be a "ip_addr_t" */ #ifndef PING_TARGET #define PING_TARGET (netif_default?netif_default->gw:ip_addr_any) #endif /** ping receive timeout - in milliseconds */ #ifndef PING_RCV_TIMEO #define PING_RCV_TIMEO 1000 #endif /** ping delay - in milliseconds */ #ifndef PING_DELAY #define PING_DELAY 1000 #endif /** ping identifier - must fit on a u16_t */ #ifndef PING_ID #define PING_ID 0xAFAF #endif /** ping additional data size to include in the packet */ #ifndef PING_DATA_SIZE #define PING_DATA_SIZE 32 #endif /** ping result action - no default action */ #ifndef PING_RESULT #define PING_RESULT(ping_ok) #endif /* ping variables */ static u16_t ping_seq_num; static u32_t ping_time; #if !PING_USE_SOCKETS static struct raw_pcb *ping_pcb; #endif /* PING_USE_SOCKETS */ /** Prepare a echo ICMP request */ static void ping_prepare_echo( struct icmp_echo_hdr *iecho, u16_t len) { size_t i; size_t data_len = len - sizeof(struct icmp_echo_hdr); ICMPH_TYPE_SET(iecho, ICMP_ECHO); ICMPH_CODE_SET(iecho, 0); iecho->chksum = 0; iecho->id = PING_ID; iecho->seqno = htons(++ping_seq_num); /* fill the additional data buffer with some data */ for(i = 0; i < data_len; i++) { ((char*)iecho)[sizeof(struct icmp_echo_hdr) + i] = (char)i; } iecho->chksum = inet_chksum(iecho, len); } #if PING_USE_SOCKETS /* Ping using the socket ip */ static err_t ping_send(int s, ip_addr_t *addr) { int err; struct icmp_echo_hdr *iecho; struct sockaddr_in to; size_t ping_size = sizeof(struct icmp_echo_hdr) + PING_DATA_SIZE; LWIP_ASSERT("ping_size is too big", ping_size <= 0xffff); iecho = (struct icmp_echo_hdr *)mem_malloc((mem_size_t)ping_size); if (!iecho) { return ERR_MEM; } ping_prepare_echo(iecho, (u16_t)ping_size); to.sin_len = sizeof(to); to.sin_family = AF_INET; inet_addr_from_ipaddr(&to.sin_addr, addr); err = lwip_sendto(s, iecho, ping_size, 0, (struct sockaddr*)&to, sizeof(to)); mem_free(iecho); return (err ? ERR_OK : ERR_VAL); } static void ping_recv(int s) { char buf[64]; int fromlen, len; struct sockaddr_in from; struct ip_hdr *iphdr; struct icmp_echo_hdr *iecho; while((len = lwip_recvfrom(s, buf, sizeof(buf), 0, (struct sockaddr*)&from, (socklen_t*)&fromlen)) > 0) { if (len >= (int)(sizeof(struct ip_hdr)+sizeof(struct icmp_echo_hdr))) { ip_addr_t fromaddr; inet_addr_to_ipaddr(&fromaddr, &from.sin_addr); LWIP_DEBUGF( PING_DEBUG, ("ping: recv ")); ip_addr_debug_print(PING_DEBUG, &fromaddr); LWIP_DEBUGF( PING_DEBUG, (" %"U32_F" ms\n", (sys_now() - ping_time))); iphdr = (struct ip_hdr *)buf; iecho = (struct icmp_echo_hdr *)(buf + (IPH_HL(iphdr) * 4)); if ((iecho->id == PING_ID) && (iecho->seqno == htons(ping_seq_num))) { /* do some ping result processing */ PING_RESULT((ICMPH_TYPE(iecho) == ICMP_ER)); return; } else { LWIP_DEBUGF( PING_DEBUG, ("ping: drop\n")); } } } if (len == 0) { LWIP_DEBUGF( PING_DEBUG, ("ping: recv - %"U32_F" ms - timeout\n", (sys_now()-ping_time))); } /* do some ping result processing */ PING_RESULT(0); } static void ping_thread(void *arg) { int s; int timeout = PING_RCV_TIMEO; ip_addr_t ping_target; LWIP_UNUSED_ARG(arg); if ((s = lwip_socket(AF_INET, SOCK_RAW, IP_PROTO_ICMP)) < 0) { return; } lwip_setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)); while (1) { ping_target = PING_TARGET; if (ping_send(s, &ping_target) == ERR_OK) { LWIP_DEBUGF( PING_DEBUG, ("ping: send ")); ip_addr_debug_print(PING_DEBUG, &ping_target); LWIP_DEBUGF( PING_DEBUG, ("\n")); ping_time = sys_now(); ping_recv(s); } else { LWIP_DEBUGF( PING_DEBUG, ("ping: send ")); ip_addr_debug_print(PING_DEBUG, &ping_target); LWIP_DEBUGF( PING_DEBUG, (" - error\n")); } sys_msleep(PING_DELAY); } } #else /* PING_USE_SOCKETS */ /* Ping using the raw ip */ static u8_t ping_recv(void *arg, struct raw_pcb *pcb, struct pbuf *p, ip_addr_t *addr) { struct icmp_echo_hdr *iecho; LWIP_UNUSED_ARG(arg); LWIP_UNUSED_ARG(pcb); LWIP_UNUSED_ARG(addr); LWIP_ASSERT("p != NULL", p != NULL); if ((p->tot_len >= (PBUF_IP_HLEN + sizeof(struct icmp_echo_hdr))) && pbuf_header(p, -PBUF_IP_HLEN) == 0) { iecho = (struct icmp_echo_hdr *)p->payload; if ((iecho->id == PING_ID) && (iecho->seqno == htons(ping_seq_num))) { LWIP_DEBUGF( PING_DEBUG, ("ping: recv ")); ip_addr_debug_print(PING_DEBUG, addr); LWIP_DEBUGF( PING_DEBUG, (" %"U32_F" ms\n", (sys_now()-ping_time))); /* do some ping result processing */ PING_RESULT(1); pbuf_free(p); return 1; /* eat the packet */ } /* not eaten, restore original packet */ pbuf_header(p, PBUF_IP_HLEN); } return 0; /* don't eat the packet */ } static void ping_send(struct raw_pcb *raw, ip_addr_t *addr) { struct pbuf *p; struct icmp_echo_hdr *iecho; size_t ping_size = sizeof(struct icmp_echo_hdr) + PING_DATA_SIZE; LWIP_DEBUGF( PING_DEBUG, ("ping: send ")); ip_addr_debug_print(PING_DEBUG, addr); LWIP_DEBUGF( PING_DEBUG, ("\n")); LWIP_ASSERT("ping_size <= 0xffff", ping_size <= 0xffff); p = pbuf_alloc(PBUF_IP, (u16_t)ping_size, PBUF_RAM); if (!p) { return; } if ((p->len == p->tot_len) && (p->next == NULL)) { iecho = (struct icmp_echo_hdr *)p->payload; ping_prepare_echo(iecho, (u16_t)ping_size); raw_sendto(raw, p, addr); ping_time = sys_now(); } pbuf_free(p); } static void ping_timeout(void *arg) { struct raw_pcb *pcb = (struct raw_pcb*)arg; ip_addr_t ping_target = PING_TARGET; LWIP_ASSERT("ping_timeout: no pcb given!", pcb != NULL); ping_send(pcb, &ping_target); sys_timeout(PING_DELAY, ping_timeout, pcb); } static void ping_raw_init(void) { ping_pcb = raw_new(IP_PROTO_ICMP); LWIP_ASSERT("ping_pcb != NULL", ping_pcb != NULL); raw_recv(ping_pcb, ping_recv, NULL); raw_bind(ping_pcb, IP_ADDR_ANY); sys_timeout(PING_DELAY, ping_timeout, ping_pcb); } void ping_send_now() { ip_addr_t ping_target = PING_TARGET; LWIP_ASSERT("ping_pcb != NULL", ping_pcb != NULL); ping_send(ping_pcb, &ping_target); } #endif /* PING_USE_SOCKETS */ void ping_init(void) { #if PING_USE_SOCKETS sys_thread_new("ping_thread", ping_thread, NULL, DEFAULT_THREAD_STACKSIZE, DEFAULT_THREAD_PRIO); #else /* PING_USE_SOCKETS */ ping_raw_init(); #endif /* PING_USE_SOCKETS */ } #endif /* LWIP_RAW */ ocproxy-1.60/contrib/apps/ping/ping.h000066400000000000000000000005071303453231400176110ustar00rootroot00000000000000#ifndef LWIP_PING_H #define LWIP_PING_H /** * PING_USE_SOCKETS: Set to 1 to use sockets, otherwise the raw api is used */ #ifndef PING_USE_SOCKETS #define PING_USE_SOCKETS LWIP_SOCKET #endif void ping_init(void); #if !PING_USE_SOCKETS void ping_send_now(void); #endif /* !PING_USE_SOCKETS */ #endif /* LWIP_PING_H */ ocproxy-1.60/contrib/apps/rtp/000077500000000000000000000000001303453231400163515ustar00rootroot00000000000000ocproxy-1.60/contrib/apps/rtp/rtp.c000066400000000000000000000221461303453231400173270ustar00rootroot00000000000000/** * @file * RTP client/server module * */ /* * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * */ #include "lwip/opt.h" #if LWIP_SOCKET && LWIP_IGMP /* don't build if not configured for use in lwipopts.h */ #include "lwip/sys.h" #include "lwip/sockets.h" #include "rtpdata.h" #include /** This is an example of a "RTP" client/server based on a MPEG4 bitstream (with socket API). */ /** * RTP_DEBUG: Enable debugging for RTP. */ #ifndef RTP_DEBUG #define RTP_DEBUG LWIP_DBG_ON #endif /** RTP stream port */ #ifndef RTP_STREAM_PORT #define RTP_STREAM_PORT 4000 #endif /** RTP stream multicast address as IPv4 address in "u32_t" format */ #ifndef RTP_STREAM_ADDRESS #define RTP_STREAM_ADDRESS inet_addr("232.0.0.0") #endif /** RTP send delay - in milliseconds */ #ifndef RTP_SEND_DELAY #define RTP_SEND_DELAY 40 #endif /** RTP receive timeout - in milliseconds */ #ifndef RTP_RECV_TIMEOUT #define RTP_RECV_TIMEOUT 2000 #endif /** RTP stats display period - in received packets */ #ifndef RTP_RECV_STATS #define RTP_RECV_STATS 50 #endif /** RTP macro to let the application process the data */ #ifndef RTP_RECV_PROCESSING #define RTP_RECV_PROCESSING(p,s) #endif /** RTP packet/payload size */ #define RTP_PACKET_SIZE 1500 #define RTP_PAYLOAD_SIZE 1024 /** RTP header constants */ #define RTP_VERSION 0x80 #define RTP_TIMESTAMP_INCREMENT 3600 #define RTP_SSRC 0 #define RTP_PAYLOADTYPE 96 #define RTP_MARKER_MASK 0x80 /** RTP message header */ #ifdef PACK_STRUCT_USE_INCLUDES # include "arch/bpstruct.h" #endif PACK_STRUCT_BEGIN struct rtp_hdr { PACK_STRUCT_FIELD(u8_t version); PACK_STRUCT_FIELD(u8_t payloadtype); PACK_STRUCT_FIELD(u16_t seqNum); PACK_STRUCT_FIELD(u32_t timestamp); PACK_STRUCT_FIELD(u32_t ssrc); } PACK_STRUCT_STRUCT; PACK_STRUCT_END #ifdef PACK_STRUCT_USE_INCLUDES # include "arch/epstruct.h" #endif /** RTP packets */ static u8_t rtp_send_packet[RTP_PACKET_SIZE]; static u8_t rtp_recv_packet[RTP_PACKET_SIZE]; /** * RTP send packets */ static void rtp_send_packets( int sock, struct sockaddr_in* to) { struct rtp_hdr* rtphdr; u8_t* rtp_payload; int rtp_payload_size; int rtp_data_index; /* prepare RTP packet */ rtphdr = (struct rtp_hdr*)rtp_send_packet; rtphdr->version = RTP_VERSION; rtphdr->payloadtype = 0; rtphdr->ssrc = PP_HTONL(RTP_SSRC); rtphdr->timestamp = htonl(ntohl(rtphdr->timestamp) + RTP_TIMESTAMP_INCREMENT); /* send RTP stream packets */ rtp_data_index = 0; do { rtp_payload = rtp_send_packet+sizeof(struct rtp_hdr); rtp_payload_size = min(RTP_PAYLOAD_SIZE, (sizeof(rtp_data) - rtp_data_index)); memcpy(rtp_payload, rtp_data + rtp_data_index, rtp_payload_size); /* set MARKER bit in RTP header on the last packet of an image */ rtphdr->payloadtype = RTP_PAYLOADTYPE | (((rtp_data_index + rtp_payload_size) >= sizeof(rtp_data)) ? RTP_MARKER_MASK : 0); /* send RTP stream packet */ if (sendto(sock, rtp_send_packet, sizeof(struct rtp_hdr) + rtp_payload_size, 0, (struct sockaddr *)to, sizeof(struct sockaddr)) >= 0) { rtphdr->seqNum = htons(ntohs(rtphdr->seqNum) + 1); rtp_data_index += rtp_payload_size; } else { LWIP_DEBUGF(RTP_DEBUG, ("rtp_sender: not sendto==%i\n", errno)); } }while (rtp_data_index < sizeof(rtp_data)); } /** * RTP send thread */ static void rtp_send_thread(void *arg) { int sock; struct sockaddr_in local; struct sockaddr_in to; u32_t rtp_stream_address; LWIP_UNUSED_ARG(arg); /* initialize RTP stream address */ rtp_stream_address = RTP_STREAM_ADDRESS; /* if we got a valid RTP stream address... */ if (rtp_stream_address != 0) { /* create new socket */ sock = socket(AF_INET, SOCK_DGRAM, 0); if (sock >= 0) { /* prepare local address */ memset(&local, 0, sizeof(local)); local.sin_family = AF_INET; local.sin_port = PP_HTONS(INADDR_ANY); local.sin_addr.s_addr = PP_HTONL(INADDR_ANY); /* bind to local address */ if (bind(sock, (struct sockaddr *)&local, sizeof(local)) == 0) { /* prepare RTP stream address */ memset(&to, 0, sizeof(to)); to.sin_family = AF_INET; to.sin_port = PP_HTONS(RTP_STREAM_PORT); to.sin_addr.s_addr = rtp_stream_address; /* send RTP packets */ memset(rtp_send_packet, 0, sizeof(rtp_send_packet)); while (1) { rtp_send_packets( sock, &to); sys_msleep(RTP_SEND_DELAY); } } /* close the socket */ closesocket(sock); } } } /** * RTP recv thread */ static void rtp_recv_thread(void *arg) { int sock; struct sockaddr_in local; struct sockaddr_in from; int fromlen; struct ip_mreq ipmreq; struct rtp_hdr* rtphdr; u32_t rtp_stream_address; int timeout; int result; int recvrtppackets = 0; int lostrtppackets = 0; u16_t lastrtpseq = 0; LWIP_UNUSED_ARG(arg); /* initialize RTP stream address */ rtp_stream_address = RTP_STREAM_ADDRESS; /* if we got a valid RTP stream address... */ if (rtp_stream_address != 0) { /* create new socket */ sock = socket(AF_INET, SOCK_DGRAM, 0); if (sock >= 0) { /* prepare local address */ memset(&local, 0, sizeof(local)); local.sin_family = AF_INET; local.sin_port = PP_HTONS(RTP_STREAM_PORT); local.sin_addr.s_addr = PP_HTONL(INADDR_ANY); /* bind to local address */ if (bind(sock, (struct sockaddr *)&local, sizeof(local)) == 0) { /* set recv timeout */ timeout = RTP_RECV_TIMEOUT; setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout)); /* prepare multicast "ip_mreq" struct */ ipmreq.imr_multiaddr.s_addr = rtp_stream_address; ipmreq.imr_interface.s_addr = PP_HTONL(INADDR_ANY); /* join multicast group */ if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &ipmreq, sizeof(ipmreq)) == 0) { /* receive RTP packets */ while(1) { fromlen = sizeof(from); result = recvfrom(sock, rtp_recv_packet, sizeof(rtp_recv_packet), 0, (struct sockaddr *)&from, (socklen_t *)&fromlen); if (result >= sizeof(struct rtp_hdr)) { rtphdr = (struct rtp_hdr *)rtp_recv_packet; recvrtppackets++; if ((lastrtpseq == 0) || ((lastrtpseq + 1) == ntohs(rtphdr->seqNum))) { RTP_RECV_PROCESSING((rtp_recv_packet + sizeof(rtp_hdr)),(result-sizeof(rtp_hdr))); } else { lostrtppackets++; } lastrtpseq = ntohs(rtphdr->seqNum); if ((recvrtppackets % RTP_RECV_STATS) == 0) { LWIP_DEBUGF(RTP_DEBUG, ("rtp_recv_thread: recv %6i packet(s) / lost %4i packet(s) (%.4f%%)...\n", recvrtppackets, lostrtppackets, (lostrtppackets*100.0)/recvrtppackets)); } } else { LWIP_DEBUGF(RTP_DEBUG, ("rtp_recv_thread: recv timeout...\n")); } } /* leave multicast group */ setsockopt(sock, IPPROTO_IP, IP_DROP_MEMBERSHIP, &ipmreq, sizeof(ipmreq)); } } /* close the socket */ closesocket(sock); } } } void rtp_init(void) { sys_thread_new("rtp_send_thread", rtp_send_thread, NULL, DEFAULT_THREAD_STACKSIZE, DEFAULT_THREAD_PRIO); sys_thread_new("rtp_recv_thread", rtp_recv_thread, NULL, DEFAULT_THREAD_STACKSIZE, DEFAULT_THREAD_PRIO); } #endif /* LWIP_SOCKET && LWIP_IGMP */ ocproxy-1.60/contrib/apps/rtp/rtp.h000066400000000000000000000002301303453231400173220ustar00rootroot00000000000000#ifndef LWIP_RTP_H #define LWIP_RTP_H #if LWIP_SOCKET && LWIP_IGMP void rtp_init(void); #endif /* LWIP_SOCKET && LWIP_IGMP */ #endif /* LWIP_RTP_H */ ocproxy-1.60/contrib/apps/rtp/rtpdata.h000066400000000000000000003130051303453231400201630ustar00rootroot00000000000000const char rtp_data[] = { 0x00, 0x00, 0x01, 0xb0, 0xf5, 0x00, 0x00, 0x01, 0xb5, 0x09, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x20, 0x00, 0x86, 0x84, 0x00, 0x67, 0x0c, 0x2c, 0x10, 0x90, 0x51, 0x8f, 0x00, 0x00, 0x01, 0xb2, 0x44, 0x69, 0x76, 0x58, 0x35, 0x30, 0x33, 0x62, 0x31, 0x33, 0x39, 0x33, 0x70, 0x00, 0x00, 0x01, 0xb2, 0x58, 0x76, 0x69, 0x44, 0x30, 0x30, 0x33, 0x39, 0x00, 0x00, 0x01, 0xb6, 0x18, 0x60, 0xab, 0x94, 0x03, 0xc0, 0xca, 0xc0, 0x3e, 0xd0, 0x78, 0x4f, 0xf9, 0x44, 0x91, 0xe9, 0xfa, 0xc9, 0xfe, 0xa1, 0xa4, 0xc1, 0x66, 0x03, 0x2e, 0x39, 0x0c, 0x7e, 0x0e, 0xaa, 0x02, 0x92, 0xf8, 0xd5, 0xec, 0xe2, 0x35, 0xb9, 0x35, 0x0c, 0xb3, 0x82, 0xa6, 0xad, 0xd0, 0xd1, 0xca, 0xb8, 0xe8, 0x10, 0x55, 0x78, 0x03, 0xc0, 0x38, 0x15, 0xba, 0xce, 0xe2, 0xea, 0x00, 0xc3, 0x60, 0xb1, 0x70, 0xf4, 0x14, 0x6c, 0x35, 0x4d, 0xe8, 0x5a, 0x1e, 0x58, 0xdf, 0x03, 0x01, 0xfd, 0x2a, 0x45, 0x54, 0xca, 0x0f, 0x05, 0x00, 0xbd, 0xd0, 0xcc, 0xb4, 0x90, 0x4c, 0x24, 0x6b, 0x20, 0x30, 0x95, 0xf1, 0x2f, 0xb4, 0xa7, 0x83, 0xdc, 0xce, 0x03, 0x05, 0x02, 0x1a, 0x5d, 0x1a, 0x2c, 0xbf, 0x51, 0x28, 0x8b, 0xd7, 0x6b, 0xdd, 0xf9, 0x44, 0xbb, 0x0e, 0x91, 0x64, 0xb9, 0xa6, 0x33, 0xd3, 0x6e, 0x34, 0xa4, 0xac, 0xac, 0x53, 0x0d, 0x79, 0xbe, 0xae, 0x5b, 0x47, 0x2e, 0xde, 0x62, 0xa1, 0x53, 0xcd, 0x7d, 0xfe, 0x66, 0xa1, 0x2b, 0x9c, 0xe1, 0xca, 0xbc, 0xea, 0x84, 0x1c, 0x68, 0xff, 0xbb, 0x28, 0xa1, 0x26, 0x18, 0x99, 0xb1, 0x4f, 0x68, 0x80, 0x28, 0x0e, 0x20, 0xc3, 0xbf, 0x0f, 0x80, 0xf8, 0x90, 0x3b, 0x1f, 0x16, 0xe4, 0xb0, 0x6f, 0x44, 0x16, 0x38, 0xb8, 0xc3, 0x81, 0x22, 0xfa, 0xe3, 0x09, 0xf6, 0x61, 0x6d, 0xef, 0x67, 0x56, 0x3b, 0x57, 0xb5, 0x23, 0x03, 0x1f, 0x6d, 0x0d, 0xb9, 0x08, 0xc6, 0x43, 0xba, 0xd1, 0x40, 0x5a, 0xe8, 0xca, 0x9e, 0x17, 0x1f, 0x6d, 0x5d, 0x16, 0x98, 0xab, 0xe6, 0x99, 0xf6, 0x37, 0xc6, 0x1b, 0xdc, 0xb9, 0xb3, 0xfe, 0x9a, 0x4b, 0x1e, 0xec, 0xf9, 0x5f, 0xb8, 0xc7, 0xfc, 0xbe, 0x6c, 0xd5, 0xf3, 0x9b, 0x17, 0x8b, 0x89, 0x82, 0xff, 0x30, 0x19, 0x20, 0x30, 0xe6, 0x29, 0x96, 0x75, 0x75, 0xeb, 0x00, 0x3f, 0xa1, 0x20, 0x5b, 0x06, 0x11, 0x98, 0x1f, 0xb2, 0xad, 0x3a, 0x59, 0xe6, 0x7d, 0x38, 0xa4, 0xb1, 0x4f, 0xfe, 0xdf, 0x3a, 0x4b, 0xdb, 0x69, 0xc3, 0x93, 0xcc, 0xdf, 0x5e, 0xf7, 0x2a, 0x38, 0x2a, 0x89, 0x84, 0x80, 0x6c, 0x12, 0x44, 0x95, 0x78, 0xd8, 0x7e, 0x3f, 0x4e, 0xcf, 0x3f, 0x39, 0xba, 0x9f, 0xfa, 0x8f, 0x2f, 0x62, 0xfa, 0xf0, 0xb6, 0x20, 0xa7, 0x06, 0x02, 0x3f, 0x28, 0x96, 0x80, 0xf0, 0x99, 0x8e, 0x82, 0x15, 0x11, 0x87, 0x35, 0xa4, 0xfd, 0x53, 0xcb, 0xcd, 0x68, 0x38, 0xe8, 0xdb, 0x8d, 0xc2, 0x71, 0xbc, 0x65, 0x3e, 0xac, 0x5b, 0x0d, 0xae, 0xc0, 0x3c, 0x77, 0xfe, 0xe8, 0xde, 0x3c, 0xbd, 0xdb, 0xb3, 0x39, 0x09, 0x56, 0x0a, 0xa2, 0xfe, 0x40, 0xd7, 0x6f, 0x56, 0x07, 0x02, 0xec, 0xd6, 0xed, 0x06, 0x5e, 0x2f, 0xb6, 0xce, 0xf1, 0x4f, 0x16, 0x88, 0x04, 0x41, 0x79, 0x0e, 0x98, 0xbe, 0x54, 0x75, 0x1a, 0xd6, 0x50, 0xcf, 0x82, 0x6a, 0xf7, 0xaf, 0x7f, 0xfb, 0x6d, 0x88, 0x97, 0x24, 0x40, 0x68, 0xa0, 0x57, 0x79, 0x57, 0xe9, 0x6b, 0xaa, 0xe5, 0xe4, 0x2b, 0xaa, 0x14, 0x64, 0x90, 0x6c, 0x50, 0x4a, 0xe3, 0x97, 0x43, 0xf6, 0x81, 0x90, 0xa9, 0xa6, 0xba, 0xb1, 0x21, 0x12, 0x5f, 0xe0, 0xdf, 0x88, 0x86, 0x03, 0x30, 0x94, 0xb2, 0x6d, 0xd2, 0xdc, 0x45, 0x14, 0x54, 0x1d, 0xe8, 0x38, 0x8d, 0xbe, 0x8a, 0xaf, 0x20, 0xa2, 0x3e, 0xa2, 0x5c, 0xc6, 0xae, 0xe6, 0xc4, 0x48, 0xec, 0xea, 0xc7, 0x4e, 0x17, 0xb2, 0x91, 0x52, 0xb4, 0xe9, 0x8b, 0x15, 0xfb, 0x99, 0x7c, 0xda, 0xb8, 0xad, 0x57, 0x31, 0x5b, 0x5b, 0x67, 0xaa, 0x1e, 0x93, 0x76, 0xa5, 0x25, 0xd9, 0x0d, 0x70, 0xd8, 0xb9, 0x11, 0x34, 0xfd, 0xaf, 0x0e, 0x0d, 0x42, 0x57, 0x97, 0x26, 0x06, 0xdf, 0x29, 0x7e, 0x79, 0x72, 0x22, 0x36, 0xa5, 0x9f, 0x6a, 0x16, 0x24, 0x6f, 0x10, 0x56, 0xec, 0x5b, 0x46, 0x50, 0x94, 0x88, 0xc4, 0xfa, 0x9e, 0xd8, 0x5b, 0xb7, 0x50, 0x72, 0x62, 0x25, 0xaa, 0x39, 0x84, 0x69, 0xaa, 0xfc, 0xbf, 0x9b, 0x45, 0xf7, 0xc5, 0x41, 0x97, 0x41, 0xc7, 0xac, 0x7f, 0x68, 0x92, 0xab, 0x64, 0xaa, 0x46, 0x32, 0x84, 0x77, 0x1b, 0xfc, 0xbc, 0x5a, 0x42, 0x28, 0xfa, 0x3e, 0x55, 0xf4, 0xe9, 0x44, 0xac, 0xc5, 0x4a, 0x6c, 0x93, 0xde, 0x03, 0x6d, 0xdc, 0xb8, 0x5b, 0xb7, 0x83, 0x7e, 0xc2, 0xaa, 0x33, 0x70, 0x34, 0x41, 0x46, 0x25, 0xa5, 0x6f, 0xdb, 0x96, 0x0f, 0xd3, 0xab, 0xd4, 0x17, 0x65, 0x96, 0x0c, 0x1e, 0x39, 0x4c, 0x9d, 0x90, 0x3f, 0x5b, 0x8d, 0xaa, 0xce, 0xac, 0xa6, 0x50, 0xf0, 0x66, 0xb2, 0x30, 0xce, 0x42, 0x61, 0xaa, 0xb6, 0x7e, 0xca, 0xbf, 0xfd, 0xbf, 0xef, 0x51, 0xed, 0xdf, 0x95, 0x0b, 0xa7, 0x34, 0x24, 0x13, 0x62, 0x44, 0x81, 0xdf, 0x3a, 0x8e, 0x95, 0x91, 0x67, 0xd7, 0x57, 0x54, 0x92, 0x1d, 0x79, 0xa3, 0x2a, 0xf3, 0x0c, 0x7a, 0x12, 0xa8, 0x33, 0xf9, 0x05, 0x02, 0x7b, 0xef, 0x12, 0x18, 0xab, 0x8b, 0x40, 0x38, 0x7e, 0x0c, 0x1f, 0x04, 0x30, 0x62, 0xa8, 0xd5, 0xd9, 0x78, 0xdd, 0x1c, 0xb4, 0x57, 0xc1, 0x83, 0xc4, 0x41, 0x08, 0x72, 0x5c, 0xc2, 0xb6, 0xd3, 0xd4, 0x85, 0x4a, 0x7e, 0x58, 0xc3, 0x19, 0xfa, 0xdd, 0x51, 0x03, 0x85, 0x1d, 0xe9, 0x10, 0x5e, 0x8c, 0x8f, 0x41, 0x03, 0xe9, 0xbc, 0xa8, 0xba, 0xeb, 0x73, 0x7d, 0x85, 0x69, 0xc7, 0x3b, 0xd9, 0x49, 0x0b, 0x39, 0x03, 0x12, 0x11, 0x8b, 0x72, 0x97, 0x62, 0x5f, 0xfe, 0x59, 0x4d, 0xc0, 0x3a, 0xdf, 0xcb, 0x3e, 0x80, 0x39, 0xd5, 0x7a, 0xb1, 0x45, 0x86, 0x06, 0xf6, 0xb6, 0xda, 0x98, 0xa1, 0x41, 0xae, 0x12, 0xd3, 0xd1, 0x71, 0x5a, 0xa5, 0x40, 0xc0, 0x8a, 0x3f, 0x4e, 0xac, 0x78, 0x93, 0x55, 0x31, 0xfc, 0xcf, 0x67, 0x93, 0x52, 0xc4, 0x53, 0x0d, 0xdf, 0x49, 0xd7, 0x83, 0x00, 0x18, 0x4b, 0xcd, 0x65, 0xaf, 0xb5, 0xd5, 0x6c, 0xc4, 0x14, 0xb7, 0xdb, 0x9d, 0x06, 0x17, 0xca, 0xe1, 0x60, 0x07, 0x6d, 0x57, 0xd0, 0xfb, 0x1a, 0xf5, 0xb2, 0x56, 0xca, 0xea, 0x21, 0x77, 0x41, 0xc0, 0x46, 0xc8, 0x85, 0xe3, 0x15, 0x6a, 0xdb, 0x80, 0x47, 0x6d, 0x05, 0x44, 0x06, 0x04, 0xf6, 0x92, 0x24, 0xdb, 0x9b, 0x6f, 0xfa, 0x8d, 0x72, 0x2d, 0x75, 0x7e, 0x33, 0x9c, 0xe7, 0x06, 0xbb, 0x3d, 0xa4, 0xb7, 0xee, 0x31, 0x46, 0x4b, 0x91, 0xe2, 0xb0, 0x54, 0x5c, 0x78, 0x9e, 0x45, 0x90, 0xe4, 0x76, 0xbe, 0xe1, 0x4c, 0xae, 0x89, 0x20, 0x6e, 0x77, 0x76, 0x94, 0x63, 0x93, 0xaa, 0x62, 0x0e, 0x28, 0x7b, 0xec, 0xc9, 0xc5, 0x25, 0x64, 0x5a, 0xe9, 0xcc, 0x91, 0x1a, 0x9c, 0xcf, 0x91, 0x47, 0x32, 0x12, 0x9f, 0x8b, 0x36, 0x07, 0x33, 0x4c, 0x45, 0x06, 0x19, 0xdb, 0x61, 0xc5, 0x68, 0xb7, 0xab, 0x2e, 0x7b, 0x5c, 0xa6, 0x4c, 0x6e, 0x08, 0x5f, 0xc1, 0xc4, 0x99, 0x64, 0xef, 0xd8, 0x05, 0x5c, 0x0f, 0x76, 0xdd, 0xab, 0x4f, 0x8e, 0x29, 0x54, 0x59, 0x1d, 0x30, 0x33, 0xfb, 0x3b, 0x43, 0x96, 0xf4, 0x52, 0x47, 0x2c, 0x66, 0x81, 0xca, 0xa6, 0x73, 0x51, 0xc1, 0xc0, 0x32, 0x98, 0xa3, 0x41, 0x1c, 0x40, 0x5e, 0x22, 0x05, 0xa0, 0xdb, 0xb0, 0x88, 0xdf, 0xee, 0x2f, 0x3a, 0xbb, 0xe2, 0xef, 0x79, 0x09, 0xa6, 0x0c, 0x0f, 0x4c, 0xdc, 0x81, 0xcc, 0x3d, 0x36, 0x52, 0x4e, 0xbd, 0x44, 0x0d, 0x0d, 0x84, 0xf5, 0x74, 0x33, 0x14, 0x1a, 0x87, 0xcb, 0xcc, 0x93, 0xa3, 0x69, 0x21, 0x20, 0x26, 0x23, 0xd9, 0x95, 0x0c, 0x22, 0x2b, 0x2f, 0x0d, 0xf4, 0x34, 0x74, 0x53, 0x16, 0x5d, 0x60, 0x96, 0x3e, 0x53, 0xd3, 0xcc, 0xc5, 0x72, 0x49, 0xc2, 0x4d, 0xea, 0x02, 0x21, 0x7f, 0xbd, 0x80, 0x1d, 0xf0, 0x87, 0xe6, 0xdb, 0xcc, 0x92, 0xdd, 0xfe, 0x78, 0x4a, 0xd2, 0xf9, 0x77, 0x24, 0xed, 0x5a, 0x31, 0x6c, 0xec, 0x71, 0x5d, 0x85, 0xad, 0xb3, 0xb9, 0x6f, 0x11, 0x2d, 0xfa, 0x42, 0x2b, 0xcb, 0x01, 0x08, 0x18, 0x11, 0x56, 0xcb, 0x01, 0xe1, 0xe0, 0x1f, 0x06, 0xe8, 0x3c, 0x6c, 0x01, 0xaa, 0x49, 0x86, 0xbf, 0x63, 0x79, 0x03, 0xbe, 0xd8, 0x47, 0x4f, 0x26, 0x0d, 0x11, 0xe3, 0x76, 0x27, 0x0e, 0xf1, 0x79, 0x44, 0x46, 0xc3, 0x3b, 0x4f, 0x05, 0x20, 0x40, 0xff, 0x59, 0x6f, 0xaa, 0x17, 0xf4, 0x40, 0xa1, 0x15, 0x0a, 0x4c, 0x0f, 0x94, 0x81, 0xb8, 0x0c, 0x8e, 0x8d, 0xc3, 0x80, 0xc1, 0xeb, 0x02, 0x16, 0xf4, 0xbe, 0xca, 0xa4, 0x3a, 0xa8, 0xec, 0x0c, 0x89, 0xc4, 0x59, 0xe4, 0x8b, 0x9a, 0x40, 0x7e, 0xae, 0xea, 0xa0, 0xeb, 0x6a, 0x99, 0x95, 0x73, 0x79, 0x62, 0x18, 0xb8, 0x38, 0x64, 0x73, 0x97, 0xb7, 0x58, 0xd1, 0x2d, 0x8d, 0xbe, 0xf3, 0x13, 0x2f, 0x7c, 0xc0, 0x1d, 0x61, 0x4e, 0x4c, 0xe6, 0x95, 0xce, 0x97, 0xf9, 0xbc, 0xf4, 0x5a, 0xce, 0xa1, 0x3b, 0x39, 0xef, 0xc5, 0x39, 0x4b, 0x72, 0x1b, 0xa5, 0x41, 0x92, 0x27, 0xda, 0x72, 0xc2, 0xbb, 0xd4, 0x8d, 0x34, 0x97, 0x9d, 0xb7, 0xde, 0xe7, 0xb0, 0x64, 0x8a, 0x0a, 0x0c, 0x0e, 0x60, 0x30, 0x62, 0xb8, 0xbb, 0x9f, 0x96, 0x05, 0x31, 0x33, 0xfa, 0x3c, 0x1f, 0xf4, 0x3d, 0x04, 0x3c, 0x5c, 0x1e, 0x1b, 0xfe, 0xf1, 0xfe, 0xa1, 0xb1, 0x03, 0x54, 0x99, 0x50, 0x61, 0xc5, 0xbc, 0x2d, 0x00, 0xfe, 0xaf, 0x01, 0xe1, 0x7f, 0xeb, 0xd4, 0x77, 0x0d, 0xb4, 0x0a, 0x9c, 0x18, 0x92, 0x3d, 0x5a, 0xbf, 0xc0, 0x98, 0x66, 0xcc, 0x06, 0x09, 0x6a, 0x50, 0xe9, 0x18, 0x32, 0x00, 0x78, 0xc8, 0x06, 0x68, 0xac, 0x8b, 0x3f, 0x38, 0xbf, 0x4a, 0x33, 0x30, 0x1c, 0x4f, 0xae, 0x16, 0x44, 0x98, 0x24, 0x08, 0xc9, 0x07, 0xed, 0x62, 0xbb, 0x89, 0x15, 0xca, 0x0f, 0x09, 0x00, 0x7a, 0x51, 0xc5, 0x93, 0x54, 0x45, 0xfb, 0x73, 0xdf, 0xe9, 0x42, 0x07, 0x90, 0x10, 0xcb, 0xdb, 0x2b, 0x47, 0x20, 0x2b, 0xaa, 0xf4, 0x5c, 0xa4, 0x28, 0x38, 0x9d, 0x5a, 0x44, 0x22, 0x0d, 0x54, 0x81, 0x1d, 0x07, 0x0a, 0x37, 0xee, 0x49, 0x8b, 0xfb, 0x3a, 0x8d, 0x7e, 0x83, 0x84, 0xfd, 0xf7, 0x98, 0xad, 0xac, 0xa7, 0x46, 0x07, 0x62, 0x72, 0x56, 0x1c, 0x03, 0x05, 0x4d, 0x70, 0xd8, 0x60, 0x62, 0x8a, 0x8d, 0xe8, 0x23, 0x03, 0x04, 0x6d, 0x60, 0xdc, 0x2a, 0x27, 0x92, 0x08, 0x8f, 0x65, 0xed, 0xbd, 0xca, 0xa5, 0x1d, 0x80, 0x8d, 0x11, 0x03, 0x83, 0xc7, 0x05, 0x04, 0x85, 0xcd, 0x2f, 0x3a, 0xd4, 0x83, 0x02, 0x91, 0x91, 0xc5, 0x76, 0xb5, 0x79, 0xcb, 0xfb, 0x29, 0x22, 0x90, 0x1e, 0x09, 0x9f, 0x2c, 0x07, 0x77, 0xa0, 0x38, 0xf8, 0x63, 0xf5, 0x2a, 0xd4, 0xc5, 0x0f, 0xd7, 0x43, 0x38, 0xb5, 0xe8, 0x38, 0x94, 0x29, 0x71, 0x68, 0xb4, 0x99, 0x0a, 0x4d, 0xf6, 0x94, 0x9d, 0x8e, 0x96, 0x58, 0x88, 0x63, 0x46, 0x02, 0x9d, 0x64, 0x83, 0x70, 0x72, 0x32, 0x6f, 0x90, 0x1d, 0x0e, 0xd5, 0xf5, 0xd9, 0x0d, 0xe8, 0x0f, 0xa3, 0x20, 0x5f, 0x26, 0x59, 0xc3, 0x50, 0x33, 0x04, 0xc9, 0x0c, 0xc8, 0xa2, 0xce, 0x12, 0x43, 0x44, 0xa3, 0x55, 0xe5, 0x07, 0x05, 0x1a, 0x69, 0xa8, 0xc4, 0x39, 0x92, 0xa2, 0x44, 0x0e, 0x08, 0xe0, 0xa2, 0x4a, 0x28, 0xd7, 0x80, 0xe1, 0x37, 0x96, 0x0c, 0x49, 0x28, 0x0f, 0x3c, 0xc8, 0xe2, 0xc1, 0x5d, 0x4f, 0xd4, 0x48, 0xa2, 0x21, 0x59, 0xf1, 0x0d, 0x9f, 0xaa, 0xc6, 0x77, 0xc8, 0xe5, 0xce, 0x0d, 0xca, 0x02, 0x87, 0x4a, 0x49, 0x01, 0xc8, 0x48, 0xc8, 0xf3, 0x1b, 0x2f, 0xdf, 0x6c, 0xcb, 0x88, 0x66, 0xf1, 0x40, 0xbd, 0x6a, 0x34, 0xfc, 0xb0, 0x89, 0xde, 0x11, 0xc5, 0xc6, 0xa2, 0x44, 0xc6, 0xdb, 0x67, 0xff, 0xd1, 0x79, 0x01, 0xa4, 0x9e, 0xf0, 0x1f, 0x10, 0x57, 0x2b, 0x24, 0xc5, 0x1c, 0x09, 0x45, 0x7e, 0xcc, 0x55, 0xe5, 0x0d, 0x64, 0xe2, 0x2c, 0xe4, 0xea, 0xe4, 0x81, 0x31, 0xfd, 0x61, 0x38, 0x8f, 0xba, 0x1f, 0xb4, 0xd9, 0x6c, 0xa8, 0xac, 0xe4, 0xe8, 0xca, 0x9e, 0xee, 0xa9, 0x51, 0xd7, 0xe9, 0x9d, 0xcc, 0xb0, 0x7c, 0x24, 0xc5, 0x13, 0xa0, 0x89, 0x78, 0x0b, 0x15, 0xd1, 0x09, 0xe4, 0xbf, 0x34, 0x6f, 0xcf, 0x0b, 0x82, 0x51, 0xb3, 0x70, 0x7d, 0x83, 0xe1, 0x24, 0x0d, 0x33, 0xad, 0xda, 0x5d, 0xfe, 0xe7, 0x38, 0x54, 0x52, 0x0e, 0x3d, 0xd5, 0xec, 0xef, 0x0b, 0x05, 0xe1, 0x16, 0xa9, 0x45, 0xec, 0x5f, 0x81, 0xb9, 0xc8, 0xff, 0x36, 0x0e, 0x0e, 0x01, 0x81, 0x31, 0xae, 0x4b, 0x35, 0xd8, 0x18, 0x17, 0x8c, 0x33, 0x7a, 0xa2, 0xee, 0x06, 0x5b, 0xd8, 0x0b, 0x07, 0xb0, 0x52, 0xbe, 0xf6, 0xf4, 0x38, 0xec, 0x35, 0x6e, 0x45, 0xc1, 0x5e, 0x51, 0xd3, 0x67, 0x93, 0x6d, 0xaf, 0xd0, 0xe0, 0x2a, 0xea, 0x6a, 0x1e, 0x03, 0x0c, 0x38, 0xa4, 0x38, 0xea, 0x34, 0x41, 0x99, 0xcb, 0xe0, 0xcd, 0xda, 0xf2, 0xee, 0x86, 0x28, 0x83, 0x38, 0x0b, 0x13, 0xd1, 0x73, 0x1e, 0x4f, 0xb5, 0x18, 0x7d, 0xef, 0xed, 0x09, 0xdf, 0xf7, 0x4a, 0x91, 0xdb, 0x41, 0x84, 0xf7, 0x07, 0x14, 0x15, 0x3b, 0x01, 0xc5, 0x28, 0x41, 0x78, 0x9f, 0xf6, 0x92, 0xce, 0x06, 0xe0, 0xb9, 0x9d, 0xa0, 0xee, 0xf0, 0x25, 0xa9, 0xd4, 0xe0, 0x71, 0xb4, 0x66, 0x0c, 0x11, 0x47, 0x01, 0x89, 0x34, 0x62, 0x11, 0x60, 0x27, 0xa0, 0xfb, 0x1f, 0xfe, 0xd1, 0x50, 0x6e, 0x0e, 0x23, 0xc3, 0xd8, 0x0e, 0xe8, 0x53, 0xa7, 0x94, 0x03, 0x12, 0x41, 0x9a, 0x90, 0x97, 0xce, 0x87, 0x0d, 0x42, 0x9d, 0x07, 0xce, 0xff, 0xef, 0x4e, 0x07, 0x1a, 0x31, 0x08, 0x92, 0x98, 0x0c, 0x49, 0x46, 0x74, 0x22, 0x2a, 0xf1, 0x01, 0x51, 0x48, 0x26, 0xe9, 0xf5, 0xcd, 0xb0, 0x0c, 0x2e, 0xa1, 0x3d, 0x29, 0x05, 0x4f, 0xa0, 0x12, 0x06, 0x08, 0x9c, 0x94, 0x08, 0x60, 0xce, 0xd0, 0x96, 0x81, 0x81, 0x18, 0x62, 0x03, 0xcc, 0xba, 0x15, 0xd6, 0x91, 0x11, 0x14, 0x7e, 0xb2, 0x7e, 0xd4, 0x56, 0x74, 0x37, 0xdc, 0x82, 0xfb, 0x21, 0xa1, 0x93, 0x91, 0x60, 0x3d, 0xcb, 0x28, 0x4b, 0x52, 0xe9, 0x26, 0x4a, 0x0c, 0x32, 0xca, 0x31, 0xab, 0x10, 0x19, 0x6e, 0x76, 0x50, 0x1e, 0x7c, 0x89, 0x2f, 0x42, 0x4a, 0x46, 0xf8, 0xb1, 0x5e, 0xdc, 0xbe, 0x81, 0x4a, 0x0c, 0x4e, 0x6a, 0x31, 0x70, 0xd4, 0x17, 0x62, 0x30, 0xf8, 0xbb, 0xaa, 0xba, 0x06, 0x98, 0xf4, 0x05, 0x40, 0x7c, 0x8e, 0x81, 0x22, 0xc7, 0x8b, 0xf2, 0x67, 0x49, 0x64, 0x58, 0x1c, 0xb8, 0xa0, 0x6d, 0xb9, 0xea, 0x5b, 0x11, 0x47, 0x18, 0xe7, 0xd0, 0xbc, 0xce, 0xf3, 0x9d, 0x19, 0x10, 0x92, 0x95, 0x45, 0x47, 0x78, 0x87, 0x81, 0x32, 0x6b, 0xc0, 0xe5, 0x7a, 0x79, 0x25, 0x37, 0x0d, 0x05, 0x06, 0x73, 0x39, 0x50, 0x9f, 0x8f, 0x5d, 0x09, 0x24, 0x34, 0x32, 0x18, 0x04, 0x62, 0x9c, 0xe8, 0x1e, 0x06, 0x52, 0x88, 0x1e, 0x26, 0x01, 0x30, 0x36, 0x81, 0x60, 0x63, 0x41, 0x6a, 0x77, 0xa8, 0x42, 0xd4, 0xba, 0x1f, 0x0e, 0x79, 0x06, 0x2d, 0x16, 0x83, 0x00, 0xe3, 0xe6, 0xcb, 0xba, 0x82, 0x4a, 0x27, 0xd7, 0x5e, 0xdc, 0x58, 0x44, 0x19, 0x28, 0x0c, 0xc7, 0x2f, 0x57, 0xb2, 0x83, 0x83, 0x40, 0xcc, 0x1c, 0xb8, 0x99, 0x41, 0xb9, 0xb0, 0xc8, 0x1f, 0x36, 0x00, 0x75, 0x14, 0xa9, 0x25, 0x34, 0x87, 0x83, 0x05, 0x13, 0x16, 0x7d, 0x91, 0x40, 0x3b, 0x9c, 0xe8, 0x38, 0x57, 0x17, 0xd2, 0x03, 0xc0, 0xff, 0x4e, 0x0c, 0x1f, 0x16, 0x96, 0xc0, 0xe3, 0x8d, 0x62, 0x75, 0xb8, 0x04, 0xae, 0x03, 0x80, 0x88, 0xa1, 0x56, 0x31, 0x57, 0x66, 0x2d, 0x8a, 0xef, 0x11, 0x6f, 0xca, 0xe9, 0x47, 0x79, 0xd0, 0x9d, 0x0c, 0xb0, 0x18, 0x47, 0x06, 0x03, 0x57, 0x2c, 0xda, 0x8f, 0x4a, 0x80, 0xd9, 0xa0, 0x62, 0x80, 0x60, 0x4d, 0x95, 0x18, 0x8c, 0x18, 0x45, 0xcb, 0x17, 0xad, 0x34, 0xa3, 0xd2, 0xa1, 0xb5, 0xd3, 0x32, 0xd9, 0xdb, 0xd1, 0x82, 0x98, 0x18, 0x83, 0xa9, 0xcd, 0xb5, 0x20, 0x77, 0x03, 0x5c, 0x5f, 0xa6, 0xdb, 0x48, 0x12, 0xd7, 0x46, 0xc8, 0xd1, 0x78, 0x1c, 0x1d, 0x17, 0x04, 0x91, 0xe8, 0xbc, 0x2a, 0xa0, 0x53, 0x83, 0x11, 0x29, 0xff, 0x18, 0xfe, 0x8d, 0x98, 0x6e, 0xad, 0x11, 0x65, 0xa0, 0xc8, 0x3c, 0x48, 0x48, 0x13, 0x55, 0x28, 0xf5, 0x61, 0x9d, 0xe0, 0x38, 0x5e, 0x12, 0xc0, 0x70, 0x44, 0xbf, 0x6f, 0x25, 0x9d, 0x2b, 0xcf, 0xb6, 0x79, 0x3d, 0xcf, 0x45, 0x32, 0xa8, 0x19, 0x67, 0x3a, 0x14, 0x43, 0x6d, 0x7d, 0xa1, 0x04, 0xb7, 0x3e, 0xd3, 0x75, 0x45, 0x2a, 0x6a, 0x6d, 0xb2, 0x12, 0x87, 0x90, 0xa0, 0x6b, 0xbf, 0x1a, 0x5b, 0xb7, 0x14, 0xd0, 0x26, 0x88, 0x5e, 0xb8, 0x4d, 0x70, 0x19, 0x65, 0x36, 0xdd, 0x9c, 0x40, 0x7a, 0xbf, 0x21, 0xc8, 0x38, 0x38, 0x01, 0xca, 0x1e, 0xc5, 0xee, 0xb3, 0x40, 0xc0, 0x9a, 0xd6, 0x24, 0xa7, 0xb4, 0x6b, 0x06, 0x18, 0xfc, 0x1c, 0x11, 0xaf, 0x6d, 0xcc, 0xbd, 0x5e, 0xc8, 0x8e, 0x07, 0xbc, 0xe0, 0x52, 0x8f, 0x9a, 0xb1, 0x74, 0x40, 0xe4, 0x63, 0x20, 0x99, 0x4f, 0xa8, 0xbc, 0x0e, 0xf2, 0x86, 0x80, 0xea, 0x09, 0x8a, 0xec, 0xdd, 0xe7, 0x39, 0x49, 0x6e, 0xc4, 0x5c, 0x5d, 0x0d, 0x45, 0xd1, 0x7b, 0x8b, 0xd5, 0xaf, 0x43, 0x17, 0xe9, 0x49, 0xac, 0x6d, 0x10, 0xa6, 0x4e, 0x5e, 0xa8, 0xc8, 0x20, 0xca, 0x54, 0x8e, 0xa1, 0x15, 0xb5, 0x0d, 0xa0, 0x66, 0x70, 0x93, 0x6f, 0x01, 0xc4, 0x2b, 0xc1, 0x46, 0xbd, 0x74, 0x96, 0x05, 0x75, 0x50, 0xc0, 0xc3, 0x8b, 0x22, 0x25, 0x07, 0x1d, 0xf6, 0x70, 0x92, 0x2d, 0x17, 0x09, 0xcb, 0xef, 0xbd, 0x88, 0xd6, 0x46, 0x7b, 0xbd, 0xa0, 0xe7, 0xe9, 0xc7, 0x09, 0x01, 0xc0, 0xb1, 0x29, 0x3a, 0xc1, 0xdd, 0x05, 0xd2, 0x6a, 0x60, 0x73, 0x06, 0x54, 0x26, 0x84, 0x0b, 0x22, 0x42, 0x7e, 0x0d, 0x62, 0xfe, 0xc5, 0xb8, 0x30, 0x3a, 0xa2, 0x5f, 0x5b, 0xee, 0x6c, 0xc2, 0x50, 0x7a, 0x18, 0x00, 0xdf, 0x86, 0x41, 0x97, 0x16, 0x3d, 0xd9, 0xcb, 0x09, 0x46, 0x40, 0xb0, 0x04, 0xe5, 0xa0, 0xbb, 0xa9, 0x8d, 0x84, 0xa6, 0xd4, 0xb7, 0x53, 0xb2, 0xdf, 0x33, 0x16, 0x41, 0x38, 0x2f, 0x3c, 0xa8, 0x21, 0xef, 0x3e, 0xd6, 0xcd, 0x8b, 0xf9, 0x1f, 0x03, 0x7a, 0x29, 0x18, 0x84, 0x26, 0x7f, 0xe1, 0xdf, 0x98, 0x1c, 0x36, 0x58, 0xdc, 0x51, 0xde, 0x2d, 0x35, 0x1f, 0x69, 0xa7, 0x0a, 0x82, 0x08, 0xe9, 0x59, 0x7f, 0x2b, 0x4a, 0x39, 0x25, 0x96, 0x5f, 0xf1, 0x08, 0xa6, 0x5b, 0x4b, 0x67, 0x51, 0x12, 0xf0, 0xf2, 0xae, 0x68, 0xbb, 0x72, 0xef, 0x0a, 0xb6, 0x02, 0xbd, 0x14, 0x42, 0x37, 0x1b, 0x80, 0xe2, 0x3a, 0xb7, 0xb4, 0x1c, 0x0a, 0x9b, 0xa0, 0xea, 0x11, 0x21, 0x4b, 0x07, 0xc9, 0x93, 0xb7, 0x7b, 0xd1, 0x13, 0x8d, 0x62, 0xfd, 0x28, 0xbd, 0x44, 0x0e, 0x0f, 0x4e, 0x49, 0xb4, 0x43, 0x11, 0xc0, 0x38, 0x38, 0x08, 0xd2, 0xd9, 0x2e, 0x2c, 0x03, 0x9f, 0xa7, 0xd6, 0x37, 0x46, 0x01, 0x1f, 0x58, 0x56, 0xc0, 0x9c, 0x07, 0x0c, 0x9d, 0xba, 0x0a, 0x9a, 0x15, 0xd4, 0x63, 0x6a, 0x13, 0x69, 0xe0, 0x6f, 0x4c, 0xd0, 0x53, 0xc0, 0xf6, 0x6f, 0x3c, 0xb7, 0x7d, 0xcb, 0x3b, 0x40, 0x8e, 0xfa, 0x04, 0x48, 0x16, 0x35, 0x8b, 0x7d, 0xbc, 0x81, 0xaa, 0xb2, 0xe8, 0xbf, 0x7a, 0x0c, 0x1c, 0xfe, 0x86, 0x26, 0x8e, 0x86, 0x25, 0x83, 0x9d, 0x07, 0x11, 0xcf, 0xb8, 0x5b, 0x88, 0xe9, 0x5e, 0x12, 0x21, 0x13, 0xed, 0xb1, 0xfa, 0x0c, 0x87, 0xf0, 0xa3, 0x96, 0x05, 0x75, 0x33, 0x7a, 0x3d, 0x1f, 0x09, 0x49, 0x58, 0x56, 0x9d, 0x95, 0x5e, 0x52, 0x9b, 0x30, 0x3d, 0x64, 0x3d, 0xe4, 0xde, 0xcb, 0x3c, 0x59, 0x56, 0x0d, 0xd4, 0x94, 0x43, 0xf6, 0x24, 0xb7, 0x19, 0x1f, 0xa5, 0x6f, 0xd7, 0xc5, 0x9f, 0x56, 0xde, 0xe7, 0x38, 0x8a, 0xed, 0x3c, 0x15, 0xc1, 0x9b, 0x6b, 0x55, 0xab, 0x11, 0xa4, 0xce, 0xef, 0xd2, 0x4c, 0x88, 0x00, 0xad, 0x15, 0x18, 0xff, 0xb5, 0xad, 0xdf, 0x6f, 0xa4, 0xdc, 0xbc, 0xab, 0x84, 0x65, 0x30, 0xab, 0x09, 0x6b, 0xf4, 0xff, 0x43, 0x78, 0x30, 0x08, 0xa7, 0xa0, 0xa9, 0xa2, 0xf0, 0x8b, 0x72, 0x82, 0xa0, 0x5c, 0x12, 0xb0, 0x27, 0xe1, 0x84, 0x09, 0x27, 0x6e, 0x2d, 0x62, 0xc6, 0xd1, 0x85, 0x1a, 0x72, 0xb1, 0xbf, 0x83, 0xcc, 0x7f, 0xfa, 0x13, 0x54, 0xe0, 0x71, 0xfa, 0x0e, 0x23, 0x7d, 0x06, 0x25, 0x18, 0x4a, 0x11, 0x69, 0x43, 0x76, 0xe8, 0xc8, 0x18, 0x23, 0x96, 0x15, 0x2c, 0x7f, 0x4e, 0x8b, 0x01, 0x83, 0x6d, 0x18, 0x83, 0x04, 0x5b, 0x80, 0xa8, 0xc1, 0x9d, 0x01, 0xfa, 0xe2, 0xa3, 0x8d, 0x4f, 0xe9, 0x63, 0x0d, 0xfe, 0xe7, 0x7b, 0xcc, 0x5e, 0x86, 0xf5, 0x1b, 0xae, 0x0e, 0x93, 0xa0, 0x1f, 0x36, 0x33, 0xe8, 0x0e, 0x74, 0xcf, 0xa0, 0x43, 0x11, 0x82, 0x6d, 0x5a, 0xa8, 0xa6, 0x1a, 0xcb, 0xa1, 0xb4, 0x99, 0x6a, 0x08, 0x8f, 0x68, 0x30, 0x2c, 0x5f, 0x51, 0xfd, 0x10, 0x1a, 0xff, 0xd6, 0xec, 0xe7, 0x7a, 0xc7, 0xaf, 0x49, 0x16, 0xbb, 0x51, 0x50, 0xad, 0xbf, 0x8b, 0x76, 0x86, 0x20, 0x9b, 0x11, 0x81, 0xc5, 0x1b, 0x6f, 0x06, 0xdf, 0xfc, 0x28, 0xda, 0xe9, 0x03, 0x6a, 0xc1, 0x83, 0x96, 0xc1, 0x86, 0x3a, 0x12, 0xd2, 0x8a, 0x8c, 0x83, 0x85, 0xd0, 0xa0, 0xf3, 0x2e, 0x86, 0xee, 0xe1, 0xb7, 0xa1, 0x6d, 0x16, 0x2e, 0xf4, 0x46, 0xc1, 0x45, 0x99, 0xd2, 0x6d, 0x72, 0xd2, 0xe6, 0x52, 0x84, 0x07, 0x84, 0xf3, 0xc0, 0xe0, 0x0e, 0xa2, 0x1f, 0x6c, 0xce, 0xf6, 0x83, 0xc1, 0xc0, 0x3f, 0x47, 0xb9, 0x68, 0xc8, 0x11, 0x04, 0x14, 0x40, 0xc3, 0x43, 0x13, 0xa0, 0xf3, 0xff, 0xff, 0xbe, 0xfe, 0x58, 0xd4, 0x51, 0x7b, 0x0a, 0x01, 0x62, 0x48, 0xe1, 0x9b, 0x6b, 0x65, 0x8b, 0x54, 0x41, 0xc8, 0x9d, 0x57, 0x57, 0x64, 0xf7, 0x51, 0x83, 0x0c, 0x47, 0x25, 0x01, 0xc8, 0xad, 0x4a, 0x58, 0x4b, 0x05, 0xe0, 0xc0, 0x3d, 0x10, 0x4e, 0xb5, 0x85, 0xb8, 0xbc, 0xb0, 0x1e, 0x2a, 0x00, 0xb0, 0x58, 0xbd, 0x5e, 0xca, 0x4a, 0x0c, 0x2e, 0x19, 0x82, 0xe5, 0x3e, 0x8b, 0xa0, 0xe0, 0xc8, 0x8a, 0xae, 0xe7, 0xbe, 0x55, 0xbc, 0x45, 0x4a, 0x60, 0x60, 0x09, 0xcb, 0x89, 0x4c, 0x32, 0x08, 0x6d, 0x09, 0x0d, 0xb4, 0xd2, 0x54, 0xf8, 0xa8, 0xab, 0xca, 0x6f, 0xc4, 0xbf, 0x00, 0xe6, 0xb6, 0x8c, 0x4f, 0xc6, 0x16, 0xf7, 0x67, 0x1a, 0x9b, 0x2a, 0x1c, 0xe0, 0x0e, 0x44, 0x80, 0x80, 0x34, 0xb2, 0x9d, 0x59, 0x58, 0x17, 0xd1, 0x87, 0x81, 0x60, 0x2c, 0xf8, 0x0a, 0xad, 0x69, 0x49, 0x5d, 0x40, 0x43, 0x1b, 0x4e, 0x83, 0x7c, 0x48, 0x88, 0x92, 0x09, 0x3f, 0x05, 0x78, 0xf6, 0xc0, 0x60, 0xc9, 0xea, 0xd0, 0x66, 0xd3, 0x20, 0x08, 0x5b, 0xa0, 0xaf, 0x1d, 0xb3, 0xa1, 0x35, 0x2e, 0x1c, 0xc8, 0x33, 0x09, 0x1a, 0x34, 0x6d, 0x83, 0x06, 0x61, 0x21, 0x5a, 0x99, 0x57, 0xd1, 0xcc, 0xa2, 0x96, 0xed, 0x05, 0xc3, 0x61, 0x84, 0x1e, 0x07, 0xfc, 0x3e, 0x55, 0x2d, 0x01, 0xe4, 0x92, 0xc4, 0x56, 0xd6, 0xff, 0xc0, 0xa0, 0x6a, 0x23, 0x89, 0x29, 0xc4, 0x76, 0x43, 0xf6, 0x7c, 0xd6, 0x55, 0x0a, 0x0a, 0xb1, 0x00, 0x13, 0xaf, 0xa2, 0xa0, 0xe4, 0x5c, 0x11, 0xb2, 0xa2, 0x51, 0x80, 0x46, 0x98, 0xc3, 0x1e, 0x1b, 0x35, 0xc2, 0x5c, 0xb5, 0xf4, 0xfb, 0xf2, 0x1c, 0x83, 0x83, 0x80, 0x7c, 0xf8, 0x01, 0xfd, 0x9a, 0x85, 0x49, 0x69, 0xc7, 0xd8, 0x1a, 0xc3, 0x0f, 0xa3, 0x27, 0xb5, 0xa6, 0xc5, 0xdb, 0x3a, 0x15, 0x6e, 0x5e, 0xdb, 0x93, 0x60, 0x8b, 0x28, 0x31, 0x48, 0xc0, 0x35, 0x09, 0x3b, 0x5f, 0x28, 0x18, 0x54, 0x01, 0x80, 0x66, 0x8c, 0x8e, 0x7e, 0xd6, 0xaa, 0x8d, 0xa9, 0x9c, 0xa6, 0xe3, 0x10, 0xb6, 0x8c, 0x16, 0xd0, 0x97, 0x4f, 0x78, 0x15, 0x21, 0x88, 0xb8, 0x85, 0xb9, 0x01, 0xd1, 0x67, 0x69, 0xfd, 0xbe, 0xe4, 0x52, 0xd6, 0xc4, 0x6a, 0x24, 0x07, 0x54, 0x28, 0x08, 0xa6, 0x6f, 0x94, 0x03, 0x22, 0xf8, 0x67, 0x46, 0x20, 0x9a, 0x4c, 0x93, 0x90, 0x1c, 0x09, 0x90, 0x32, 0x46, 0x32, 0x0a, 0x2d, 0xe8, 0x27, 0xc5, 0xdc, 0xf6, 0xc9, 0xde, 0x4e, 0x1a, 0x45, 0x02, 0x5b, 0xab, 0xeb, 0x4a, 0x2f, 0x4d, 0x95, 0x29, 0xe8, 0x0f, 0x04, 0xcc, 0xb8, 0xbc, 0x6b, 0x32, 0x06, 0x08, 0x0d, 0xc0, 0x5f, 0xdb, 0x24, 0x46, 0xb1, 0xbe, 0x85, 0x5a, 0xeb, 0x4a, 0xa0, 0x40, 0x42, 0x48, 0x59, 0x37, 0xbd, 0x18, 0x82, 0x72, 0x63, 0xfd, 0xa5, 0x12, 0x83, 0x90, 0x85, 0x1e, 0xd5, 0x83, 0x35, 0xe0, 0xb9, 0x02, 0xc7, 0xcd, 0x88, 0x23, 0x86, 0xe7, 0xc7, 0x12, 0x4b, 0xcd, 0x1c, 0x59, 0x51, 0x29, 0x0c, 0x3b, 0xc9, 0xd0, 0x4d, 0xf9, 0x6a, 0x33, 0xba, 0xef, 0x2e, 0xe5, 0xd8, 0x69, 0x1a, 0x14, 0x44, 0x29, 0xe6, 0xcb, 0xee, 0x7f, 0xd6, 0x9b, 0x25, 0x0c, 0x51, 0x05, 0x48, 0xe4, 0xf9, 0x6a, 0xfd, 0xc9, 0x9d, 0x8b, 0xd9, 0xd1, 0x3a, 0x14, 0x7d, 0xa9, 0x38, 0x5a, 0x55, 0xd4, 0x57, 0x7f, 0xfb, 0x62, 0x11, 0x80, 0x30, 0x61, 0x1d, 0x6a, 0x00, 0x92, 0x2e, 0x9a, 0x7b, 0x82, 0x4a, 0x75, 0x77, 0x3b, 0x61, 0xb6, 0xbe, 0x36, 0xa1, 0x87, 0x67, 0x46, 0x0f, 0x30, 0xaf, 0x70, 0xbd, 0x8d, 0xc8, 0x31, 0x53, 0x37, 0xc0, 0xc1, 0x8c, 0x15, 0x1d, 0x4d, 0x38, 0xb5, 0x5c, 0x1c, 0x0b, 0xc1, 0x53, 0x17, 0xe0, 0x75, 0xb6, 0x68, 0x19, 0x9d, 0x2b, 0xf4, 0xe2, 0x09, 0x41, 0x30, 0xbe, 0xd0, 0xf7, 0xb2, 0x2c, 0x69, 0xd1, 0x33, 0x83, 0xa6, 0x59, 0x66, 0x17, 0xcb, 0x59, 0x6c, 0x18, 0x0c, 0x27, 0x1b, 0xfe, 0xd4, 0x72, 0xac, 0x75, 0x25, 0x65, 0xca, 0xfa, 0x0c, 0x05, 0xac, 0x29, 0x06, 0x04, 0xe1, 0x78, 0xe8, 0x79, 0x4a, 0xf2, 0xa9, 0xe6, 0xfb, 0xf1, 0x0e, 0x7e, 0xcd, 0x95, 0x6c, 0xed, 0x5a, 0x9a, 0xa6, 0xc5, 0x01, 0x4d, 0x38, 0x36, 0x24, 0x6b, 0xac, 0xe8, 0xf0, 0x77, 0xb9, 0xe9, 0x6f, 0x55, 0x8f, 0x52, 0x48, 0xb2, 0xeb, 0xe6, 0x29, 0xb7, 0xa6, 0xa5, 0x71, 0xbe, 0x57, 0x9e, 0xd0, 0xda, 0xa1, 0xe5, 0x08, 0xaa, 0x65, 0xc1, 0x13, 0xe8, 0x43, 0xef, 0x06, 0xac, 0xf8, 0x1f, 0x37, 0xff, 0xb7, 0x53, 0x7e, 0x65, 0xd9, 0xf4, 0xdf, 0x99, 0xc5, 0x25, 0x9b, 0x9b, 0x5c, 0x71, 0x90, 0x6c, 0x49, 0xbe, 0x55, 0xff, 0x69, 0x70, 0xfa, 0xff, 0xca, 0x7f, 0xe4, 0xe2, 0x4c, 0x42, 0x84, 0x3a, 0x7d, 0xb0, 0x07, 0x07, 0x8c, 0x29, 0x80, 0xc5, 0xa3, 0xc6, 0xee, 0xe1, 0x66, 0xe3, 0x1f, 0xdf, 0xd5, 0x15, 0x08, 0x89, 0x16, 0x3c, 0x30, 0x39, 0xcf, 0xaf, 0x35, 0x10, 0x2a, 0x38, 0x19, 0xbe, 0x26, 0xb8, 0x13, 0x83, 0x00, 0x1c, 0xe4, 0xda, 0xc5, 0x2b, 0xcf, 0xd2, 0xad, 0xc2, 0xa9, 0x37, 0xb7, 0xb5, 0x01, 0x41, 0x0d, 0x40, 0x38, 0x01, 0x9d, 0xe5, 0x12, 0x7f, 0xb4, 0x38, 0x54, 0x5c, 0xdb, 0x7c, 0x02, 0x73, 0x7e, 0x2c, 0x17, 0x2a, 0x1e, 0x09, 0x0a, 0xb3, 0x7c, 0x5d, 0x07, 0xbb, 0xf5, 0xfb, 0xff, 0xa6, 0x9e, 0xef, 0x29, 0xb5, 0x0b, 0x70, 0x6a, 0xa0, 0x6d, 0x01, 0x67, 0xe9, 0x2d, 0x98, 0x72, 0xa6, 0x44, 0x47, 0x12, 0xa2, 0x58, 0x25, 0x2b, 0xdc, 0x67, 0x71, 0xa5, 0x57, 0x0b, 0x15, 0x65, 0xba, 0xa6, 0x07, 0xb3, 0xb6, 0x22, 0x35, 0xde, 0x13, 0x09, 0xda, 0x08, 0x0d, 0xb3, 0xad, 0x83, 0xc1, 0x40, 0x42, 0x3b, 0xb7, 0x22, 0x90, 0xf5, 0xbe, 0x5d, 0xea, 0xcb, 0x01, 0x88, 0xa5, 0x72, 0x60, 0xbe, 0x23, 0x64, 0x6d, 0x57, 0xbb, 0x10, 0x7f, 0x94, 0x41, 0xac, 0x73, 0x84, 0xb1, 0x75, 0xc1, 0x38, 0xeb, 0x25, 0xbe, 0x6e, 0xf4, 0xb9, 0x8f, 0xa9, 0xd5, 0x84, 0x14, 0xad, 0xfe, 0xc3, 0x48, 0x11, 0x52, 0x99, 0x3a, 0x4e, 0x70, 0xe7, 0x65, 0x5a, 0x29, 0x85, 0x2a, 0x02, 0x68, 0x99, 0xaf, 0xaa, 0xfa, 0xad, 0x2c, 0xd1, 0x09, 0x46, 0xc4, 0x0d, 0xfd, 0xba, 0x0c, 0x18, 0x98, 0x6d, 0x97, 0x5a, 0xd3, 0x0d, 0xf9, 0x57, 0xbd, 0x75, 0x4e, 0x7f, 0x3b, 0xd5, 0xf2, 0xa3, 0x9d, 0xde, 0xaf, 0x10, 0x13, 0x97, 0xd5, 0x1c, 0xdb, 0xa3, 0xa2, 0xe9, 0x50, 0x7d, 0x44, 0xdd, 0xe4, 0x0d, 0xea, 0x08, 0x27, 0x33, 0x41, 0xba, 0xd5, 0xda, 0xc4, 0x2c, 0xec, 0xe7, 0x66, 0x35, 0xc9, 0x3b, 0xd9, 0x27, 0x73, 0x83, 0x17, 0x0d, 0x08, 0x3d, 0x35, 0x34, 0xa6, 0x9e, 0xd7, 0xea, 0x84, 0xb2, 0xcf, 0x87, 0x95, 0x94, 0xd5, 0x8b, 0x2e, 0x11, 0x89, 0x02, 0x06, 0x25, 0x6a, 0x46, 0xd5, 0xe5, 0xa5, 0xb9, 0x54, 0x67, 0x22, 0x9d, 0x2b, 0x92, 0xa0, 0x3c, 0x5e, 0xc5, 0x78, 0x38, 0xac, 0xc2, 0xff, 0xe1, 0x57, 0xbc, 0xb2, 0xd5, 0x48, 0xc7, 0x85, 0x10, 0x81, 0x54, 0x89, 0x3d, 0xbb, 0xdc, 0xb8, 0xd8, 0xf5, 0x9c, 0x8c, 0xa7, 0xe9, 0x46, 0x45, 0xd7, 0x40, 0x88, 0x8c, 0xdc, 0x56, 0xdc, 0x46, 0xa3, 0x06, 0xfc, 0xce, 0x91, 0x69, 0x8a, 0x55, 0x02, 0x8b, 0x72, 0xe7, 0xdb, 0x1f, 0xa5, 0x2b, 0x06, 0x40, 0x55, 0x31, 0x45, 0x9d, 0x40, 0xdd, 0x90, 0x54, 0x9a, 0x70, 0x64, 0x89, 0x15, 0xc9, 0xbe, 0x4f, 0xb3, 0x6d, 0xe5, 0x1c, 0xab, 0xc2, 0xc8, 0x30, 0x94, 0xea, 0x5e, 0x54, 0xab, 0x14, 0x7b, 0xfe, 0xce, 0x9b, 0xe6, 0xae, 0x50, 0xa6, 0xe9, 0x18, 0xb6, 0xb1, 0x95, 0x44, 0x53, 0xcf, 0x7b, 0x96, 0x7b, 0x98, 0x59, 0x43, 0x8e, 0x95, 0x0c, 0x21, 0x3b, 0x95, 0xc2, 0xb5, 0xe1, 0x42, 0x80, 0xc0, 0xf6, 0x99, 0xa4, 0xe0, 0x19, 0x83, 0xe1, 0x29, 0x28, 0xf3, 0xd4, 0x72, 0xdb, 0x77, 0xd4, 0x3c, 0xaa, 0x70, 0x3c, 0x45, 0xbd, 0x1b, 0x76, 0xf4, 0x80, 0x30, 0x60, 0x34, 0x12, 0x6f, 0xe2, 0x84, 0x96, 0xaf, 0x36, 0x29, 0xfb, 0x52, 0x73, 0xa8, 0xff, 0x2d, 0xe9, 0xe3, 0x3f, 0xf4, 0xa8, 0xb2, 0xf7, 0x4d, 0x15, 0x45, 0x83, 0x9b, 0x38, 0x33, 0x8b, 0x8a, 0xf0, 0x80, 0xd4, 0x5e, 0x79, 0x7e, 0xf2, 0xd1, 0xb8, 0xbe, 0x2f, 0xb2, 0x94, 0x9e, 0x24, 0x73, 0xfe, 0x02, 0x63, 0x26, 0x79, 0xa4, 0xdd, 0x4a, 0xda, 0x4a, 0xb5, 0xbb, 0x7c, 0x55, 0xdb, 0xee, 0xca, 0x1b, 0x4b, 0xd9, 0xd8, 0x02, 0x0e, 0xfd, 0xaa, 0xd7, 0xee, 0x6c, 0xb3, 0x86, 0xfb, 0x28, 0x56, 0x0c, 0x1a, 0xab, 0xf8, 0x24, 0xb3, 0xf5, 0x51, 0x46, 0xc6, 0x5b, 0xbd, 0x5a, 0xc9, 0x26, 0xd9, 0xb5, 0x75, 0xb9, 0xc3, 0x7c, 0x3c, 0x48, 0x43, 0x08, 0x5a, 0x3f, 0x6f, 0x4b, 0xfb, 0x41, 0x86, 0xc5, 0xad, 0xf1, 0x78, 0xa7, 0x24, 0xce, 0x45, 0xe8, 0xa4, 0x5e, 0x33, 0xcb, 0x3b, 0x39, 0xd4, 0x67, 0x55, 0x72, 0x63, 0xc2, 0xd6, 0x1b, 0x45, 0x29, 0xbb, 0xd8, 0x81, 0x00, 0xcc, 0x63, 0xd3, 0xc5, 0x12, 0x73, 0xfe, 0xf6, 0xde, 0x6e, 0x41, 0x89, 0x5f, 0xaf, 0x65, 0x5a, 0x9b, 0x21, 0x59, 0x5c, 0xc1, 0x0b, 0xc5, 0x7a, 0xbe, 0x28, 0xdf, 0x40, 0xf6, 0x2c, 0x8a, 0xc2, 0xa5, 0x2b, 0x74, 0xf9, 0x3d, 0x63, 0x13, 0xd8, 0x98, 0x71, 0x6f, 0x73, 0xb6, 0x88, 0x0d, 0xb3, 0x66, 0x5a, 0x56, 0x22, 0x77, 0x9b, 0x88, 0x08, 0x64, 0x2d, 0xff, 0x50, 0x42, 0x0d, 0x35, 0x47, 0x1b, 0x93, 0x2d, 0x42, 0x88, 0x50, 0x2f, 0x06, 0xcf, 0x29, 0x4a, 0x3e, 0xa5, 0x5d, 0xc4, 0xea, 0xbb, 0x03, 0xde, 0xf0, 0x73, 0x2f, 0x51, 0xa8, 0x13, 0x11, 0x64, 0x03, 0x14, 0xfb, 0xb3, 0xe1, 0xe2, 0x65, 0x18, 0xcd, 0xd9, 0x51, 0x72, 0xf3, 0x72, 0xd1, 0x12, 0xa3, 0x42, 0x8c, 0x4d, 0x00, 0x79, 0x9f, 0x36, 0x24, 0x8e, 0x95, 0x2a, 0xcc, 0x06, 0x02, 0xea, 0xad, 0x2b, 0xaa, 0x43, 0xcf, 0xe5, 0xd3, 0x4b, 0x2c, 0x4a, 0x34, 0x76, 0xdb, 0x9b, 0x97, 0x80, 0xe1, 0x56, 0xba, 0x6d, 0xe5, 0xf7, 0x40, 0x70, 0x3a, 0x05, 0x91, 0xca, 0x8f, 0x9b, 0xc1, 0x88, 0x2c, 0x0f, 0x0b, 0xb2, 0x50, 0x42, 0x06, 0x2d, 0xbb, 0x98, 0x4b, 0xc6, 0x22, 0x90, 0x78, 0xcf, 0xfd, 0xe6, 0x50, 0x60, 0x9d, 0x16, 0xda, 0xd1, 0xd2, 0x6f, 0xb3, 0xf9, 0x21, 0xab, 0x38, 0xc2, 0x30, 0xd4, 0xb7, 0xea, 0x1d, 0xfa, 0xf6, 0xe7, 0x01, 0xc1, 0xde, 0xc0, 0xb3, 0x4f, 0x03, 0x0f, 0xe7, 0x40, 0x39, 0x3a, 0x3a, 0xbb, 0x08, 0x81, 0x5f, 0x10, 0x10, 0x94, 0x4c, 0x5d, 0x3f, 0x9f, 0xd0, 0x34, 0x9d, 0x3e, 0xad, 0x31, 0x8f, 0x66, 0xf6, 0xf4, 0x45, 0x2a, 0x9b, 0x78, 0xe2, 0x02, 0x3f, 0xbc, 0x3f, 0x2e, 0xfb, 0x01, 0xf8, 0x1a, 0x9b, 0xc0, 0xf6, 0xe5, 0xb5, 0x65, 0xf8, 0xa2, 0xce, 0x3c, 0x23, 0xb4, 0x25, 0x17, 0x2a, 0xb5, 0xa0, 0x60, 0xfd, 0x5f, 0x2f, 0xa5, 0x0f, 0xd5, 0x28, 0x6b, 0xf6, 0xf4, 0x3a, 0xe4, 0xf2, 0x28, 0x8c, 0xd8, 0xac, 0xe4, 0xdf, 0x51, 0x0b, 0x14, 0x6a, 0x32, 0x5e, 0x0b, 0x9d, 0x5f, 0xf8, 0x9d, 0x27, 0xfd, 0x36, 0xfb, 0xfa, 0x59, 0xe0, 0x33, 0xce, 0xf1, 0x63, 0xb6, 0xd9, 0x6f, 0x41, 0xe1, 0x20, 0x15, 0xba, 0x5e, 0x42, 0x57, 0xed, 0x09, 0x1a, 0x59, 0xed, 0x1e, 0x8f, 0x4b, 0xea, 0x56, 0x94, 0x6f, 0x33, 0xba, 0x2f, 0x14, 0x74, 0x9e, 0x08, 0x51, 0x08, 0x8d, 0xbf, 0xf3, 0x7d, 0x57, 0x2a, 0xf1, 0x01, 0xf2, 0x59, 0xd2, 0xd9, 0xce, 0xe4, 0x97, 0xa4, 0xf8, 0x3f, 0x9c, 0x00, 0x6b, 0xa3, 0x1a, 0xfe, 0x82, 0x26, 0xd6, 0x26, 0x67, 0xb6, 0xf2, 0xab, 0xad, 0x7c, 0x3d, 0x9c, 0x06, 0x34, 0xa3, 0x61, 0x55, 0x29, 0x42, 0xe3, 0xac, 0xea, 0x52, 0x4a, 0xc6, 0x1c, 0x32, 0x21, 0xa5, 0x69, 0xbf, 0x7f, 0x1a, 0xc6, 0x04, 0xaa, 0x92, 0x0e, 0x54, 0x79, 0xac, 0xa5, 0xbb, 0xe4, 0x32, 0xc5, 0x2a, 0x38, 0x69, 0x67, 0x91, 0x57, 0xf1, 0xfa, 0xa0, 0xe9, 0xa5, 0x43, 0xea, 0x9e, 0x6c, 0xe4, 0x1b, 0x72, 0xef, 0x1c, 0x5a, 0xac, 0xcc, 0xf7, 0xae, 0x41, 0xcc, 0xa6, 0xcf, 0xaa, 0xe5, 0xd5, 0x77, 0xc1, 0xdc, 0x6e, 0x7f, 0xb9, 0xad, 0x62, 0xe5, 0x56, 0xf0, 0xd3, 0xca, 0x35, 0x1a, 0x55, 0x3f, 0xa0, 0xc1, 0xef, 0x9b, 0x6a, 0x59, 0xba, 0x59, 0x35, 0x6f, 0x72, 0xd3, 0x48, 0x86, 0xa5, 0x41, 0x4e, 0x25, 0xa3, 0x06, 0x0f, 0x55, 0xa6, 0x9b, 0xb3, 0x26, 0x03, 0x8e, 0x2d, 0xe6, 0x75, 0x3b, 0x38, 0xd4, 0xe7, 0xfe, 0xa3, 0xdd, 0xe5, 0xd9, 0x2a, 0x20, 0x71, 0x29, 0x39, 0xec, 0xab, 0xdc, 0xda, 0xa5, 0x47, 0xae, 0x59, 0x05, 0xb5, 0x71, 0x2b, 0x0a, 0x84, 0x25, 0x51, 0x9f, 0xa9, 0x6d, 0x2f, 0x9b, 0x8a, 0x1b, 0x4f, 0xc9, 0xfd, 0xe6, 0x4e, 0x74, 0x3b, 0x5c, 0x8b, 0xf3, 0x6e, 0x4a, 0x18, 0xc0, 0x74, 0x3f, 0x72, 0xee, 0x48, 0xa7, 0x75, 0xb6, 0x7f, 0x6a, 0x2e, 0x49, 0x6a, 0xd3, 0xa1, 0x40, 0xd4, 0x47, 0xd8, 0xce, 0x59, 0x2c, 0x43, 0xc5, 0xe5, 0x5d, 0xfa, 0x66, 0x3f, 0xfa, 0x86, 0xf5, 0x7c, 0x3d, 0x17, 0x32, 0xa2, 0x0f, 0xf1, 0xa5, 0x3d, 0xb4, 0x11, 0xf8, 0x6c, 0x96, 0x22, 0x18, 0xb9, 0xe9, 0x56, 0xee, 0x15, 0x28, 0x44, 0x84, 0x91, 0x11, 0x09, 0xab, 0x75, 0xb6, 0x3d, 0xd9, 0x38, 0xb9, 0x6a, 0x10, 0x1c, 0x35, 0x19, 0xb3, 0x89, 0xd9, 0x95, 0x16, 0xfa, 0x92, 0x2f, 0x45, 0xdc, 0x3f, 0x25, 0x2c, 0xd0, 0x74, 0xd0, 0xc8, 0xf6, 0x9a, 0x31, 0x3f, 0xb8, 0x5a, 0x80, 0xd2, 0xc8, 0x39, 0x10, 0x04, 0xb1, 0x12, 0xf9, 0x19, 0x5a, 0xe6, 0xa0, 0xd1, 0x7d, 0x00, 0xdd, 0xed, 0x2b, 0x49, 0xa0, 0x48, 0x07, 0x3c, 0x69, 0x00, 0x34, 0x43, 0x5e, 0xc6, 0xf1, 0xa4, 0x12, 0x73, 0x06, 0xc8, 0x0e, 0x97, 0x18, 0xdb, 0xd5, 0x82, 0xbd, 0x78, 0xf2, 0x3f, 0x5e, 0xa1, 0x5f, 0x88, 0x88, 0x92, 0xfe, 0x5f, 0x5b, 0xe9, 0xda, 0x04, 0xe5, 0x04, 0xc2, 0x23, 0xf6, 0x95, 0x49, 0x92, 0x40, 0xfd, 0x58, 0x31, 0xbd, 0xc8, 0x83, 0xd2, 0xd4, 0x76, 0x21, 0x0a, 0x82, 0x40, 0xf0, 0x21, 0x26, 0x69, 0x40, 0x19, 0x12, 0xcb, 0x95, 0x37, 0xd1, 0xc6, 0x82, 0xbb, 0x56, 0xab, 0x8d, 0x86, 0xcf, 0xb2, 0x83, 0xba, 0x43, 0x53, 0xa6, 0x95, 0x7e, 0x52, 0xb6, 0x6e, 0xac, 0x8a, 0xa1, 0x29, 0x38, 0x58, 0x77, 0xbe, 0xf2, 0x46, 0x77, 0x65, 0x2c, 0xc8, 0xa6, 0xac, 0xba, 0x88, 0x8e, 0xc3, 0x74, 0x5c, 0x41, 0x70, 0x20, 0x8f, 0xf6, 0x16, 0x87, 0xc3, 0xa4, 0xc6, 0xe1, 0x78, 0x97, 0xef, 0x51, 0x87, 0x17, 0xea, 0xc8, 0xe9, 0xc5, 0x04, 0x31, 0xe9, 0x68, 0x84, 0xde, 0x26, 0x56, 0x3a, 0xf8, 0xfc, 0xb3, 0x8a, 0x12, 0x33, 0xe6, 0x57, 0x43, 0x32, 0x6f, 0xd1, 0x0d, 0x6a, 0x8d, 0x83, 0x7e, 0x70, 0x1c, 0x7a, 0x26, 0xbe, 0x02, 0x94, 0x03, 0x98, 0x6e, 0x6b, 0x0c, 0x0e, 0xdb, 0xdc, 0x44, 0x55, 0x80, 0xc0, 0x3c, 0x26, 0x33, 0xf0, 0x41, 0xd6, 0xdb, 0x97, 0xc3, 0xa5, 0x77, 0xd7, 0x26, 0xf7, 0x6e, 0x79, 0x47, 0x67, 0x78, 0xbe, 0x55, 0xc5, 0x41, 0x9d, 0x5a, 0xb0, 0x65, 0x6a, 0x0a, 0xd2, 0x0f, 0xfd, 0xe0, 0xe7, 0xc3, 0xa5, 0x00, 0xf1, 0x5f, 0xfb, 0xb4, 0xc0, 0x30, 0x4e, 0x3d, 0x6d, 0x94, 0xb6, 0x83, 0x2f, 0xf6, 0xed, 0x06, 0x25, 0xbb, 0xd0, 0x60, 0xaf, 0xea, 0x64, 0x2b, 0x86, 0x9b, 0x68, 0x66, 0x79, 0x91, 0x8f, 0x7c, 0x10, 0xd5, 0x8e, 0x73, 0xaa, 0x8b, 0x95, 0x67, 0x54, 0x52, 0xd1, 0xeb, 0x5d, 0x9e, 0x42, 0x22, 0xf9, 0x73, 0xd0, 0x3d, 0x11, 0xc1, 0x09, 0xa1, 0x15, 0x33, 0x7f, 0x99, 0x54, 0x28, 0xdf, 0xb7, 0xcb, 0x50, 0x8d, 0xff, 0x0f, 0xad, 0xd7, 0xf3, 0x37, 0xed, 0x20, 0xf6, 0x82, 0x3a, 0x80, 0xc8, 0xfe, 0x91, 0x1a, 0x0d, 0xa0, 0xa0, 0xc9, 0x20, 0x2a, 0xa3, 0x76, 0x64, 0x9d, 0x04, 0x4f, 0x5e, 0x83, 0x0c, 0x78, 0xf1, 0x82, 0x70, 0x66, 0x47, 0xd6, 0x71, 0x50, 0x8d, 0x06, 0x31, 0x89, 0xd4, 0x05, 0x4d, 0x4b, 0xde, 0x03, 0x0a, 0x59, 0x46, 0x04, 0x81, 0x2d, 0x38, 0x30, 0xd8, 0x74, 0x3f, 0x64, 0x18, 0xa1, 0x33, 0x3f, 0x83, 0x1c, 0xc7, 0x8f, 0xd6, 0xf8, 0x49, 0x09, 0x7f, 0xfa, 0x19, 0x99, 0xd7, 0x30, 0xd8, 0x41, 0x4a, 0xc2, 0x6e, 0x35, 0x3d, 0xac, 0xfe, 0xd2, 0xa6, 0xa1, 0xbb, 0x33, 0x3c, 0xe3, 0x7c, 0xc0, 0x60, 0x3f, 0x3c, 0xdc, 0x5a, 0x02, 0xa5, 0x26, 0x37, 0x94, 0x11, 0xbb, 0xf6, 0xb4, 0x91, 0x1c, 0xc8, 0xe1, 0x60, 0x28, 0x04, 0x36, 0x15, 0x2b, 0x0f, 0x23, 0x05, 0xe5, 0xcc, 0xe3, 0x6c, 0x36, 0x15, 0x98, 0xbf, 0x07, 0x81, 0x81, 0xcd, 0xb0, 0x51, 0xe8, 0x3c, 0x6c, 0x01, 0x63, 0xcf, 0xc1, 0x88, 0x7f, 0x75, 0xa1, 0x70, 0xe3, 0xe6, 0x4c, 0xb1, 0x4d, 0xaa, 0x4b, 0x1a, 0x6b, 0x39, 0x02, 0x9d, 0x31, 0xe8, 0x8c, 0x08, 0x21, 0x09, 0x9c, 0xf7, 0x9b, 0x1e, 0xb4, 0xab, 0x85, 0xb7, 0xf1, 0x9c, 0xe7, 0x50, 0xe4, 0xee, 0xf2, 0x0c, 0x00, 0x58, 0xb9, 0xa4, 0xf1, 0xbf, 0xcd, 0x62, 0x2a, 0xf8, 0xe6, 0x8e, 0x65, 0x94, 0xb5, 0x4e, 0xcb, 0xcc, 0x2c, 0x34, 0x6c, 0x44, 0x88, 0x09, 0xd4, 0x68, 0x1e, 0x02, 0x08, 0x32, 0xfe, 0x75, 0x58, 0x43, 0x63, 0xc4, 0x9e, 0x4d, 0xbf, 0x17, 0xeb, 0x6c, 0x0c, 0x78, 0x78, 0xd2, 0x40, 0x60, 0x0e, 0x2e, 0x4d, 0xfb, 0xa0, 0xc1, 0xf8, 0xee, 0x56, 0x8a, 0xee, 0xaa, 0x6f, 0xc9, 0x29, 0x4e, 0x07, 0x8d, 0xac, 0x1b, 0x96, 0x9c, 0x2b, 0x13, 0xe7, 0x78, 0xba, 0xe8, 0x79, 0xb6, 0x40, 0x71, 0xdd, 0x34, 0x1b, 0x4c, 0x9e, 0x5e, 0xa9, 0x53, 0xba, 0xba, 0xc1, 0xd4, 0x81, 0xc0, 0x15, 0x51, 0x50, 0xed, 0xbc, 0xef, 0x24, 0x3c, 0x2b, 0xba, 0x39, 0x2a, 0xef, 0x27, 0xa7, 0x2f, 0x27, 0x7b, 0x62, 0x3a, 0x6d, 0x70, 0xdf, 0x86, 0xcf, 0x16, 0xf0, 0x18, 0x63, 0xf8, 0xd6, 0x37, 0xb6, 0x4b, 0x23, 0x6a, 0xdb, 0x6d, 0xbb, 0x7f, 0x9c, 0x5b, 0x79, 0x24, 0xe5, 0xe9, 0xae, 0x22, 0xa7, 0x6c, 0x3e, 0x4b, 0x36, 0x58, 0xa3, 0xd8, 0xcb, 0x15, 0x49, 0x6e, 0xef, 0x3b, 0x11, 0xac, 0xb4, 0xd5, 0x8d, 0xd0, 0xa5, 0x56, 0x0e, 0x65, 0x07, 0x13, 0x54, 0xff, 0xb3, 0x7f, 0x3e, 0xa2, 0xee, 0xf0, 0xac, 0xd0, 0xc9, 0x79, 0x87, 0xd5, 0x52, 0xa5, 0x49, 0x65, 0x44, 0x55, 0xaa, 0x2c, 0x96, 0x1b, 0xe9, 0x36, 0x1f, 0x5c, 0x54, 0xdb, 0x7e, 0x6e, 0x8e, 0x7f, 0x99, 0xd9, 0x24, 0x51, 0x67, 0xaf, 0x64, 0x2a, 0xbc, 0xbc, 0xff, 0x16, 0xe4, 0x40, 0x42, 0x4f, 0x5a, 0x92, 0x29, 0x69, 0x15, 0x6f, 0xbb, 0x16, 0xe1, 0xbb, 0xd5, 0x39, 0x38, 0xa0, 0x97, 0xa2, 0x65, 0x15, 0xe9, 0xa6, 0x59, 0xec, 0x92, 0xed, 0xd5, 0x1b, 0x79, 0x2d, 0x51, 0x2f, 0x56, 0x37, 0xbd, 0x24, 0x36, 0x52, 0x43, 0x76, 0x28, 0xeb, 0x6a, 0x24, 0x6f, 0x79, 0xd0, 0xe4, 0xaa, 0xf3, 0x27, 0x6a, 0xc8, 0x91, 0xa2, 0xa6, 0x8e, 0xab, 0x92, 0xb3, 0xed, 0xd0, 0xef, 0x11, 0xb4, 0xa0, 0xab, 0x60, 0xcb, 0x3a, 0x52, 0xbd, 0x1a, 0xae, 0xc8, 0xe7, 0x56, 0x9c, 0x53, 0x85, 0x8a, 0x77, 0x57, 0xcd, 0xa2, 0xe5, 0xe1, 0xb3, 0x67, 0xa0, 0x9f, 0x4c, 0xbc, 0xda, 0x39, 0xc2, 0xb9, 0x27, 0x11, 0xc3, 0x7a, 0xb7, 0x17, 0xec, 0x1a, 0xc7, 0xf7, 0x3c, 0xd4, 0xdf, 0xe6, 0x95, 0xf3, 0x25, 0x37, 0xb5, 0x04, 0x50, 0xb7, 0x45, 0xc2, 0x72, 0x49, 0xb9, 0xbe, 0xb3, 0xeb, 0x6e, 0x64, 0x8a, 0x6d, 0x80, 0xc1, 0x9d, 0xe0, 0xc5, 0xf4, 0xad, 0x86, 0xdb, 0x51, 0x2d, 0xbf, 0x68, 0xa9, 0x78, 0x83, 0x22, 0x1b, 0xab, 0x9b, 0x28, 0x26, 0x36, 0xac, 0x84, 0xe6, 0x98, 0x56, 0xf8, 0x84, 0x05, 0xdb, 0x94, 0x71, 0x9d, 0xba, 0xdc, 0x5f, 0xcb, 0x2f, 0xbc, 0xd8, 0x8e, 0xed, 0x24, 0x51, 0xd5, 0xfa, 0x4e, 0x2f, 0x08, 0x5a, 0xc8, 0x96, 0x5c, 0xad, 0x86, 0x36, 0xcd, 0x80, 0x60, 0xb7, 0x67, 0x3f, 0xc5, 0x25, 0x45, 0x9d, 0x11, 0x26, 0x20, 0xed, 0xe7, 0x7a, 0x7c, 0x4e, 0x3d, 0x51, 0x07, 0x29, 0x33, 0xfd, 0xad, 0xa3, 0xc5, 0x02, 0x09, 0x62, 0xd9, 0x3a, 0x55, 0x66, 0xd9, 0x16, 0x5e, 0x45, 0xad, 0x5d, 0xe6, 0xc7, 0x43, 0xcd, 0x1e, 0x36, 0xdf, 0xcb, 0x51, 0x4c, 0xf6, 0x60, 0x7b, 0x3b, 0x14, 0xa3, 0x8b, 0xf1, 0x4a, 0x0b, 0x3a, 0x54, 0x46, 0x38, 0xa7, 0x14, 0x1a, 0xe1, 0x3a, 0xa6, 0xa4, 0x08, 0x5f, 0xf3, 0x3d, 0x6b, 0xf6, 0x5c, 0xc2, 0xc5, 0x16, 0xdb, 0x69, 0xb5, 0x30, 0xac, 0x0b, 0xaf, 0x56, 0xe1, 0x24, 0x3c, 0x2f, 0x69, 0x33, 0x3b, 0xbd, 0xd6, 0x14, 0x28, 0x5b, 0x24, 0x9d, 0x46, 0xb5, 0x5e, 0xa0, 0xb2, 0x73, 0x51, 0x0d, 0x04, 0x6c, 0x0f, 0x38, 0x97, 0xed, 0xcd, 0xaa, 0x55, 0xa3, 0xb5, 0x7e, 0x96, 0x22, 0xc1, 0x16, 0x2d, 0xd4, 0x7c, 0xe9, 0xd4, 0xd9, 0xf3, 0x63, 0x86, 0xfc, 0xd2, 0x82, 0xdd, 0x44, 0x86, 0xf5, 0x05, 0xe5, 0x5f, 0x82, 0xe2, 0x47, 0xb9, 0x69, 0xb5, 0x03, 0x4d, 0x31, 0xc0, 0x43, 0xa3, 0xb0, 0xfa, 0xcb, 0x6b, 0x09, 0x23, 0x3f, 0x6b, 0x72, 0x28, 0x97, 0xf2, 0xaf, 0x9c, 0x9c, 0x1b, 0x48, 0xb4, 0x8b, 0x1f, 0x3a, 0x0d, 0x15, 0x2b, 0x82, 0x18, 0xf9, 0x96, 0x0a, 0xfc, 0x06, 0xf3, 0x3e, 0x89, 0x4c, 0x8a, 0x64, 0xaa, 0x43, 0x84, 0x7d, 0x82, 0xe3, 0xa2, 0xc5, 0x62, 0x32, 0x51, 0xda, 0xa1, 0xc0, 0xe0, 0xac, 0x73, 0x91, 0x9b, 0xfe, 0x49, 0x9a, 0xc7, 0x43, 0xd9, 0x32, 0xd0, 0x2f, 0x2a, 0x25, 0xa8, 0x99, 0x22, 0xe5, 0x4d, 0x08, 0xcc, 0xa4, 0xf4, 0x6a, 0x34, 0x1f, 0x8f, 0xd8, 0x5f, 0x8a, 0x57, 0xad, 0xc8, 0x8d, 0x4f, 0x27, 0x50, 0x05, 0x12, 0xb6, 0x83, 0x83, 0x35, 0x82, 0x2d, 0x30, 0x89, 0x78, 0x68, 0x5c, 0x09, 0x95, 0xd1, 0x90, 0x38, 0x17, 0xb6, 0x88, 0xa0, 0x1c, 0x30, 0x0a, 0x6c, 0x94, 0x16, 0x20, 0xb0, 0x0a, 0x8f, 0x0c, 0xc9, 0xaa, 0xe6, 0x84, 0x82, 0xff, 0x6a, 0x25, 0xc1, 0x1c, 0x1c, 0xbc, 0x05, 0xc1, 0x61, 0xeb, 0x63, 0xce, 0x2b, 0x1e, 0x2a, 0x4b, 0x04, 0x7c, 0x61, 0x9f, 0x8e, 0x99, 0xfd, 0x49, 0xa0, 0x78, 0x43, 0xff, 0xb2, 0xe1, 0x5f, 0x3d, 0xec, 0x06, 0xe8, 0x94, 0xbf, 0x67, 0x43, 0xdb, 0xfc, 0xf3, 0x7c, 0xed, 0xc3, 0xf8, 0xa5, 0x11, 0xa0, 0x58, 0x04, 0x5e, 0xab, 0x54, 0x99, 0x29, 0x53, 0x0a, 0x87, 0xf1, 0x20, 0x78, 0xac, 0x18, 0x3d, 0x2e, 0x12, 0xc4, 0x86, 0xd1, 0x28, 0xfc, 0x03, 0x71, 0x38, 0xf8, 0x15, 0xb1, 0xad, 0x47, 0x03, 0xa6, 0xcc, 0x7d, 0x53, 0x16, 0x94, 0x1d, 0x17, 0x22, 0xdf, 0xe3, 0xef, 0x89, 0x77, 0xa3, 0xd6, 0x87, 0x98, 0x9b, 0xf7, 0x1a, 0x1f, 0xb3, 0xad, 0xb0, 0x5c, 0x23, 0x24, 0x4e, 0xca, 0x46, 0x13, 0xeb, 0x71, 0xaa, 0x23, 0x46, 0x5a, 0xf8, 0x93, 0xf6, 0x37, 0xf7, 0x26, 0x82, 0xb5, 0x3b, 0x7d, 0xf4, 0xf5, 0xc9, 0x98, 0x01, 0x65, 0xb5, 0x50, 0xf5, 0x4d, 0xcf, 0x36, 0xad, 0xb1, 0xd4, 0xff, 0x9b, 0x4c, 0xc7, 0xef, 0x80, 0xcb, 0x0a, 0xd3, 0x2b, 0xf3, 0x6c, 0x7f, 0x22, 0xd7, 0x2e, 0x01, 0x5f, 0x59, 0xb9, 0x2c, 0xbf, 0xf6, 0xc8, 0xf3, 0xd1, 0x85, 0x40, 0x7d, 0x30, 0x06, 0x08, 0x0c, 0xb5, 0x78, 0xc0, 0x2a, 0xc4, 0xb4, 0xad, 0x80, 0x69, 0x7a, 0x95, 0x69, 0xc7, 0xa9, 0xd4, 0x33, 0x57, 0xf1, 0x74, 0x12, 0xfc, 0xd3, 0x4d, 0x62, 0x96, 0x94, 0xef, 0x44, 0x81, 0xbd, 0x1b, 0x78, 0xc0, 0xb9, 0x20, 0xf8, 0x79, 0x07, 0x89, 0xc4, 0x06, 0x87, 0xc9, 0x32, 0xf1, 0xa6, 0x1b, 0xd4, 0x81, 0x01, 0x5c, 0x54, 0xad, 0x9f, 0xd0, 0x61, 0x04, 0x77, 0xf9, 0x32, 0xcd, 0x69, 0xb4, 0xac, 0x78, 0x72, 0x94, 0x40, 0x4d, 0xee, 0xa9, 0xb3, 0xc9, 0x98, 0xda, 0xd9, 0x91, 0x8f, 0x2e, 0xa4, 0x18, 0x07, 0xd9, 0xc8, 0x03, 0xc9, 0x45, 0x38, 0x38, 0x89, 0xff, 0xb3, 0x57, 0x69, 0x46, 0x37, 0x37, 0xcd, 0xb5, 0xf5, 0x4c, 0xf7, 0x92, 0xa7, 0x48, 0xad, 0xa9, 0x57, 0x93, 0x7b, 0xef, 0xae, 0x59, 0xf6, 0xb6, 0x15, 0xca, 0x22, 0x3e, 0x58, 0x65, 0x26, 0x4a, 0x39, 0xf0, 0xf4, 0x4a, 0x4a, 0xd4, 0xff, 0x8a, 0x94, 0x75, 0x9f, 0x29, 0xf5, 0xdf, 0x36, 0xa3, 0x6e, 0x07, 0xbe, 0xec, 0x2d, 0xcf, 0xc9, 0xb7, 0xb1, 0x6e, 0xf5, 0xc1, 0x88, 0x43, 0xf1, 0x7f, 0x81, 0xc0, 0xa4, 0x04, 0x50, 0x6e, 0x16, 0x7c, 0x3f, 0x05, 0x58, 0x30, 0xe4, 0x7a, 0x0e, 0x05, 0x58, 0x30, 0x29, 0xc1, 0x8b, 0x4b, 0x01, 0x4c, 0x0c, 0xa4, 0x18, 0x41, 0x10, 0x41, 0x10, 0x18, 0x6c, 0xa4, 0x3f, 0x02, 0xe0, 0xaa, 0x06, 0x0e, 0x41, 0xf0, 0x7f, 0xed, 0x0b, 0x69, 0x44, 0xb4, 0xe5, 0xcd, 0x5c, 0x1f, 0xb4, 0x3f, 0xd5, 0x7c, 0x6d, 0xa2, 0xf6, 0x8b, 0xc4, 0x88, 0x24, 0x2b, 0x4f, 0xac, 0xec, 0xff, 0xc7, 0x20, 0x64, 0x78, 0xa9, 0x20, 0x32, 0x96, 0x1b, 0x8a, 0xfc, 0xac, 0xaf, 0xf5, 0xac, 0x6f, 0x14, 0xe5, 0x6d, 0xa6, 0xcc, 0x45, 0x19, 0x2a, 0xe8, 0xd0, 0x12, 0x9f, 0xc1, 0xe9, 0xa0, 0x03, 0xe0, 0x52, 0x9a, 0x82, 0x27, 0xb7, 0x7e, 0x3e, 0xbd, 0x60, 0xb5, 0xb5, 0x65, 0xcc, 0xf4, 0x42, 0xec, 0xbb, 0x3f, 0xf4, 0x89, 0x55, 0xef, 0x41, 0x55, 0x14, 0x03, 0x23, 0x65, 0xb5, 0xae, 0x33, 0xdd, 0xe1, 0x87, 0x9b, 0xe6, 0xfa, 0x20, 0x27, 0x1f, 0x27, 0x98, 0xa2, 0x6d, 0x2e, 0x2f, 0x48, 0x3f, 0x51, 0xde, 0xdc, 0x8d, 0xd4, 0xcd, 0xb6, 0x58, 0xa5, 0x46, 0xdc, 0x2d, 0xe1, 0x69, 0x67, 0xf8, 0x36, 0xa7, 0x87, 0x23, 0xf9, 0x41, 0xe0, 0x60, 0x43, 0x05, 0x14, 0x03, 0x05, 0x9d, 0x08, 0x00, 0x8a, 0x08, 0xb5, 0x38, 0x2a, 0x80, 0xd6, 0xab, 0x10, 0xe8, 0x3c, 0x17, 0xfd, 0x34, 0xb8, 0x15, 0xa0, 0xaa, 0x8a, 0xc0, 0xd4, 0x6d, 0x42, 0xea, 0x47, 0x0a, 0x03, 0xd0, 0xb1, 0x29, 0xed, 0x06, 0xe9, 0x7b, 0x6a, 0x9b, 0x06, 0x62, 0x27, 0xf0, 0x28, 0x84, 0x3c, 0x10, 0x01, 0x84, 0xa0, 0x62, 0xd5, 0x0d, 0xeb, 0x2c, 0x37, 0x07, 0x9f, 0x57, 0x73, 0xc0, 0xc2, 0x00, 0x7e, 0xc0, 0xec, 0x71, 0x55, 0x4c, 0x67, 0xc3, 0xfa, 0xcd, 0x4c, 0x38, 0xf3, 0x3f, 0x85, 0xd0, 0xc5, 0xba, 0x80, 0xf4, 0x4d, 0x3f, 0x56, 0x9b, 0x64, 0x40, 0xc2, 0xf1, 0xd6, 0xab, 0xed, 0xca, 0x93, 0x04, 0xb1, 0xf6, 0x97, 0xf7, 0x03, 0xbf, 0x52, 0xec, 0x57, 0x53, 0xcd, 0xf2, 0x8a, 0x5b, 0xea, 0xd2, 0x9c, 0x51, 0xaa, 0x64, 0xe3, 0xd4, 0x08, 0x25, 0xe5, 0xc2, 0x56, 0x84, 0x2c, 0x6f, 0xe5, 0xdd, 0x56, 0x24, 0x97, 0x24, 0x6f, 0x13, 0xa7, 0x9e, 0xd6, 0x07, 0xca, 0xc3, 0xf1, 0xc8, 0xef, 0x32, 0x2b, 0xf5, 0x98, 0xab, 0x5a, 0xcc, 0x0f, 0xd9, 0x9f, 0x1f, 0x78, 0xae, 0x7f, 0x2e, 0xf0, 0x2c, 0x61, 0x08, 0x1e, 0x06, 0x04, 0x10, 0x53, 0x01, 0xe0, 0xfc, 0x18, 0xb0, 0x6c, 0x5c, 0xa0, 0x3e, 0x1c, 0xd0, 0x3b, 0x40, 0xf9, 0x65, 0x53, 0xd0, 0x61, 0x00, 0x1e, 0x0b, 0xfc, 0xf9, 0x41, 0x56, 0x20, 0x88, 0x0a, 0x41, 0x80, 0xc7, 0x40, 0xd0, 0xe0, 0x3c, 0x07, 0xc1, 0x80, 0x54, 0x46, 0x0c, 0xad, 0x30, 0xf0, 0x1e, 0x0a, 0x02, 0xf4, 0xe3, 0xf6, 0x87, 0xdc, 0x07, 0x81, 0xff, 0x1c, 0x48, 0x61, 0x5a, 0xb4, 0xbe, 0x63, 0x80, 0xaa, 0x50, 0x3f, 0xfb, 0x2d, 0x7d, 0x96, 0x67, 0x01, 0x55, 0xd0, 0xf7, 0xed, 0x6e, 0x87, 0xd6, 0x95, 0xeb, 0x9e, 0xda, 0xb2, 0x0e, 0x1a, 0x0c, 0x6c, 0xa7, 0xaa, 0xe1, 0x79, 0x84, 0xd9, 0x98, 0x23, 0x09, 0x6d, 0xf2, 0x08, 0xbd, 0x68, 0x70, 0x3c, 0x1f, 0xb2, 0x1e, 0x71, 0x48, 0x18, 0xef, 0x95, 0x32, 0xc8, 0x79, 0xc5, 0x25, 0x43, 0x72, 0xa4, 0x6f, 0x7a, 0x3a, 0xb9, 0x55, 0x27, 0xca, 0x5d, 0x55, 0x5b, 0x2c, 0x2f, 0x2e, 0xdf, 0x5c, 0xff, 0x92, 0x25, 0x63, 0x7f, 0x35, 0x4e, 0x76, 0x8d, 0xf2, 0x9b, 0x99, 0xff, 0x7e, 0xf4, 0xb3, 0xe6, 0x03, 0x10, 0x32, 0x70, 0x86, 0x0d, 0x85, 0x6a, 0x3a, 0x24, 0xb0, 0x99, 0x6a, 0x06, 0xb8, 0x21, 0x02, 0x18, 0x32, 0xe9, 0x18, 0xd0, 0x78, 0x48, 0x0a, 0xd2, 0x83, 0x15, 0xb0, 0xba, 0x49, 0x67, 0x0b, 0x19, 0x06, 0x41, 0xa1, 0x70, 0xe9, 0x57, 0x52, 0xe8, 0x85, 0xf6, 0x1b, 0x55, 0x8a, 0xda, 0x10, 0x68, 0x33, 0x09, 0x81, 0xe0, 0x7f, 0xb5, 0x04, 0x49, 0xff, 0x08, 0x40, 0xaa, 0x6f, 0xa3, 0xcf, 0xb6, 0xac, 0x21, 0x2a, 0x1d, 0xab, 0xf9, 0x6d, 0x2c, 0x6f, 0xcd, 0xb4, 0x3e, 0xd4, 0x93, 0xfe, 0xf7, 0xd4, 0xb2, 0x20, 0x99, 0xbb, 0xd3, 0x4a, 0x78, 0x88, 0x1c, 0x41, 0xa6, 0x83, 0x65, 0xc0, 0x7b, 0xc3, 0x81, 0xca, 0x41, 0x21, 0x50, 0x82, 0xde, 0x2a, 0x68, 0xb7, 0xc9, 0xbc, 0x1f, 0xab, 0xfa, 0xde, 0x55, 0xe2, 0xde, 0x0e, 0x59, 0xff, 0x2a, 0x86, 0xb3, 0xbf, 0xd5, 0x15, 0x44, 0x59, 0xe6, 0x6d, 0x06, 0x60, 0xab, 0x07, 0x20, 0xa0, 0x95, 0xb0, 0x2d, 0x04, 0x11, 0x28, 0xb5, 0x92, 0xbd, 0x68, 0x0c, 0x42, 0xde, 0xb6, 0x06, 0x73, 0x5a, 0x2a, 0x5c, 0x73, 0x9b, 0xe0, 0xee, 0x58, 0xe0, 0xb8, 0x07, 0x40, 0xf8, 0x42, 0x1d, 0xb2, 0x0c, 0x5c, 0xc0, 0xf8, 0x7a, 0x98, 0xbd, 0xbf, 0x83, 0x2b, 0x03, 0xc5, 0xf1, 0xa5, 0x5f, 0x9f, 0xdc, 0x63, 0x2f, 0xfb, 0xac, 0xe6, 0x2e, 0x9b, 0x65, 0x4e, 0xd0, 0x18, 0x4e, 0x58, 0xdd, 0xa5, 0xb2, 0x67, 0x5a, 0x6c, 0x05, 0x1e, 0x06, 0x60, 0x1b, 0x00, 0xf0, 0xec, 0x14, 0x1f, 0x4e, 0x9d, 0x24, 0x56, 0xc8, 0x43, 0x64, 0x7e, 0x5a, 0xaf, 0x66, 0x6b, 0x6a, 0xb1, 0x84, 0xec, 0xb1, 0xe0, 0x55, 0x6d, 0xf5, 0x03, 0x56, 0x70, 0x73, 0x77, 0x3b, 0x7f, 0xf5, 0x9b, 0x2d, 0x62, 0x40, 0x18, 0x6a, 0xf5, 0x1f, 0xc5, 0xf7, 0xa3, 0x2e, 0x3f, 0x5c, 0x98, 0x42, 0x08, 0x21, 0x09, 0x60, 0x78, 0x3f, 0xf8, 0x47, 0x43, 0xf6, 0xa9, 0x27, 0x0a, 0x1e, 0x33, 0x03, 0xea, 0xfc, 0x08, 0x61, 0x08, 0x7d, 0xa5, 0xc9, 0xe6, 0xcd, 0xce, 0x7d, 0x81, 0xfb, 0x43, 0xd1, 0xf8, 0x90, 0x3c, 0xaa, 0xaf, 0x53, 0x96, 0x42, 0xfa, 0x98, 0xbc, 0x3c, 0x8c, 0x2f, 0xd2, 0xc8, 0xa5, 0xaf, 0xa9, 0x93, 0xf9, 0x6b, 0x82, 0x58, 0x28, 0xc0, 0xf8, 0xfd, 0x85, 0x4a, 0x95, 0x0e, 0x59, 0xfe, 0xee, 0x16, 0xab, 0x6e, 0x30, 0xc3, 0x4c, 0x4f, 0xb3, 0xfe, 0x37, 0xfe, 0x4d, 0xcf, 0x66, 0x4d, 0x6f, 0x79, 0xfb, 0xc9, 0xc8, 0xbf, 0x21, 0xc3, 0x03, 0xdf, 0x84, 0x0a, 0xc0, 0xe5, 0x28, 0xf8, 0x0e, 0x8e, 0x83, 0xff, 0xcf, 0x27, 0x2f, 0x54, 0xb8, 0xe5, 0x52, 0xae, 0xf9, 0xb9, 0x37, 0x1b, 0x97, 0x62, 0x8f, 0x29, 0x96, 0xe6, 0xac, 0x6e, 0x1c, 0xb6, 0xde, 0x21, 0xe4, 0x34, 0xed, 0x71, 0x9b, 0x69, 0xfe, 0xac, 0x4a, 0x4a, 0x07, 0x55, 0x2b, 0x08, 0x42, 0x1a, 0x46, 0xe2, 0x51, 0x08, 0x7a, 0x21, 0x7c, 0x0e, 0x68, 0x34, 0x11, 0x92, 0xd5, 0x6c, 0xf9, 0xa5, 0x4a, 0x75, 0x52, 0x56, 0x04, 0x11, 0xfb, 0x55, 0x16, 0xa8, 0xd5, 0x7e, 0xb8, 0x38, 0x93, 0x7f, 0xbb, 0xa0, 0xb2, 0x28, 0xd0, 0x33, 0x62, 0x58, 0x94, 0x9c, 0x78, 0x3f, 0x48, 0xa8, 0x4a, 0xa2, 0x1a, 0x96, 0xb0, 0xb1, 0x52, 0x42, 0xf5, 0x49, 0xfd, 0x36, 0x66, 0xea, 0xfe, 0x9e, 0x6f, 0xdb, 0x93, 0x79, 0x6a, 0x25, 0xd7, 0xe3, 0xec, 0x03, 0x5b, 0x1f, 0x0f, 0x47, 0x63, 0xe1, 0xf4, 0x1d, 0x0f, 0x00, 0xe8, 0xf9, 0xaf, 0x26, 0x4e, 0xca, 0x7a, 0x94, 0x7a, 0xc1, 0x77, 0xd5, 0x07, 0xdf, 0xd2, 0xdf, 0x56, 0x9b, 0xfa, 0x5c, 0x61, 0x99, 0x65, 0x6b, 0xc0, 0x65, 0x82, 0xbf, 0xa9, 0xa3, 0x89, 0x02, 0xd4, 0xc2, 0x06, 0x0e, 0x80, 0x31, 0xa0, 0x78, 0x2f, 0xf9, 0x44, 0x06, 0x18, 0x9b, 0x7e, 0xac, 0x1e, 0x0b, 0xfd, 0x9f, 0x82, 0x85, 0x91, 0x28, 0x18, 0x38, 0xf7, 0x04, 0x28, 0x23, 0xe8, 0x30, 0x18, 0x10, 0x18, 0x51, 0xec, 0xe0, 0x2b, 0x27, 0xc5, 0x7d, 0x51, 0xde, 0x75, 0x74, 0x27, 0xb5, 0xc1, 0x66, 0xc0, 0x8e, 0x10, 0xcb, 0xd2, 0x83, 0x32, 0x21, 0x26, 0x12, 0x07, 0xf1, 0x37, 0xbe, 0xaf, 0x52, 0x44, 0xcd, 0x40, 0x6c, 0x12, 0xfb, 0xcc, 0xef, 0x03, 0xfb, 0x90, 0x21, 0xa4, 0xef, 0x74, 0x18, 0xd2, 0x9b, 0x3c, 0x22, 0x1f, 0x14, 0x01, 0xe0, 0x51, 0x62, 0x66, 0x52, 0x40, 0x3b, 0xa2, 0x4e, 0x09, 0x5e, 0x05, 0x3f, 0xc7, 0xc0, 0xa7, 0xcb, 0x47, 0x20, 0xaa, 0x8c, 0x8e, 0x14, 0xf0, 0xb7, 0xa3, 0x80, 0x23, 0xc2, 0xc0, 0xe7, 0x87, 0xcd, 0x24, 0x6c, 0x49, 0x03, 0x82, 0x18, 0x31, 0x5e, 0x17, 0xc6, 0x9a, 0xbc, 0x60, 0x1e, 0x0b, 0xfd, 0xb1, 0x28, 0x10, 0xc2, 0x13, 0x5f, 0xa3, 0x75, 0x05, 0x8d, 0x89, 0x25, 0xc5, 0x5b, 0xf5, 0x0a, 0x78, 0x05, 0xbe, 0xf2, 0x1a, 0xca, 0x86, 0x80, 0xc7, 0x9a, 0x55, 0xe9, 0x33, 0xde, 0x2b, 0xfe, 0xff, 0x74, 0x45, 0xdb, 0x77, 0x76, 0x95, 0xdf, 0xff, 0x6d, 0xaf, 0x35, 0x8f, 0x79, 0x01, 0x64, 0x91, 0x10, 0xcc, 0x55, 0xae, 0x68, 0x14, 0x00, 0xcd, 0x0f, 0x19, 0x56, 0x56, 0x39, 0xc6, 0x2e, 0x79, 0xa6, 0xb5, 0x70, 0xe6, 0x90, 0x6a, 0x0c, 0xb2, 0xa9, 0x3d, 0xde, 0x16, 0xb6, 0xdf, 0xf5, 0x44, 0x59, 0x4d, 0xdb, 0xd7, 0xc7, 0xd4, 0x06, 0xd0, 0x07, 0x03, 0x97, 0x3f, 0xa1, 0xa4, 0x48, 0x81, 0xc7, 0x5a, 0x1b, 0x0f, 0x6d, 0x33, 0xa6, 0x2d, 0xf0, 0xe8, 0xb9, 0x8e, 0x0e, 0x13, 0x30, 0xd4, 0x35, 0xe6, 0xbd, 0x81, 0x91, 0x84, 0x0b, 0x32, 0x2c, 0x2f, 0x09, 0x9d, 0x9d, 0x3f, 0xe5, 0x34, 0x11, 0xce, 0x62, 0x19, 0xd2, 0x9e, 0x3f, 0x4e, 0x78, 0x0e, 0x25, 0x19, 0x11, 0xf5, 0x00, 0x3c, 0x94, 0x23, 0xdc, 0x07, 0x23, 0x39, 0x91, 0xa3, 0xe1, 0xe5, 0x02, 0x43, 0x4d, 0x3f, 0x51, 0x82, 0xc4, 0x1c, 0x2e, 0xeb, 0xcf, 0xc1, 0xf3, 0x0d, 0x27, 0xb9, 0x93, 0x74, 0x73, 0x37, 0x6d, 0xd0, 0x33, 0x9e, 0xea, 0x39, 0x14, 0xa2, 0xea, 0x22, 0xce, 0x73, 0x88, 0x88, 0x54, 0xa8, 0xc4, 0xc2, 0xd5, 0x0b, 0x2c, 0x37, 0xe2, 0xdd, 0x88, 0x44, 0xc6, 0xc1, 0x5d, 0x5c, 0xae, 0xec, 0xa8, 0xd4, 0x44, 0x1c, 0xaa, 0x3b, 0xd5, 0x90, 0x20, 0x9d, 0x43, 0xc3, 0x83, 0x71, 0xea, 0x82, 0xf6, 0xc4, 0x0b, 0x1a, 0xff, 0x40, 0x87, 0xd8, 0x0f, 0x66, 0xf3, 0xf2, 0x72, 0x6a, 0xd6, 0x11, 0xad, 0xef, 0xd9, 0xa0, 0xc1, 0xef, 0xe1, 0x59, 0x56, 0x77, 0x95, 0x44, 0x88, 0x44, 0x5e, 0xf2, 0x22, 0xea, 0xce, 0x15, 0x26, 0xf6, 0x24, 0x9b, 0xb9, 0xb7, 0xa8, 0x54, 0xd6, 0x65, 0xbc, 0xe2, 0xd1, 0x6f, 0x4e, 0x45, 0x90, 0x8c, 0xce, 0xf6, 0x23, 0x8b, 0xc3, 0x43, 0x5a, 0x9a, 0xde, 0xe2, 0x82, 0xd0, 0xfb, 0xed, 0xb2, 0x1e, 0x41, 0xc2, 0x05, 0x08, 0x06, 0xd7, 0x54, 0xf1, 0x1c, 0x95, 0x71, 0x41, 0x4a, 0xd3, 0x72, 0xc5, 0xb9, 0x93, 0x6d, 0xd6, 0xb3, 0xa8, 0xaa, 0xc8, 0xed, 0x8b, 0xc5, 0xd6, 0x97, 0x49, 0xd7, 0x9d, 0x89, 0xe4, 0x91, 0x69, 0x2c, 0xda, 0xba, 0xd6, 0x0d, 0x83, 0xde, 0xc5, 0xc6, 0x26, 0xfa, 0x81, 0xe9, 0x56, 0xea, 0x9b, 0x27, 0x36, 0xa3, 0xe7, 0x2a, 0xcb, 0x2c, 0x8b, 0xa3, 0x71, 0x99, 0xe5, 0x9b, 0xc4, 0x10, 0x33, 0xa1, 0x5c, 0x4d, 0x45, 0x62, 0x02, 0xab, 0x93, 0x9f, 0x51, 0x20, 0x77, 0xe5, 0x37, 0x72, 0xa0, 0x95, 0x74, 0x5c, 0x5e, 0xa9, 0x58, 0x6a, 0x33, 0xfa, 0xbf, 0x0f, 0xf9, 0xa9, 0x8b, 0x75, 0xaf, 0x58, 0x5b, 0xcc, 0xfb, 0x17, 0x43, 0xd2, 0xae, 0xf9, 0x47, 0xb6, 0x1b, 0xde, 0xc5, 0xd1, 0xae, 0x8d, 0xeb, 0x37, 0xe5, 0xf3, 0x3e, 0xc2, 0x9f, 0x69, 0x6e, 0xb7, 0xf0, 0x21, 0x22, 0x2e, 0x76, 0x49, 0x57, 0x45, 0x56, 0x40, 0x8d, 0xe2, 0x54, 0x8a, 0x8b, 0x4b, 0x6c, 0x68, 0x70, 0xc2, 0x2f, 0x7b, 0x99, 0x16, 0xef, 0x54, 0xc8, 0xa3, 0xa1, 0xea, 0x3e, 0xda, 0xb8, 0x56, 0xa5, 0xbc, 0x20, 0xab, 0xa2, 0xaf, 0x27, 0xa2, 0xeb, 0xa1, 0x9b, 0x32, 0x4d, 0xa6, 0xf8, 0x1c, 0x68, 0x61, 0x45, 0x7a, 0xb3, 0x6b, 0x4d, 0x0e, 0x3f, 0xfb, 0xb8, 0x8e, 0x7e, 0xf7, 0x85, 0x8b, 0x55, 0x1c, 0xe6, 0x4e, 0x73, 0xbc, 0x8b, 0x09, 0x88, 0xfe, 0x37, 0xa5, 0x9d, 0xb6, 0x5b, 0x67, 0x38, 0x80, 0xd7, 0x7b, 0xc2, 0x53, 0xae, 0x58, 0xb2, 0xd9, 0xb6, 0xae, 0x4b, 0x0d, 0xaf, 0x4d, 0x94, 0x3b, 0x5c, 0xfe, 0x9a, 0xb8, 0x90, 0x15, 0xbf, 0x56, 0xb6, 0xb7, 0x72, 0x2d, 0x7d, 0x65, 0x96, 0x08, 0x90, 0xab, 0xba, 0xa4, 0xd1, 0x11, 0x5a, 0x3c, 0xcd, 0x62, 0x59, 0x3e, 0xc4, 0xe6, 0xf6, 0xac, 0xa4, 0xae, 0x59, 0xb3, 0xba, 0xa7, 0x88, 0xfb, 0x28, 0xde, 0x72, 0x11, 0xd8, 0xe3, 0xb2, 0x23, 0x95, 0x05, 0x5a, 0x8c, 0x16, 0xea, 0xf0, 0xdc, 0x59, 0x01, 0x3c, 0xff, 0x54, 0xe1, 0x65, 0xf5, 0xe5, 0x0f, 0x2d, 0x58, 0x63, 0x7b, 0x9c, 0xe3, 0xd9, 0x7a, 0xb1, 0x2f, 0x7b, 0x28, 0x4b, 0x13, 0x4d, 0x33, 0x03, 0x86, 0x2f, 0xbc, 0x1e, 0xdc, 0x91, 0x1f, 0x7b, 0x79, 0x00, 0xae, 0xad, 0xde, 0xf1, 0x18, 0x50, 0x4d, 0x80, 0x33, 0x9d, 0xb9, 0xca, 0x50, 0x8f, 0x84, 0xab, 0xf0, 0x99, 0x55, 0x73, 0x73, 0xdc, 0x6b, 0x2e, 0x7f, 0x9c, 0x9f, 0x11, 0x20, 0x2b, 0xe2, 0x95, 0xc9, 0xa1, 0xab, 0x24, 0x93, 0xb0, 0xd1, 0x51, 0x52, 0x05, 0xd6, 0x0c, 0x5f, 0x78, 0x4b, 0x4f, 0xd4, 0xc4, 0x6a, 0x92, 0xfa, 0x6b, 0x6a, 0x76, 0xf4, 0x73, 0x62, 0x8e, 0x6a, 0xca, 0x16, 0x43, 0x06, 0xd3, 0xa8, 0xc2, 0x9b, 0xb0, 0x72, 0xca, 0xa9, 0xf8, 0xb4, 0x1f, 0xb0, 0xdf, 0xba, 0x49, 0xb3, 0x96, 0x0d, 0xd1, 0x2e, 0x68, 0x4e, 0x83, 0x10, 0x41, 0xad, 0xb7, 0x36, 0xde, 0xb7, 0xce, 0xf0, 0xb7, 0x16, 0x5a, 0xe2, 0xd7, 0x96, 0x0a, 0xcb, 0xe2, 0xac, 0xeb, 0x05, 0x57, 0x91, 0x99, 0x78, 0x8f, 0x8b, 0xf7, 0x16, 0x5f, 0x90, 0x28, 0x5b, 0x6b, 0xa2, 0xee, 0xf7, 0xa0, 0xf5, 0x30, 0x01, 0x84, 0xbd, 0x05, 0xe0, 0x3a, 0x1b, 0x04, 0xd5, 0x56, 0xd3, 0x61, 0x8c, 0xa0, 0xe0, 0x1e, 0x72, 0xa9, 0xf9, 0x10, 0x1f, 0xd3, 0xa3, 0x68, 0xca, 0x11, 0x1d, 0x2c, 0xa6, 0x9a, 0x88, 0xae, 0x29, 0xe7, 0xaf, 0xfd, 0x3f, 0xc1, 0xce, 0x7b, 0xfc, 0x53, 0xec, 0x6f, 0x90, 0x41, 0xcc, 0xb3, 0x19, 0xe6, 0x0e, 0x66, 0xa8, 0x73, 0x52, 0xb1, 0xa4, 0x20, 0xe4, 0x47, 0x0c, 0xb4, 0xad, 0x9b, 0xf6, 0x73, 0xe9, 0xae, 0x7b, 0x2c, 0x2c, 0xf9, 0x6c, 0x05, 0x6c, 0x0e, 0x54, 0x41, 0xb5, 0xe8, 0xc5, 0x18, 0xa9, 0x4a, 0x81, 0xc2, 0x8a, 0x98, 0xaa, 0xf2, 0xce, 0x7f, 0xde, 0xff, 0xaa, 0x36, 0x99, 0xf7, 0x99, 0x6b, 0x79, 0x7a, 0x56, 0xc3, 0x33, 0x5a, 0xde, 0x6c, 0x9b, 0x14, 0xe5, 0xe6, 0xe6, 0x68, 0xdf, 0x23, 0xde, 0xef, 0x57, 0xed, 0xb6, 0xdb, 0xd4, 0x3d, 0xb4, 0x96, 0xa1, 0xb4, 0x8d, 0x05, 0x24, 0x80, 0xe2, 0x51, 0xaf, 0xe8, 0x3f, 0x7c, 0x00, 0x72, 0x13, 0xc6, 0xc2, 0xd0, 0x2b, 0x26, 0x8e, 0x74, 0x7c, 0x3c, 0xd6, 0x62, 0x8b, 0x15, 0xfc, 0x74, 0x3c, 0xfa, 0x59, 0x73, 0x85, 0x97, 0x13, 0xfd, 0x35, 0x57, 0x2b, 0x53, 0x24, 0x6a, 0x96, 0xf5, 0xa5, 0x12, 0x7a, 0xe2, 0x88, 0x79, 0x54, 0xe9, 0x07, 0x83, 0xf5, 0x10, 0x7e, 0x93, 0xc9, 0x7d, 0x2a, 0x9e, 0x37, 0xaa, 0xfd, 0x4b, 0x78, 0x37, 0x2d, 0x61, 0xb6, 0x1b, 0x29, 0x0f, 0x54, 0x7d, 0x6b, 0xf9, 0xa5, 0x98, 0x7a, 0xaf, 0x41, 0x63, 0xd0, 0xc0, 0xeb, 0x19, 0x83, 0x81, 0x3a, 0xd9, 0x06, 0x24, 0xaf, 0xa3, 0x44, 0xc4, 0x9b, 0xca, 0x37, 0xcc, 0x2c, 0x51, 0x22, 0x8a, 0xd6, 0x56, 0x0b, 0x24, 0x92, 0x35, 0x58, 0xb0, 0x70, 0x20, 0x4c, 0xc9, 0xe8, 0xc1, 0x60, 0xe0, 0xb2, 0x4f, 0x28, 0x51, 0x0f, 0x29, 0x31, 0xa9, 0xd8, 0xa9, 0xa4, 0xc9, 0xa6, 0xf3, 0xb8, 0x3e, 0x1e, 0x24, 0x2e, 0x9b, 0x73, 0xaa, 0x2b, 0x70, 0xb9, 0x86, 0x87, 0x3b, 0x93, 0x7f, 0x30, 0xb5, 0x4a, 0x82, 0xdf, 0xa8, 0xe2, 0x9a, 0x7c, 0xcf, 0x4f, 0x7e, 0x9b, 0x2b, 0x19, 0x05, 0x5a, 0x8c, 0x24, 0x07, 0x12, 0x91, 0xe9, 0x8b, 0x44, 0x84, 0x93, 0x47, 0x29, 0xd8, 0x1f, 0x09, 0x54, 0x77, 0x36, 0x96, 0x27, 0x06, 0x50, 0x3e, 0xf2, 0x59, 0xff, 0x87, 0x6c, 0xfd, 0x2e, 0x35, 0x89, 0xef, 0xea, 0x9d, 0x2d, 0xbb, 0xf5, 0x2d, 0xaf, 0x2d, 0xbd, 0x78, 0x95, 0x38, 0xe1, 0xb4, 0xda, 0xc7, 0xd3, 0x34, 0x3f, 0x53, 0x24, 0xaa, 0x93, 0xe3, 0x4c, 0xb1, 0xbf, 0xc1, 0xb5, 0xfb, 0x5a, 0xa7, 0x0a, 0xbf, 0x26, 0xaf, 0x2f, 0x2a, 0x24, 0x4e, 0x44, 0x4a, 0x49, 0x93, 0x1a, 0xf9, 0x6b, 0x79, 0xac, 0xaf, 0xc5, 0x3c, 0xcb, 0xca, 0x6e, 0x50, 0x60, 0xa5, 0x3d, 0xf3, 0x78, 0xb3, 0x5c, 0x44, 0xa6, 0xfc, 0xd6, 0x8c, 0xba, 0x8c, 0x1d, 0x48, 0x06, 0x10, 0x9a, 0x88, 0x10, 0x1e, 0xd7, 0xb2, 0xe6, 0xf5, 0xa4, 0xe9, 0x15, 0x09, 0x25, 0xed, 0x35, 0x93, 0x75, 0xb6, 0x5a, 0x92, 0x22, 0x54, 0xd6, 0x78, 0x93, 0x39, 0xef, 0x01, 0x49, 0x92, 0x39, 0x3d, 0x4d, 0xe6, 0x8b, 0xa7, 0x8b, 0x92, 0x5b, 0xb3, 0x1a, 0x48, 0x93, 0xcd, 0x5e, 0xed, 0xad, 0x7b, 0x22, 0x3d, 0xde, 0xcc, 0xdb, 0xb7, 0x7b, 0x6f, 0x24, 0x99, 0x88, 0x0f, 0x6f, 0xe1, 0x66, 0x45, 0x3d, 0x02, 0x74, 0xd2, 0xc4, 0xa1, 0x57, 0x50, 0x8c, 0x95, 0x11, 0x40, 0x2c, 0x45, 0x3c, 0x52, 0x85, 0xfa, 0x6a, 0xb4, 0x21, 0x09, 0x0d, 0x72, 0xaa, 0x10, 0x84, 0x85, 0x56, 0x7f, 0xcc, 0xe0, 0x80, 0x3a, 0x2e, 0x6a, 0xc6, 0x58, 0xe8, 0xe1, 0x9c, 0xbe, 0x6b, 0x38, 0xdb, 0x4a, 0x74, 0x70, 0xdc, 0x0f, 0x5a, 0x2d, 0xd5, 0x16, 0x29, 0xd3, 0xe5, 0xfc, 0xc3, 0x49, 0xb2, 0x34, 0xc3, 0x4d, 0x30, 0xd6, 0x5b, 0x71, 0x86, 0x3d, 0x15, 0x7a, 0x5d, 0xbd, 0xfd, 0x9e, 0xc9, 0x99, 0x3b, 0x7b, 0xbb, 0x79, 0xdb, 0xb6, 0xed, 0x5e, 0x9f, 0x2a, 0x63, 0x5a, 0x2f, 0x25, 0x42, 0x14, 0x42, 0x4a, 0x45, 0x13, 0x74, 0xa3, 0x87, 0xc4, 0x7b, 0x99, 0xfc, 0xdf, 0x6f, 0xa3, 0x7e, 0xfc, 0xb1, 0xbf, 0x7f, 0x33, 0xfe, 0xdf, 0x55, 0xae, 0x7f, 0xdf, 0x53, 0x9b, 0x95, 0x0e, 0x6f, 0x65, 0x21, 0xba, 0x88, 0x1d, 0xc0, 0x58, 0x03, 0x9f, 0x81, 0xcb, 0xd4, 0x60, 0xe2, 0x17, 0x18, 0xbe, 0xa6, 0xa2, 0x41, 0x28, 0x74, 0xd1, 0x6b, 0x4d, 0x09, 0x43, 0xc5, 0x5e, 0x67, 0x2e, 0x2b, 0xf2, 0xa1, 0xe2, 0x65, 0x58, 0xaf, 0x39, 0xb1, 0x43, 0x38, 0xc3, 0x59, 0x8c, 0xe7, 0x3f, 0xfc, 0xe7, 0xe6, 0xad, 0xfd, 0x82, 0x2b, 0xc5, 0xad, 0x7b, 0xde, 0x6a, 0x34, 0xd7, 0xa3, 0x5e, 0xcc, 0x99, 0xef, 0x35, 0x26, 0x67, 0xbd, 0x88, 0xb3, 0x3d, 0xee, 0x66, 0x64, 0x85, 0x53, 0x24, 0xe6, 0x49, 0xc8, 0x79, 0x0f, 0x55, 0xc6, 0x43, 0x20, 0x1f, 0x0a, 0x02, 0xad, 0x88, 0x90, 0x84, 0x56, 0x94, 0x85, 0x55, 0x1b, 0xe3, 0x0c, 0x7a, 0xb7, 0xbe, 0x6b, 0x33, 0x59, 0xd2, 0xd6, 0x77, 0xd9, 0x26, 0xb3, 0xfe, 0x70, 0xb5, 0xbb, 0xc9, 0x5b, 0xff, 0x39, 0x85, 0xbb, 0xdd, 0x51, 0xc9, 0xde, 0x3a, 0x38, 0xb0, 0xcc, 0x1d, 0xc0, 0x4e, 0x4c, 0xe3, 0x5b, 0x62, 0x11, 0xae, 0xbe, 0xa8, 0x86, 0x2f, 0xce, 0xdd, 0x19, 0x02, 0xc5, 0xee, 0xc2, 0x9a, 0x0b, 0x96, 0x95, 0x63, 0x9a, 0xfa, 0x83, 0x88, 0x74, 0x07, 0x1f, 0xd1, 0x02, 0x22, 0x2a, 0x0c, 0x45, 0xcb, 0x42, 0x64, 0x42, 0x41, 0xa7, 0x45, 0x21, 0x44, 0x83, 0x86, 0x03, 0x56, 0x80, 0x31, 0x21, 0x7d, 0x59, 0x10, 0x64, 0x19, 0x39, 0xd6, 0xe9, 0x1e, 0x9c, 0x5c, 0x44, 0xb1, 0x28, 0x39, 0x71, 0x5a, 0x62, 0x78, 0x91, 0x60, 0x7f, 0x2f, 0xff, 0xf0, 0x3d, 0x1c, 0x00, 0x60, 0xe7, 0x67, 0x74, 0xcb, 0x8c, 0x21, 0x40, 0x2c, 0x51, 0x0d, 0x75, 0x88, 0x40, 0x70, 0x38, 0x82, 0x01, 0xc6, 0xba, 0x0e, 0x26, 0x68, 0x56, 0x44, 0x0e, 0x34, 0xe6, 0x2b, 0x13, 0x69, 0x9a, 0x65, 0x85, 0x28, 0x79, 0x10, 0xf0, 0x31, 0x91, 0x61, 0x88, 0x54, 0xa2, 0xaf, 0x41, 0xcf, 0xef, 0x7b, 0xcb, 0xcb, 0xd9, 0x54, 0xca, 0x22, 0x21, 0x40, 0xe2, 0xfa, 0x8a, 0xf2, 0x03, 0x81, 0x72, 0x70, 0x41, 0x9a, 0xd5, 0xdc, 0x8d, 0xf2, 0x76, 0x2e, 0x55, 0xfb, 0xa8, 0x38, 0x6d, 0x70, 0x74, 0x7a, 0x10, 0x54, 0xc5, 0xaa, 0x26, 0xa3, 0x44, 0x0b, 0x00, 0x5f, 0x2c, 0xdc, 0xe0, 0x75, 0x11, 0xde, 0x44, 0x7c, 0xec, 0x44, 0x75, 0x75, 0x43, 0x9a, 0xc5, 0x0f, 0xed, 0xde, 0xed, 0x24, 0xd9, 0x10, 0x62, 0xc8, 0xf8, 0x04, 0x56, 0xec, 0x46, 0x42, 0x96, 0x15, 0xcb, 0x17, 0x5a, 0xc4, 0x38, 0xb1, 0x22, 0xe8, 0xa1, 0x48, 0xc8, 0xe1, 0x92, 0xae, 0x09, 0xd1, 0x34, 0xf3, 0x03, 0x9b, 0xd1, 0xb7, 0x22, 0x05, 0x89, 0x29, 0x0e, 0xb9, 0x11, 0xf1, 0x12, 0x14, 0x01, 0x8c, 0x0c, 0xa9, 0x3c, 0xcc, 0x5e, 0x23, 0xec, 0x28, 0x0a, 0x67, 0x57, 0x36, 0x0e, 0x28, 0x39, 0x22, 0x11, 0x71, 0xda, 0xbf, 0x91, 0x7d, 0xd2, 0x85, 0xd7, 0x0c, 0xc6, 0x01, 0x3d, 0x2b, 0xda, 0xcb, 0x52, 0x23, 0x88, 0x56, 0xec, 0xe8, 0xc6, 0x20, 0x44, 0x4f, 0x8a, 0x14, 0x12, 0x50, 0xc5, 0x12, 0xe4, 0x4c, 0xa4, 0xe7, 0x46, 0x9a, 0x66, 0x72, 0x36, 0xde, 0x8e, 0x7e, 0xc9, 0x50, 0x14, 0xf4, 0x5a, 0x12, 0x55, 0xa1, 0x5d, 0x24, 0x22, 0x82, 0xc9, 0x51, 0xcb, 0xde, 0x02, 0xc0, 0xa7, 0xa2, 0x92, 0x35, 0x44, 0x46, 0x85, 0x11, 0x28, 0x30, 0x51, 0xa4, 0x43, 0x41, 0x85, 0xe0, 0xe0, 0xae, 0xf5, 0x09, 0x06, 0x99, 0x2f, 0x31, 0x99, 0x16, 0xc2, 0xc9, 0xc0, 0xd3, 0xa3, 0x28, 0x43, 0xda, 0xbf, 0x9b, 0xe8, 0x1d, 0xdb, 0xf5, 0xd0, 0x16, 0x60, 0x67, 0x49, 0x10, 0xde, 0x9d, 0x9e, 0x14, 0x8c, 0x51, 0x82, 0xc0, 0xd0, 0xa9, 0x55, 0x18, 0x5a, 0xd5, 0xb2, 0xd2, 0xb9, 0xcd, 0x59, 0x65, 0xcd, 0xd4, 0x08, 0x14, 0x41, 0x83, 0x9c, 0xdd, 0x5d, 0xfa, 0x6b, 0x29, 0x05, 0xcb, 0x52, 0x32, 0x07, 0x06, 0x24, 0xe6, 0xaf, 0xe9, 0x48, 0xa5, 0x45, 0x3a, 0x48, 0x0e, 0x20, 0x5e, 0x70, 0x17, 0xba, 0x75, 0x69, 0x48, 0x47, 0x1d, 0x36, 0x0e, 0x17, 0x11, 0x6e, 0xea, 0x34, 0x63, 0x35, 0x86, 0x92, 0x5b, 0xa6, 0xa9, 0x2c, 0xe8, 0x38, 0x16, 0x02, 0xa5, 0x59, 0xd1, 0x75, 0x7b, 0xde, 0x70, 0x1f, 0xbe, 0x00, 0x3f, 0xfa, 0xfa, 0xce, 0x9a, 0x90, 0x51, 0xe4, 0xea, 0x0c, 0x22, 0x99, 0x57, 0x34, 0x4d, 0x57, 0xa3, 0x8f, 0x86, 0xca, 0x0f, 0xdb, 0x6d, 0x37, 0x50, 0x4a, 0xe5, 0x5b, 0x6a, 0xd8, 0xbf, 0x65, 0xec, 0xd7, 0x2b, 0xb5, 0xff, 0x61, 0xc7, 0xe9, 0x7b, 0xd3, 0x96, 0xcc, 0x9c, 0x5a, 0xb7, 0xed, 0x41, 0x38, 0x73, 0x46, 0x53, 0x75, 0x6b, 0xfd, 0x30, 0xd7, 0x84, 0xaf, 0xd3, 0x32, 0x07, 0x95, 0xfc, 0x73, 0x5a, 0x1b, 0xf9, 0x42, 0x99, 0x03, 0x8e, 0x10, 0xcc, 0xa0, 0xe1, 0xa0, 0xc4, 0x10, 0x8b, 0xf7, 0xe3, 0xdc, 0xf0, 0x7d, 0x71, 0x4e, 0x7e, 0x5d, 0xb4, 0x36, 0x14, 0x28, 0x83, 0x03, 0x00, 0x58, 0x82, 0xc0, 0xfa, 0x7f, 0x39, 0x51, 0x9e, 0x89, 0xbb, 0x20, 0xcd, 0x12, 0x01, 0x3d, 0xaf, 0x50, 0x83, 0x85, 0xe8, 0x8a, 0x05, 0x29, 0xaf, 0x4e, 0xe8, 0x84, 0x31, 0x08, 0x8c, 0x3f, 0xa7, 0x22, 0xf5, 0x88, 0xea, 0x83, 0xba, 0x18, 0x0a, 0xf4, 0x92, 0xa1, 0x44, 0x0e, 0x44, 0x12, 0x6a, 0x0e, 0x90, 0x1c, 0x7a, 0xa0, 0x21, 0xa9, 0xb5, 0xd1, 0x83, 0xba, 0x6d, 0x08, 0x4d, 0xdf, 0x97, 0x35, 0x22, 0x30, 0x72, 0x03, 0xbf, 0x88, 0xc0, 0x72, 0xe0, 0x38, 0x29, 0x9d, 0x34, 0xbd, 0x0a, 0x34, 0xdf, 0x91, 0xf0, 0xa4, 0x53, 0x39, 0x09, 0x2a, 0x30, 0x73, 0xdf, 0x91, 0xc4, 0x00, 0xe5, 0xa7, 0x01, 0x39, 0xf9, 0x11, 0xa0, 0x8a, 0xbe, 0x2f, 0xaa, 0x31, 0x90, 0xcc, 0x31, 0x27, 0xfd, 0x34, 0xb1, 0xcf, 0x01, 0xfd, 0x7f, 0xff, 0xd2, 0x74, 0xa0, 0x1d, 0x4a, 0x4e, 0x59, 0x0e, 0xe9, 0xb4, 0x05, 0x00, 0xe3, 0x44, 0xf8, 0x31, 0x05, 0xd3, 0x8b, 0x21, 0x7e, 0x5c, 0x1c, 0x03, 0xc1, 0x3d, 0x51, 0x14, 0x0a, 0xea, 0x78, 0xa0, 0x31, 0x09, 0x64, 0x1c, 0x12, 0xbe, 0x1b, 0x80, 0xe2, 0x0c, 0x8b, 0x84, 0x85, 0x20, 0xb0, 0x09, 0x18, 0x28, 0xd3, 0xe0, 0xe4, 0x20, 0xe0, 0x4d, 0xf6, 0x9a, 0x07, 0x06, 0x4f, 0x60, 0xe4, 0x46, 0xdf, 0xc6, 0x22, 0xe0, 0xc0, 0x28, 0xe2, 0x32, 0x0d, 0x3f, 0xde, 0x00, 0xe0, 0x92, 0x01, 0x79, 0x54, 0x6e, 0xec, 0xba, 0x02, 0x1a, 0x6c, 0xfc, 0x5f, 0x8b, 0xc0, 0x77, 0x4f, 0x4a, 0x03, 0x61, 0x1b, 0x50, 0x83, 0x84, 0x5f, 0xa3, 0x31, 0x45, 0xc5, 0x81, 0xd4, 0xee, 0x9c, 0xda, 0x48, 0x31, 0xe2, 0x32, 0x8a, 0xe2, 0xd2, 0x5b, 0xb7, 0x68, 0xcb, 0x0d, 0x12, 0xa2, 0x42, 0x14, 0x65, 0xcd, 0x03, 0x83, 0x20, 0x9d, 0x0e, 0x0b, 0x82, 0x96, 0xb4, 0x64, 0xed, 0x34, 0xf9, 0xb5, 0x0d, 0x80, 0xfd, 0xb0, 0x01, 0xd6, 0x62, 0x8d, 0x5d, 0x1d, 0x29, 0xa1, 0x80, 0x66, 0x32, 0x7f, 0xe9, 0xb1, 0x33, 0x17, 0x1a, 0x87, 0x59, 0x72, 0x0a, 0xba, 0x7a, 0x88, 0x92, 0xf1, 0xf8, 0x31, 0x07, 0x40, 0x8f, 0x12, 0xa0, 0x45, 0x3a, 0x88, 0x1c, 0x11, 0x30, 0x72, 0xe4, 0x5a, 0x83, 0x61, 0x3c, 0x4e, 0xaa, 0x00, 0xc9, 0x19, 0xf6, 0xb0, 0x38, 0x07, 0x04, 0x93, 0x46, 0x62, 0x66, 0xb0, 0x2c, 0x08, 0xea, 0x95, 0xc1, 0x3f, 0x48, 0x99, 0x3a, 0x8e, 0xf4, 0xd2, 0xc0, 0xe0, 0xc4, 0x69, 0x34, 0x1e, 0x82, 0x00, 0x30, 0x71, 0x4b, 0xdb, 0x0c, 0x45, 0x29, 0xda, 0x4d, 0xa7, 0xf9, 0xde, 0x74, 0x5c, 0x0b, 0xa4, 0xfc, 0xa6, 0xfc, 0x3d, 0x51, 0xc9, 0xf0, 0xf3, 0x88, 0xcd, 0x4e, 0xd3, 0x60, 0xbb, 0xf3, 0xaa, 0x17, 0xe4, 0xa2, 0xe0, 0x71, 0xf8, 0x8b, 0x5c, 0x86, 0xa8, 0x3b, 0xa7, 0x64, 0x1a, 0x69, 0x8e, 0x01, 0x14, 0x49, 0x41, 0x3c, 0x08, 0xd0, 0x18, 0x07, 0xb9, 0x1c, 0x4e, 0x25, 0xd4, 0x71, 0x80, 0x7d, 0x8f, 0xff, 0x52, 0xdd, 0x36, 0x14, 0xd7, 0x4d, 0x38, 0xba, 0x36, 0x5a, 0x18, 0xa9, 0xd2, 0x91, 0xda, 0x1f, 0xb5, 0x90, 0xa1, 0x71, 0x7f, 0x48, 0x28, 0x19, 0x7a, 0x8c, 0xbc, 0x61, 0xc8, 0x12, 0x7e, 0xae, 0x15, 0x60, 0xc8, 0x4d, 0xe6, 0xea, 0x20, 0xc0, 0x13, 0x75, 0xe9, 0x52, 0xaf, 0x74, 0x3d, 0xd6, 0x6d, 0xa2, 0xba, 0x69, 0x32, 0xa4, 0x77, 0x65, 0x3d, 0x2b, 0x50, 0x75, 0x05, 0xd5, 0xee, 0x1f, 0x55, 0xca, 0xd1, 0xbf, 0x5e, 0x59, 0xbe, 0x06, 0x24, 0xc3, 0xe9, 0xff, 0xeb, 0x20, 0x39, 0x41, 0xda, 0x80, 0x75, 0x07, 0x0d, 0x56, 0x02, 0xe7, 0xaf, 0xa0, 0xcc, 0x8b, 0x4e, 0x65, 0x91, 0x12, 0xc3, 0x49, 0x52, 0xe7, 0x59, 0xa5, 0x01, 0x47, 0x2d, 0x06, 0x14, 0x4e, 0x6a, 0x3a, 0x76, 0x2e, 0xbf, 0xfe, 0xd7, 0xc1, 0x8d, 0xfa, 0xd4, 0x44, 0x27, 0x3e, 0x5a, 0x25, 0xb0, 0xc5, 0x51, 0xd3, 0x54, 0xb2, 0xab, 0xf0, 0x3c, 0x64, 0x01, 0xad, 0xb7, 0x8b, 0x85, 0x63, 0x16, 0x67, 0x95, 0xc0, 0x64, 0x3e, 0xd9, 0x62, 0x14, 0x41, 0x29, 0x6f, 0x5b, 0xc5, 0xba, 0x84, 0xd0, 0xc4, 0x2b, 0x4d, 0x8a, 0x01, 0xd2, 0xe0, 0x0f, 0x76, 0x9a, 0x02, 0x40, 0xed, 0xa1, 0x2e, 0x37, 0x7d, 0x8c, 0xe4, 0xf5, 0x90, 0x15, 0xad, 0x6b, 0x48, 0x10, 0x29, 0x40, 0xb1, 0x01, 0x1d, 0xc3, 0x5c, 0x07, 0x1f, 0x24, 0xab, 0x4a, 0x90, 0x14, 0x82, 0xc0, 0x27, 0x8d, 0x44, 0x18, 0x12, 0x05, 0x1a, 0x24, 0x1c, 0x34, 0xbf, 0x42, 0xbd, 0x3b, 0x15, 0x6d, 0x07, 0x12, 0x0b, 0x9e, 0xac, 0x0c, 0x81, 0xcf, 0xf6, 0x03, 0xd0, 0x40, 0x06, 0x30, 0x20, 0x61, 0x4e, 0x9d, 0x8c, 0xf8, 0x26, 0x84, 0x43, 0x33, 0x74, 0x1c, 0x0b, 0xec, 0xb9, 0x36, 0x41, 0x45, 0x5a, 0x28, 0xb9, 0xcd, 0x3f, 0x9d, 0x2d, 0x80, 0xe9, 0x01, 0xc2, 0xfa, 0x34, 0xde, 0x07, 0x1b, 0x73, 0xc1, 0xb8, 0xcf, 0xa5, 0x23, 0x56, 0xd7, 0x41, 0xc8, 0xf8, 0x14, 0xe7, 0x2a, 0xf0, 0x52, 0x0e, 0x0a, 0x3c, 0x43, 0x7a, 0x8c, 0x4f, 0x89, 0x41, 0xd4, 0x13, 0x7d, 0xa0, 0xe0, 0xc8, 0x89, 0xaa, 0x03, 0xd1, 0x3f, 0x3b, 0xd2, 0x40, 0x71, 0xd6, 0x37, 0x01, 0xfc, 0x05, 0xd3, 0x84, 0x39, 0x09, 0x03, 0x23, 0xa1, 0x1e, 0x9e, 0x19, 0x83, 0x06, 0x41, 0x57, 0x07, 0x0c, 0x09, 0x4f, 0x63, 0xfc, 0x66, 0xb8, 0x38, 0xf2, 0xf0, 0x17, 0x71, 0x3c, 0x32, 0x0a, 0xba, 0x28, 0x81, 0x72, 0x40, 0x5c, 0x35, 0xa9, 0x0b, 0x07, 0x02, 0x6a, 0x12, 0x11, 0xe9, 0xea, 0x0e, 0x01, 0xe0, 0xb8, 0xe8, 0x81, 0xc2, 0x8d, 0x46, 0x42, 0x9c, 0x0f, 0x43, 0xff, 0xff, 0x02, 0x76, 0x22, 0xa9, 0xcd, 0x07, 0x52, 0x3e, 0x0e, 0x04, 0xea, 0xa0, 0xf3, 0xd0, 0x01, 0x83, 0x88, 0x9a, 0xe8, 0xd1, 0x92, 0x03, 0x81, 0x3e, 0xf6, 0x54, 0x5d, 0x58, 0x4d, 0x17, 0x66, 0xc3, 0x10, 0x5c, 0xf0, 0xcc, 0x1c, 0x12, 0x3a, 0xe9, 0x05, 0x80, 0x54, 0xc8, 0xc1, 0xd7, 0xa7, 0xaa, 0xf5, 0xd8, 0x6d, 0x68, 0x8a, 0xba, 0x39, 0xc4, 0x08, 0xc8, 0x2c, 0x07, 0x83, 0x84, 0xf5, 0x79, 0xa8, 0x45, 0xcb, 0x82, 0xc3, 0x83, 0x17, 0xa6, 0x48, 0x48, 0x27, 0xd3, 0xc2, 0xe1, 0x3f, 0x07, 0x04, 0xcc, 0x65, 0xd0, 0xc8, 0x28, 0xc0, 0xe2, 0x40, 0x5c, 0x5b, 0x38, 0x0b, 0xba, 0xbf, 0xa5, 0x72, 0x72, 0xca, 0x8d, 0x1a, 0x21, 0x75, 0x8b, 0x13, 0xf2, 0x99, 0x67, 0x10, 0x51, 0x81, 0x07, 0x15, 0x60, 0x75, 0x58, 0x2a, 0xb6, 0x9e, 0xd3, 0xca, 0x54, 0xc5, 0x8a, 0x41, 0xce, 0x65, 0x24, 0x4d, 0x15, 0x45, 0xd0, 0xc0, 0x5c, 0x0b, 0xcc, 0xb1, 0xb1, 0x8f, 0x20, 0x60, 0x13, 0x34, 0xee, 0x14, 0xbf, 0x5e, 0x77, 0x4d, 0x03, 0xa0, 0x2c, 0x42, 0x6d, 0x2d, 0xa7, 0x97, 0x2f, 0x98, 0xdb, 0x5c, 0x2d, 0xd5, 0xd1, 0x77, 0xa8, 0x2e, 0x5e, 0x73, 0x81, 0x2d, 0xef, 0xb1, 0xa5, 0x38, 0x38, 0xb9, 0x56, 0xec, 0xd6, 0xb7, 0x64, 0x24, 0x41, 0x6a, 0x2a, 0x71, 0x3d, 0x04, 0x5a, 0x28, 0xa9, 0x99, 0xd6, 0x49, 0x01, 0xc4, 0x16, 0x20, 0xe8, 0xa0, 0xe5, 0x63, 0xe8, 0x53, 0xe9, 0x2f, 0x14, 0x03, 0xb8, 0x35, 0xa0, 0x44, 0x82, 0x2f, 0xdb, 0xd8, 0x1b, 0xeb, 0xd0, 0x3c, 0x58, 0x3d, 0x19, 0x16, 0x1d, 0xd7, 0xb5, 0x1b, 0x60, 0x54, 0xaf, 0xfd, 0xb4, 0x38, 0xd7, 0x7a, 0xc2, 0xa0, 0x62, 0x49, 0x2a, 0xf5, 0x61, 0x33, 0xfa, 0x25, 0xa7, 0xbc, 0x16, 0x27, 0x7d, 0xd4, 0x3f, 0x76, 0xba, 0xbf, 0xcc, 0xb3, 0x9d, 0xdc, 0xd9, 0xc3, 0xd5, 0x3e, 0xd2, 0x0b, 0xfc, 0xb6, 0x58, 0xe8, 0x80, 0x52, 0x06, 0x07, 0xb5, 0xfd, 0x15, 0xb1, 0x6e, 0x5e, 0xf4, 0xb3, 0x76, 0x0a, 0xb5, 0xea, 0xfe, 0x4f, 0xd9, 0xe1, 0xc2, 0x76, 0xbb, 0x02, 0xd9, 0x1e, 0x0f, 0x77, 0xab, 0x4f, 0x79, 0xb5, 0x8c, 0xd2, 0xdc, 0x42, 0x27, 0xef, 0xf5, 0x4e, 0x60, 0x31, 0xa9, 0x4d, 0x54, 0x47, 0xf5, 0xdb, 0x4d, 0x25, 0xec, 0xee, 0x7d, 0x56, 0x5b, 0x78, 0x2b, 0xd1, 0x25, 0xc4, 0x75, 0x96, 0xf9, 0xc8, 0x08, 0xce, 0xfb, 0x9f, 0xe2, 0xf3, 0x1f, 0x6d, 0xb5, 0xb6, 0x21, 0x95, 0x01, 0xf4, 0xca, 0x8a, 0x87, 0xbb, 0x20, 0x49, 0x53, 0x2e, 0x5c, 0xa9, 0xa8, 0x5e, 0xc3, 0x74, 0xb4, 0xa9, 0x96, 0xb4, 0x3b, 0xf8, 0x73, 0x05, 0x6b, 0x37, 0x79, 0x4a, 0x78, 0x2f, 0x82, 0x75, 0xd3, 0x2b, 0x03, 0x6a, 0xda, 0x54, 0xc4, 0xfd, 0xd6, 0xff, 0xef, 0x65, 0xe7, 0x17, 0xba, 0xb5, 0x5c, 0xc9, 0xa8, 0x9a, 0x8f, 0x9a, 0x61, 0x8a, 0xce, 0xa7, 0xdc, 0xc0, 0x2f, 0xf4, 0x21, 0x9a, 0xc6, 0x85, 0x43, 0x2c, 0xe0, 0xca, 0x93, 0x69, 0xae, 0x5d, 0x7b, 0xe3, 0x6b, 0x82, 0x71, 0x4a, 0x8a, 0x91, 0xf1, 0x28, 0x3a, 0xbd, 0x05, 0xac, 0x15, 0x22, 0xea, 0x04, 0x0e, 0xc8, 0xa2, 0xee, 0xf4, 0x1c, 0x52, 0x0e, 0x40, 0x15, 0x4d, 0x8b, 0x03, 0xa0, 0x0f, 0xe9, 0x1a, 0x0b, 0x43, 0x61, 0x85, 0x39, 0xa6, 0x41, 0x78, 0x4b, 0x78, 0x88, 0xf6, 0x9c, 0xf5, 0x70, 0x77, 0x02, 0x2c, 0x0f, 0x4f, 0x00, 0x18, 0xd2, 0xc7, 0x08, 0x41, 0xc1, 0x88, 0x4d, 0x40, 0xc7, 0x99, 0x19, 0x1e, 0x9e, 0xf2, 0xd6, 0x02, 0xc7, 0x80, 0xe1, 0x93, 0xf7, 0x91, 0x8c, 0x85, 0x73, 0x1a, 0x5c, 0xfc, 0x22, 0x74, 0xa7, 0xb4, 0xd8, 0x39, 0x18, 0x4b, 0x97, 0x01, 0xe8, 0xc1, 0x3f, 0xa2, 0x07, 0xf5, 0x80, 0x0f, 0xf4, 0x13, 0x35, 0x02, 0xad, 0x7d, 0x20, 0xc0, 0x1c, 0x14, 0xfa, 0x32, 0xef, 0x41, 0xc3, 0x56, 0x19, 0x23, 0x21, 0x62, 0xe7, 0xf2, 0x02, 0xeb, 0x4d, 0x83, 0x8a, 0x41, 0xc3, 0x07, 0x30, 0x73, 0xf4, 0xea, 0x23, 0x40, 0xe0, 0x9d, 0xae, 0x4a, 0x32, 0x05, 0xc4, 0xe9, 0x2f, 0x5d, 0xae, 0xc1, 0xc5, 0x34, 0x51, 0x22, 0xad, 0xc0, 0x75, 0xbc, 0x07, 0x1e, 0xb3, 0x47, 0xb7, 0x54, 0xf8, 0x39, 0xcd, 0x08, 0x3a, 0x80, 0xea, 0x13, 0xb5, 0xc1, 0xcb, 0x84, 0xac, 0x9b, 0x29, 0x0a, 0x34, 0xfa, 0xe4, 0x83, 0x1a, 0x0e, 0x26, 0x90, 0x72, 0xeb, 0x03, 0xa0, 0xd7, 0x23, 0xa1, 0x92, 0xc0, 0xb1, 0x39, 0xd1, 0x03, 0x83, 0x32, 0x78, 0x09, 0xf5, 0x7f, 0x17, 0x37, 0xd5, 0xa2, 0x31, 0xad, 0xa2, 0xe8, 0x48, 0xa3, 0x3e, 0x6f, 0xec, 0x75, 0xb6, 0xb3, 0xf2, 0xcb, 0x9a, 0x0e, 0xe0, 0x48, 0x36, 0x08, 0x23, 0xe4, 0xa9, 0xd8, 0x5b, 0x6b, 0x1b, 0x38, 0xdf, 0xbb, 0xc4, 0x7d, 0x86, 0x53, 0x14, 0x44, 0x47, 0xf5, 0xf5, 0xca, 0x32, 0x17, 0x86, 0x63, 0x43, 0x09, 0xeb, 0x06, 0x93, 0xfa, 0xde, 0x08, 0xb1, 0x0c, 0x5a, 0xf4, 0x26, 0x1b, 0xab, 0x12, 0xd5, 0x6e, 0xd2, 0xcc, 0x56, 0xc3, 0x1f, 0xa6, 0xcd, 0x10, 0x18, 0x1e, 0x25, 0x65, 0xb6, 0xf7, 0x7d, 0x1a, 0x56, 0x95, 0x8b, 0x22, 0xdd, 0x18, 0x74, 0xe1, 0x53, 0xb0, 0x6f, 0xc1, 0x5e, 0xb9, 0xe1, 0x1e, 0x17, 0x37, 0xe5, 0xbe, 0x9f, 0x06, 0xf8, 0xb9, 0x49, 0x09, 0x94, 0xf7, 0xfa, 0x88, 0x40, 0xde, 0x0d, 0xe5, 0xa4, 0xab, 0x82, 0x4f, 0x48, 0x97, 0x8b, 0x45, 0x17, 0x31, 0x4c, 0xd2, 0x81, 0x5a, 0x7b, 0x7d, 0x3a, 0xbb, 0x02, 0x07, 0xfa, 0xf3, 0x1b, 0xcb, 0x56, 0xc5, 0x0a, 0x62, 0x37, 0x6b, 0xab, 0xff, 0xde, 0x61, 0x68, 0x1a, 0x6e, 0xf6, 0xc2, 0xb5, 0x91, 0x20, 0x07, 0x05, 0x6a, 0x6e, 0x6e, 0xd8, 0xa3, 0x9c, 0x80, 0x3c, 0x4e, 0x8c, 0xc6, 0x96, 0xef, 0x73, 0x35, 0x08, 0x26, 0x2a, 0xdb, 0x0c, 0x2f, 0xdb, 0x3d, 0xb3, 0x94, 0xf9, 0x72, 0xe4, 0x25, 0xca, 0x41, 0xa6, 0x66, 0x83, 0x51, 0xfe, 0xf0, 0xb3, 0xd7, 0x0a, 0x40, 0x77, 0x02, 0x7a, 0xa2, 0x18, 0x43, 0x66, 0x22, 0xcb, 0x3a, 0x1c, 0x40, 0x70, 0x26, 0xa7, 0x02, 0x09, 0x7d, 0x46, 0xd2, 0xab, 0x41, 0x83, 0x41, 0x79, 0x1a, 0x30, 0x0f, 0xab, 0x06, 0x0e, 0x18, 0xa0, 0xc0, 0x48, 0x23, 0xf2, 0x06, 0xd0, 0x64, 0xfd, 0xfe, 0x5c, 0xd7, 0xed, 0x2b, 0x53, 0xbb, 0x79, 0x0c, 0x49, 0x71, 0x70, 0x37, 0x34, 0x7b, 0x77, 0xab, 0xa3, 0x80, 0xa6, 0x89, 0xd7, 0x07, 0x8a, 0x80, 0x24, 0x2d, 0x4f, 0x3c, 0xba, 0xe7, 0x4a, 0x35, 0x22, 0x4d, 0x4f, 0x8b, 0xef, 0x10, 0x87, 0xda, 0xdc, 0xe2, 0x00, 0x21, 0x5f, 0xdb, 0xb4, 0xdc, 0x19, 0xba, 0x11, 0x26, 0x9d, 0x53, 0x50, 0x41, 0xad, 0x73, 0x50, 0x85, 0x2f, 0x77, 0x50, 0x65, 0xa3, 0x20, 0x71, 0x35, 0x71, 0x2e, 0xad, 0x8d, 0x6c, 0x17, 0x06, 0x67, 0xaa, 0xdc, 0x5d, 0x6a, 0x6d, 0x49, 0xdd, 0x7f, 0x32, 0xae, 0x8e, 0x04, 0x95, 0xb2, 0x71, 0x7e, 0x2d, 0x0e, 0xc1, 0x70, 0x7f, 0x35, 0x7f, 0x60, 0x73, 0x06, 0x11, 0xf0, 0xa8, 0x7d, 0xb2, 0x87, 0xbf, 0x6d, 0x07, 0xa4, 0x0d, 0x0f, 0x99, 0xc5, 0x3c, 0xe0, 0x66, 0x0e, 0x9d, 0x3f, 0xa6, 0xae, 0xa7, 0x6b, 0x16, 0x47, 0x43, 0x87, 0x3e, 0x17, 0xb6, 0x36, 0x68, 0x71, 0x00, 0x8b, 0x37, 0x83, 0x08, 0x8c, 0x29, 0x2c, 0xd2, 0x46, 0x98, 0x1b, 0x2a, 0xe1, 0x2c, 0x46, 0x31, 0xe0, 0x5b, 0x1c, 0x86, 0xb0, 0x67, 0xd1, 0x7b, 0xe5, 0xe1, 0xa0, 0xa3, 0x5d, 0x04, 0xc3, 0xe1, 0xeb, 0x50, 0x15, 0xbf, 0xfc, 0x8b, 0x66, 0x4a, 0x85, 0x47, 0x69, 0x16, 0x62, 0x2a, 0xff, 0xff, 0x7c, 0xa1, 0x49, 0x5d, 0xde, 0x44, 0x60, 0xe2, 0x0b, 0xba, 0x1a, 0xf2, 0x11, 0x56, 0x36, 0x85, 0x03, 0xe2, 0x9f, 0xe4, 0x24, 0x14, 0xeb, 0xdd, 0xd6, 0x2b, 0x5c, 0x9b, 0x9c, 0x85, 0x72, 0xae, 0x86, 0x74, 0x89, 0x74, 0xfb, 0x6a, 0x0b, 0xee, 0xa3, 0x18, 0xae, 0x47, 0x1c, 0xb0, 0xa6, 0x93, 0x44, 0xcb, 0xd2, 0x51, 0x33, 0xf5, 0x4a, 0x90, 0x58, 0xba, 0xa6, 0x50, 0x48, 0x60, 0xb1, 0x95, 0x4a, 0xc7, 0x3c, 0xd6, 0x99, 0x9f, 0x51, 0xec, 0x61, 0x42, 0xc8, 0x3b, 0xf6, 0xda, 0xc4, 0x4b, 0x53, 0x4b, 0x1c, 0x44, 0x3f, 0x69, 0x2e, 0x79, 0xb6, 0xb6, 0x55, 0xa7, 0x62, 0x9c, 0xd5, 0x14, 0xd5, 0xad, 0x7f, 0x72, 0x89, 0xa0, 0x0c, 0xa2, 0xea, 0xc2, 0x80, 0xd8, 0x3e, 0x11, 0xc4, 0x94, 0x9e, 0x1c, 0x31, 0x18, 0x51, 0xde, 0xf0, 0x70, 0x7e, 0xee, 0x16, 0x95, 0xa9, 0x2b, 0x0a, 0xa2, 0xeb, 0x25, 0xa5, 0x55, 0x11, 0xb1, 0x49, 0xa6, 0xba, 0x4a, 0x48, 0x1c, 0x00, 0xf0, 0xa0, 0x88, 0xf5, 0xbc, 0xc9, 0x6f, 0x70, 0x3d, 0x93, 0xa7, 0x91, 0xd6, 0x3d, 0x03, 0x8f, 0xfe, 0x8b, 0xd6, 0x05, 0xc1, 0x76, 0x96, 0x6e, 0x83, 0xce, 0xff, 0xfb, 0xc3, 0xda, 0xf0, 0xa1, 0x65, 0x97, 0xa2, 0x8b, 0xbf, 0xa5, 0x10, 0x89, 0x02, 0xce, 0x23, 0x2d, 0xb2, 0x55, 0x0e, 0x4f, 0x53, 0x78, 0xdf, 0xf7, 0x3d, 0xab, 0x14, 0xbf, 0xc8, 0x0a, 0xe8, 0xfd, 0x79, 0xb0, 0xa4, 0xa4, 0x1c, 0x41, 0x13, 0x64, 0x46, 0x28, 0x4c, 0xb3, 0x24, 0x02, 0xba, 0x58, 0x50, 0x14, 0xa7, 0x67, 0x35, 0x7e, 0xf2, 0xa2, 0x7b, 0xb6, 0x0c, 0x33, 0xa8, 0x4e, 0xeb, 0xee, 0x74, 0xb6, 0x03, 0xb8, 0x0b, 0x01, 0x71, 0x0d, 0x65, 0x91, 0x7a, 0x0e, 0x05, 0x8f, 0x68, 0x48, 0x96, 0x31, 0xb0, 0x39, 0xcc, 0xd4, 0x41, 0x4c, 0xec, 0xfa, 0x22, 0xbc, 0xb5, 0x09, 0x07, 0x36, 0x77, 0x8b, 0xe0, 0xaf, 0x5f, 0x58, 0xb1, 0xb9, 0x49, 0x4d, 0x3b, 0xca, 0x87, 0xb6, 0x70, 0x92, 0x82, 0xf1, 0xe5, 0xe8, 0xdb, 0x7b, 0x65, 0x2c, 0xd8, 0xf1, 0x84, 0x08, 0x7f, 0x67, 0xf0, 0x40, 0x69, 0x24, 0xd4, 0x6b, 0x53, 0x7c, 0x74, 0x9d, 0xe8, 0x88, 0x2b, 0xab, 0xba, 0x49, 0xc4, 0x34, 0x55, 0x81, 0x60, 0x0b, 0xb3, 0xc2, 0x30, 0x22, 0xa9, 0xee, 0x82, 0x2b, 0x3a, 0x0b, 0x00, 0x5c, 0x6c, 0x95, 0x04, 0xe5, 0xef, 0x46, 0x22, 0x74, 0x98, 0x52, 0x2a, 0xd7, 0x6f, 0x68, 0x11, 0x85, 0x29, 0xfd, 0xbd, 0x28, 0xc8, 0x4f, 0xb6, 0xde, 0x41, 0x13, 0x17, 0x46, 0x46, 0xca, 0x3e, 0x69, 0xd5, 0x3f, 0xde, 0x02, 0x69, 0x86, 0x47, 0xe3, 0xe6, 0x03, 0xb6, 0x7d, 0x00, 0x9f, 0x68, 0xc1, 0x1b, 0xd4, 0xd2, 0xf5, 0x7b, 0x2d, 0x6d, 0xb6, 0x74, 0x09, 0xff, 0x46, 0x5c, 0x87, 0x15, 0x53, 0xd4, 0x1a, 0x30, 0xe0, 0x60, 0x31, 0x0a, 0xf5, 0x03, 0x38, 0x49, 0x0e, 0x6b, 0x9d, 0x12, 0x62, 0xaf, 0xe1, 0x57, 0xd2, 0xb0, 0xb5, 0x86, 0x0f, 0x36, 0x3b, 0x4c, 0xda, 0xcd, 0x46, 0x1b, 0xef, 0x0b, 0x46, 0x07, 0xf6, 0x23, 0x41, 0x42, 0x69, 0xcb, 0x91, 0x07, 0xaf, 0x78, 0xb9, 0x21, 0x20, 0x9c, 0xb5, 0x00, 0x4c, 0x13, 0x35, 0xcf, 0x17, 0x08, 0x62, 0x5e, 0xb6, 0x05, 0xb3, 0xd9, 0x28, 0x78, 0x0c, 0x2f, 0x21, 0x32, 0x21, 0x30, 0xad, 0x4c, 0xb6, 0xa5, 0x56, 0xda, 0xdc, 0x46, 0x4d, 0x3a, 0xa6, 0x2d, 0xcb, 0x94, 0x16, 0x26, 0xc1, 0x75, 0x0b, 0x8a, 0x6f, 0xf4, 0xaa, 0x0d, 0x9d, 0xae, 0xb8, 0xf8, 0x78, 0x3c, 0x5d, 0x4f, 0xd5, 0x35, 0x3a, 0x57, 0xd2, 0x97, 0xce, 0x79, 0x80, 0x24, 0x0e, 0xed, 0x3e, 0x58, 0x39, 0x90, 0x16, 0x00, 0x9d, 0x45, 0x74, 0x65, 0xc0, 0x1c, 0x48, 0x43, 0xc4, 0x7d, 0xe6, 0xf4, 0x9b, 0x5e, 0x61, 0x6a, 0xeb, 0x74, 0xd2, 0xc0, 0x9a, 0x9b, 0x3b, 0xb3, 0x0d, 0x5b, 0xc0, 0x5d, 0x65, 0xba, 0x4a, 0x32, 0x19, 0x02, 0xea, 0x7b, 0x21, 0xbb, 0x1f, 0x8c, 0xce, 0x77, 0x0a, 0x25, 0x8b, 0x83, 0x81, 0x73, 0x41, 0xf7, 0xa1, 0xb1, 0x9b, 0xfe, 0x4f, 0xc1, 0x17, 0x51, 0x9b, 0xe1, 0x28, 0x2d, 0xa2, 0x4a, 0x4b, 0x4d, 0xbc, 0xad, 0x33, 0x4a, 0x27, 0x10, 0xd2, 0x50, 0x1c, 0xb1, 0x36, 0x50, 0x48, 0x65, 0x35, 0xf8, 0x88, 0x28, 0x6b, 0x82, 0xc0, 0x1c, 0x80, 0xa0, 0xfd, 0x5d, 0x17, 0x78, 0x13, 0xeb, 0xcb, 0x5d, 0x85, 0x08, 0x51, 0x92, 0xf4, 0x1c, 0xf4, 0xa4, 0xe2, 0x35, 0x9f, 0x08, 0xa9, 0xa4, 0x08, 0x05, 0x32, 0x6d, 0x16, 0xf1, 0x7b, 0xc1, 0x92, 0xc7, 0xd7, 0x8b, 0x2c, 0x27, 0xdf, 0x4e, 0x9a, 0xe6, 0x54, 0x40, 0xe4, 0x21, 0x5a, 0xf9, 0xc6, 0x24, 0xef, 0x65, 0x07, 0x2e, 0x2b, 0x4d, 0x4f, 0x2a, 0x09, 0x6c, 0xe8, 0xc7, 0x88, 0x05, 0xc7, 0x50, 0xb2, 0xde, 0xa2, 0xa1, 0x80, 0x64, 0x0b, 0xb3, 0x36, 0xcd, 0x26, 0xde, 0x98, 0x8a, 0xe4, 0x84, 0x17, 0x54, 0x2c, 0x54, 0x0e, 0x18, 0x38, 0xa6, 0xb5, 0x0a, 0x46, 0x41, 0x2f, 0x1c, 0x74, 0x80, 0xee, 0xf1, 0x7e, 0x74, 0x29, 0x8b, 0xd4, 0xdd, 0xb5, 0x64, 0x74, 0x17, 0xcf, 0xcf, 0xd8, 0x32, 0x34, 0xf9, 0xfc, 0x58, 0x64, 0xb5, 0x44, 0x0e, 0x34, 0x41, 0x17, 0x15, 0xeb, 0xe0, 0xa3, 0x49, 0x08, 0x3f, 0xe8, 0xc8, 0x8d, 0x5e, 0xde, 0xa2, 0xb5, 0x00, 0x3a, 0x05, 0x78, 0xca, 0x0a, 0xf5, 0xe5, 0x09, 0xb0, 0x5f, 0xea, 0x33, 0x73, 0xce, 0x12, 0xde, 0x89, 0xa2, 0x49, 0x17, 0x5a, 0x70, 0x07, 0xc1, 0x3b, 0xf5, 0x4c, 0x58, 0xf6, 0xbe, 0x51, 0x49, 0x0f, 0xee, 0x8c, 0x11, 0x03, 0x85, 0x5a, 0x29, 0x35, 0xd3, 0x44, 0x4c, 0x63, 0x24, 0x0c, 0xc5, 0x2b, 0x2d, 0x9c, 0x46, 0x50, 0x28, 0xd3, 0x88, 0xc4, 0x34, 0xbb, 0xb0, 0x81, 0x41, 0x3d, 0xcf, 0x22, 0x58, 0x63, 0x43, 0x13, 0xd3, 0x70, 0x64, 0x28, 0xc6, 0xcb, 0x90, 0x6b, 0x9d, 0xd8, 0x38, 0x74, 0xfe, 0xf8, 0xa5, 0x18, 0x0f, 0x08, 0xa3, 0x76, 0x8c, 0xa0, 0xbc, 0x85, 0xc8, 0x2f, 0x0a, 0x16, 0x41, 0xc8, 0x3a, 0x02, 0xe7, 0x5e, 0x03, 0xd2, 0x49, 0xde, 0x53, 0x5c, 0x5c, 0x85, 0xf0, 0xa5, 0x69, 0x10, 0xf4, 0x28, 0x65, 0x48, 0x38, 0x52, 0x11, 0x7b, 0x78, 0x8b, 0x9d, 0x07, 0x04, 0x53, 0x3b, 0xd4, 0x75, 0x41, 0xdd, 0x7c, 0xb1, 0xb4, 0x43, 0x21, 0x33, 0xa0, 0xfd, 0xf0, 0x01, 0xee, 0x5e, 0x23, 0xd0, 0x1e, 0x4c, 0xef, 0x05, 0xe2, 0xe1, 0x47, 0x8b, 0x21, 0x84, 0x1a, 0x7b, 0xa8, 0x14, 0x03, 0x8e, 0xb1, 0x5c, 0xf4, 0x92, 0x42, 0x55, 0x86, 0x92, 0x69, 0x69, 0x42, 0x5b, 0x6a, 0xf1, 0x01, 0x20, 0x4b, 0xa7, 0x0b, 0x03, 0x82, 0x36, 0x8b, 0xa8, 0x0d, 0x10, 0xe1, 0x88, 0x38, 0x62, 0x2e, 0x13, 0xe0, 0x7a, 0x48, 0x00, 0xc6, 0xb3, 0xbd, 0xe8, 0x49, 0xaf, 0xb8, 0xed, 0x3b, 0x10, 0xa2, 0x15, 0x4a, 0xd4, 0x30, 0x7e, 0x9c, 0xe9, 0xb0, 0x58, 0x92, 0x04, 0x8d, 0x2a, 0xc8, 0xcf, 0xe9, 0xcc, 0x8b, 0xa3, 0x0c, 0x89, 0xf5, 0x9c, 0xe5, 0xc5, 0x08, 0xca, 0xd4, 0x95, 0x15, 0x21, 0xe2, 0xc8, 0xc6, 0x93, 0xc2, 0x40, 0x70, 0x62, 0xf7, 0x20, 0x39, 0x60, 0xaa, 0x5a, 0x48, 0x2e, 0x22, 0xd3, 0x47, 0x26, 0x2c, 0xb8, 0xc8, 0x88, 0xaf, 0x11, 0xf0, 0x32, 0x07, 0x02, 0x6c, 0xf1, 0x0f, 0x38, 0x84, 0x1d, 0x5d, 0x96, 0x07, 0x70, 0x1c, 0x2b, 0xb9, 0xc2, 0x50, 0x9b, 0x4e, 0x45, 0xe3, 0x25, 0x8f, 0xee, 0x14, 0x72, 0x2c, 0x68, 0x29, 0x80, 0x46, 0x58, 0xa1, 0x11, 0x20, 0x38, 0x9b, 0x70, 0x90, 0x1c, 0x2e, 0x0c, 0x84, 0xcc, 0x7e, 0x27, 0x2a, 0x16, 0x07, 0x0a, 0x1a, 0x88, 0x0f, 0x41, 0xff, 0xf8, 0x61, 0x44, 0xd8, 0x60, 0x18, 0x85, 0x53, 0x03, 0x20, 0x73, 0xa2, 0x07, 0x6b, 0xee, 0x92, 0xc7, 0x4f, 0x0d, 0xf6, 0xf0, 0x17, 0x1a, 0x59, 0xde, 0x9b, 0x28, 0x07, 0x04, 0xda, 0xca, 0x2b, 0x6a, 0x37, 0x58, 0x6b, 0xaf, 0x83, 0x13, 0x60, 0xe7, 0x6e, 0xc4, 0x48, 0x21, 0x0e, 0x58, 0x92, 0x83, 0x82, 0x78, 0x8b, 0x23, 0x58, 0xd9, 0x0d, 0x24, 0x7d, 0xb9, 0x2c, 0x07, 0x2c, 0x0e, 0x42, 0x09, 0x98, 0xb0, 0xd8, 0x4d, 0x23, 0x10, 0x70, 0xa7, 0x73, 0x86, 0xc6, 0x0b, 0x04, 0x9f, 0xfb, 0x56, 0x29, 0x07, 0x23, 0x8f, 0x98, 0x0e, 0x8f, 0x63, 0x0a, 0x50, 0x76, 0x29, 0x28, 0x26, 0x3c, 0x5f, 0x02, 0xfb, 0x51, 0x9b, 0xb0, 0x61, 0xc0, 0x70, 0xbc, 0x17, 0x29, 0xc0, 0xcc, 0x1d, 0x08, 0x62, 0xca, 0x72, 0xf0, 0xa4, 0xfd, 0x5d, 0x2c, 0x58, 0xd5, 0x5c, 0x1c, 0x2a, 0x4e, 0xf7, 0x0a, 0x01, 0xfa, 0xff, 0xff, 0xd5, 0x09, 0xa8, 0x8c, 0x1c, 0x30, 0x25, 0x09, 0xd3, 0xd9, 0x30, 0xd3, 0xdb, 0x94, 0x13, 0x74, 0xc8, 0x71, 0x1a, 0x21, 0x87, 0x43, 0x10, 0x89, 0x5a, 0x6b, 0x91, 0xd5, 0x66, 0xa0, 0xb0, 0x1c, 0x30, 0x58, 0x64, 0x15, 0xfe, 0x36, 0x04, 0x7b, 0x4d, 0x23, 0x07, 0x3a, 0xf1, 0x0a, 0xc2, 0x7d, 0x3b, 0xa1, 0x91, 0xa4, 0x62, 0x96, 0xb1, 0xae, 0x83, 0xf6, 0xc0, 0x07, 0xae, 0x6c, 0x11, 0x45, 0xf4, 0x1c, 0x35, 0x6a, 0x28, 0x39, 0x60, 0x71, 0x1b, 0xf4, 0x39, 0x44, 0x41, 0xae, 0xf1, 0x07, 0x01, 0xd4, 0x89, 0xf6, 0x94, 0x1f, 0x7d, 0xab, 0x1b, 0x20, 0xdb, 0x22, 0x1e, 0xa2, 0x07, 0x09, 0x8b, 0xe3, 0xf4, 0xda, 0x82, 0x8c, 0x25, 0x01, 0xc0, 0xe2, 0x36, 0x59, 0xa0, 0xe2, 0x42, 0x82, 0x64, 0x78, 0xb0, 0x66, 0x0e, 0x59, 0xdd, 0x63, 0x65, 0x0b, 0x02, 0x6a, 0x8c, 0xc2, 0xad, 0x7a, 0x90, 0xa3, 0xa0, 0xbd, 0xda, 0x53, 0xd9, 0xd5, 0x82, 0x4f, 0x2c, 0x37, 0xd8, 0x50, 0x8c, 0xa0, 0x2a, 0x70, 0x5e, 0x47, 0x4a, 0xa9, 0x28, 0xaf, 0x4f, 0x58, 0x88, 0x31, 0x29, 0x19, 0x76, 0x8c, 0xc8, 0xbf, 0x0d, 0xc1, 0x56, 0xe7, 0x0a, 0x05, 0xe5, 0x20, 0xe8, 0xe6, 0xb0, 0x3b, 0xb7, 0xa0, 0xe1, 0x80, 0xaa, 0xa0, 0x23, 0xd7, 0x74, 0xd5, 0x01, 0xfc, 0x19, 0x85, 0x13, 0x01, 0xc1, 0x91, 0x1b, 0xec, 0x28, 0x80, 0xb1, 0xe2, 0xc7, 0x6a, 0x74, 0x07, 0x2c, 0x31, 0x15, 0xd8, 0xbd, 0xb7, 0x82, 0xe2, 0x1d, 0x3c, 0xa2, 0x83, 0x97, 0x09, 0x3a, 0xc0, 0xb1, 0x34, 0x50, 0x0b, 0x87, 0x6c, 0xc8, 0xa7, 0x6e, 0x64, 0x37, 0xb7, 0x91, 0x1f, 0x09, 0x0a, 0x38, 0x34, 0x8c, 0x97, 0x80, 0xe5, 0x8d, 0x94, 0x0a, 0xd6, 0xe9, 0x24, 0x18, 0xae, 0x34, 0xd7, 0xd2, 0x94, 0x20, 0x36, 0x34, 0x7c, 0x29, 0xe9, 0xb0, 0x71, 0x3e, 0xe2, 0x08, 0x69, 0xde, 0x14, 0x8b, 0xca, 0x01, 0x32, 0x67, 0x64, 0x43, 0x85, 0x07, 0xf4, 0xdf, 0x04, 0xdb, 0x88, 0x38, 0xb0, 0xbc, 0x32, 0x44, 0x14, 0x4f, 0x10, 0xa8, 0x34, 0x89, 0x10, 0x38, 0x28, 0x7c, 0xe2, 0x0a, 0x0e, 0x17, 0x04, 0xae, 0xfd, 0x78, 0x5d, 0x12, 0xdc, 0xde, 0x73, 0x9c, 0x17, 0x85, 0x2f, 0x79, 0xc5, 0xbb, 0x2c, 0x21, 0x6b, 0x92, 0x14, 0x92, 0x9f, 0x9e, 0x0c, 0xd6, 0x20, 0x99, 0x28, 0xae, 0x27, 0x22, 0x6d, 0xd9, 0xc4, 0x41, 0x99, 0xfd, 0x71, 0x42, 0x25, 0x8a, 0x41, 0xd2, 0x1c, 0x60, 0xe3, 0xfa, 0x14, 0x70, 0xa4, 0x8a, 0xaf, 0xa5, 0xd1, 0x90, 0x26, 0x42, 0x2e, 0x53, 0x42, 0xe8, 0x0e, 0x0a, 0x37, 0x27, 0x69, 0x29, 0x21, 0x41, 0x3c, 0xf6, 0xf2, 0x21, 0xe5, 0x07, 0x48, 0x7a, 0x49, 0xd0, 0x5c, 0xe9, 0xc9, 0x25, 0x0c, 0xa7, 0x02, 0xa9, 0x9d, 0x17, 0x8c, 0x85, 0xdd, 0x05, 0xf6, 0x83, 0x31, 0x8f, 0x41, 0xc2, 0xa8, 0x46, 0x0e, 0xa0, 0xe0, 0x5f, 0x3c, 0x19, 0xd1, 0x4e, 0x9e, 0x40, 0x89, 0x60, 0x5e, 0xcf, 0x60, 0x38, 0x07, 0xd4, 0x20, 0xba, 0x7c, 0x28, 0xe8, 0x38, 0x62, 0xe9, 0x25, 0xe1, 0xa1, 0x90, 0x38, 0x9a, 0xac, 0x45, 0xaf, 0xa5, 0x8b, 0x21, 0xea, 0x23, 0x60, 0xe7, 0x68, 0x8c, 0xa3, 0x81, 0x4c, 0xc3, 0x74, 0xd7, 0x03, 0x22, 0x3e, 0xb8, 0xb8, 0x26, 0x64, 0x24, 0xa4, 0xa7, 0xb4, 0xe6, 0x14, 0x12, 0x05, 0x52, 0x0f, 0x45, 0x00, 0x19, 0xfc, 0x0e, 0x0a, 0x34, 0x19, 0x03, 0x81, 0x7f, 0x8d, 0x34, 0xf7, 0x02, 0x39, 0x8b, 0x8b, 0x90, 0x04, 0x52, 0x14, 0xb8, 0xb8, 0x2c, 0x42, 0x58, 0x0b, 0x98, 0x9e, 0x51, 0xc0, 0xc5, 0x68, 0x11, 0xe8, 0x03, 0x81, 0xc0, 0xbf, 0x66, 0x81, 0xd5, 0xd2, 0xb9, 0x41, 0x27, 0x02, 0x63, 0x11, 0xa3, 0x3f, 0x57, 0x9e, 0x73, 0xbc, 0xb1, 0x09, 0x4f, 0x08, 0x37, 0x30, 0x94, 0xe6, 0x93, 0x8b, 0xa3, 0x36, 0x6e, 0x00, 0xe1, 0xae, 0xa8, 0x91, 0x83, 0x8d, 0x12, 0x85, 0x4a, 0x8a, 0x1b, 0x27, 0xd3, 0xd3, 0x88, 0xc3, 0x07, 0xcc, 0x80, 0xe0, 0x5c, 0xcc, 0xea, 0xc1, 0x90, 0x2c, 0x5d, 0x3c, 0xa0, 0xe0, 0x9e, 0xad, 0x62, 0x37, 0xc5, 0xe2, 0xa1, 0x40, 0x84, 0x2b, 0x82, 0xb0, 0x5d, 0x3e, 0x73, 0xbd, 0x07, 0x0b, 0xc2, 0x77, 0x16, 0x25, 0x17, 0x70, 0xd8, 0x38, 0x69, 0x08, 0xb4, 0xcb, 0x0e, 0x05, 0x14, 0x38, 0x27, 0x48, 0xaa, 0xa1, 0x85, 0x10, 0x07, 0xa3, 0x3d, 0x54, 0x66, 0x18, 0x03, 0x8f, 0x1b, 0x3a, 0x4a, 0x27, 0xd7, 0xbb, 0x01, 0xd0, 0xfe, 0xea, 0xf3, 0xa6, 0xf8, 0x43, 0x86, 0x10, 0x1c, 0x76, 0x86, 0x34, 0x62, 0x4a, 0x0b, 0xc4, 0xb9, 0xd3, 0x4e, 0xd7, 0xf9, 0xa0, 0xb1, 0x24, 0x14, 0x50, 0xcf, 0x86, 0x81, 0x3d, 0xe5, 0x42, 0xb7, 0x68, 0x2e, 0xf4, 0x92, 0x14, 0x44, 0x63, 0x2e, 0x1d, 0x7e, 0xaf, 0x42, 0x6d, 0x7f, 0x64, 0x29, 0x0a, 0xb5, 0xec, 0x40, 0x0e, 0x04, 0xef, 0xbd, 0xe7, 0x56, 0x40, 0x0b, 0x0a, 0x79, 0x8c, 0x7b, 0xc0, 0xa7, 0x3d, 0xaf, 0x94, 0xde, 0x21, 0x45, 0xc0, 0xc0, 0x17, 0x33, 0x31, 0x0a, 0xcb, 0x92, 0x03, 0x8f, 0xb5, 0xd0, 0xf7, 0x9d, 0x3b, 0x56, 0x61, 0x21, 0x25, 0x19, 0x82, 0xee, 0xf3, 0x92, 0xa3, 0x76, 0xbd, 0xe7, 0xf6, 0x76, 0xf6, 0xe4, 0xc0, 0x29, 0x81, 0xb5, 0xd0, 0x70, 0xad, 0xff, 0x3c, 0xba, 0xd3, 0x6d, 0x96, 0xf5, 0x10, 0x2f, 0xe3, 0xb3, 0x05, 0xc4, 0x53, 0xdb, 0x61, 0x20, 0x3a, 0x9f, 0x9d, 0x35, 0xca, 0x4f, 0xa6, 0xe2, 0x90, 0x72, 0xdd, 0x09, 0x21, 0x70, 0x7e, 0xe8, 0x00, 0xf2, 0xe0, 0x3d, 0x60, 0x1d, 0x42, 0x5d, 0x20, 0x6d, 0x82, 0xb6, 0xea, 0xe8, 0x04, 0xda, 0xfa, 0x48, 0x8b, 0xb0, 0x96, 0xa0, 0x07, 0x2c, 0x4f, 0xed, 0xbc, 0x5b, 0xa0, 0xe9, 0x05, 0x0f, 0x3a, 0x4a, 0x82, 0x0a, 0xfe, 0x62, 0x13, 0xb1, 0x79, 0xde, 0x8b, 0x88, 0x34, 0xe5, 0x1a, 0x01, 0x70, 0x57, 0x2b, 0x82, 0xc3, 0x91, 0x72, 0x1a, 0xad, 0x62, 0x0e, 0x83, 0x89, 0x57, 0x81, 0x27, 0x50, 0x2f, 0x07, 0x3f, 0x07, 0x23, 0x3f, 0x17, 0xfc, 0xc4, 0x1d, 0xda, 0x18, 0x11, 0x3b, 0x6f, 0x50, 0x62, 0xc2, 0xf4, 0x40, 0x9d, 0xbc, 0x52, 0x88, 0x5c, 0x2b, 0x77, 0x28, 0x6e, 0xb9, 0x20, 0x2e, 0xad, 0x42, 0x68, 0x9f, 0x5e, 0x64, 0xbd, 0x36, 0x53, 0x0a, 0x4a, 0x46, 0x8d, 0x64, 0x2b, 0x22, 0x3b, 0xa6, 0xf5, 0x06, 0x76, 0x12, 0x89, 0xba, 0xc3, 0x24, 0x23, 0x10, 0xc0, 0x87, 0x92, 0xf0, 0xe6, 0xbe, 0x2b, 0x88, 0x6d, 0x34, 0x18, 0x1f, 0x95, 0x89, 0x01, 0x7b, 0xed, 0x07, 0x20, 0x0c, 0x44, 0xdb, 0x69, 0xae, 0x12, 0x20, 0x20, 0x8b, 0x40, 0x9e, 0x2c, 0x4f, 0x10, 0x9b, 0x5c, 0x24, 0x79, 0x78, 0x85, 0x12, 0x31, 0x98, 0x56, 0xf6, 0xde, 0xa2, 0xb4, 0x66, 0x43, 0x54, 0xa9, 0x76, 0xbc, 0xf0, 0x1c, 0x45, 0xba, 0x1a, 0x21, 0x28, 0x07, 0x3f, 0x81, 0x1e, 0x83, 0x06, 0x5d, 0x0c, 0x89, 0xa7, 0x94, 0x93, 0x80, 0xbd, 0xe9, 0xa0, 0xc3, 0xa0, 0x3c, 0xee, 0x9c, 0xf2, 0x12, 0x03, 0x85, 0x4f, 0x80, 0xea, 0x7a, 0xa2, 0xc8, 0x10, 0xae, 0x8c, 0x82, 0x46, 0x28, 0xc1, 0xc2, 0xf0, 0x77, 0x48, 0x69, 0xae, 0x48, 0x2b, 0xab, 0xe4, 0x0b, 0x5e, 0xa3, 0x91, 0x61, 0x5e, 0x5c, 0xda, 0x34, 0x44, 0xbd, 0xa4, 0x0d, 0x7e, 0x50, 0x73, 0xba, 0xf4, 0x1f, 0xbf, 0xff, 0xff, 0x6a, 0x20, 0xa6, 0x27, 0xf9, 0xc0, 0x7a, 0x0f, 0xff, 0xcf, 0xf5, 0xd1, 0xae, 0x15, 0x65, 0x28, 0x90, 0x84, 0xd3, 0x0a, 0x2f, 0x06, 0x00, 0xe2, 0x3f, 0x83, 0x4d, 0x3f, 0x10, 0xac, 0x52, 0x0e, 0x3b, 0x81, 0xd1, 0x7e, 0x06, 0x01, 0x14, 0x82, 0x3a, 0x04, 0x02, 0xe4, 0x76, 0x1e, 0xe0, 0xe0, 0x5d, 0x52, 0x95, 0xdd, 0xa7, 0xb8, 0x0b, 0x14, 0x00, 0xe0, 0xc8, 0xeb, 0x58, 0xd8, 0xc4, 0x30, 0x21, 0xe0, 0xf4, 0x30, 0x01, 0x84, 0xf4, 0x31, 0x18, 0x02, 0x7a, 0x94, 0x2c, 0x15, 0xc4, 0xda, 0xc4, 0x78, 0x62, 0x32, 0x8b, 0x42, 0x45, 0x81, 0xc5, 0x24, 0x71, 0x01, 0x74, 0xe0, 0xc8, 0x90, 0x1c, 0x6c, 0x94, 0x4d, 0x48, 0xb4, 0xf4, 0x37, 0x0d, 0x03, 0x89, 0x0f, 0x38, 0x67, 0x60, 0x3f, 0xbc, 0x00, 0x6c, 0x5e, 0x0e, 0x41, 0x4d, 0x85, 0x76, 0x02, 0xef, 0x5e, 0x41, 0xcb, 0xd0, 0x70, 0x64, 0x85, 0x62, 0x79, 0xd1, 0x80, 0xb8, 0x1c, 0x27, 0x70, 0x1f, 0xdf, 0xff, 0xf7, 0x20, 0xa3, 0x25, 0x22, 0xd3, 0x8b, 0x9e, 0x02, 0x1e, 0x5c, 0x1c, 0x11, 0xae, 0xa3, 0x3a, 0xb7, 0xb2, 0x8b, 0xab, 0xe0, 0xb1, 0x12, 0xf0, 0x1c, 0x2e, 0x0a, 0x12, 0xbc, 0x95, 0x0f, 0x6a, 0x09, 0x2f, 0x45, 0xeb, 0x40, 0x1c, 0x43, 0xcd, 0x59, 0x0b, 0xe2, 0x6a, 0x5f, 0x43, 0x4a, 0x09, 0x54, 0xd3, 0x62, 0x9f, 0x65, 0x88, 0x94, 0x8c, 0xaa, 0xc2, 0xfa, 0xfe, 0x55, 0x2c, 0xe7, 0x82, 0xad, 0x6d, 0x41, 0xcc, 0x19, 0x22, 0xe0, 0xa7, 0x31, 0x53, 0x91, 0x03, 0xf5, 0x17, 0xfe, 0x2e, 0x29, 0x26, 0x4c, 0xb1, 0xb9, 0x2f, 0x5b, 0x80, 0x8c, 0xb8, 0x61, 0x41, 0x77, 0x41, 0xef, 0x11, 0xd4, 0x06, 0x86, 0x24, 0x5e, 0x44, 0x2b, 0x8c, 0xd1, 0x14, 0x93, 0x32, 0xfc, 0x5b, 0x51, 0x0a, 0xb4, 0xe5, 0x64, 0x3c, 0xb4, 0xd8, 0x39, 0x18, 0x51, 0x48, 0x41, 0xcb, 0x70, 0x9f, 0x70, 0x32, 0x40, 0x15, 0x4a, 0x88, 0x0e, 0x46, 0x19, 0x84, 0x70, 0xd2, 0xe7, 0xf5, 0xe7, 0x81, 0xaa, 0xe7, 0xdf, 0xe8, 0x69, 0x25, 0x36, 0x48, 0x0e, 0x42, 0x14, 0x4d, 0xa6, 0xf2, 0x92, 0xac, 0x49, 0xd2, 0x66, 0x85, 0x01, 0x28, 0xb8, 0x13, 0x19, 0x6b, 0x78, 0x2e, 0x7e, 0xbf, 0xf8, 0x13, 0xee, 0x50, 0x71, 0xcf, 0x20, 0x7f, 0x20, 0x30, 0x2c, 0x34, 0x13, 0x5b, 0xb2, 0x31, 0x8a, 0xe2, 0xf7, 0x34, 0x83, 0x31, 0xa6, 0xbe, 0x99, 0x56, 0x1b, 0x6b, 0xb4, 0xa8, 0xf9, 0xca, 0x31, 0x1a, 0x39, 0x50, 0x2c, 0x0e, 0x90, 0x1c, 0x73, 0xdc, 0x9d, 0x5d, 0x6e, 0x22, 0xa6, 0x90, 0x9e, 0x5a, 0xb2, 0x0e, 0x13, 0x45, 0xe7, 0xb3, 0xa0, 0xc4, 0xcf, 0xbd, 0x43, 0x4d, 0x83, 0x06, 0x50, 0xe5, 0x81, 0x6e, 0x00, 0xee, 0x00, 0xe8, 0xe9, 0xb8, 0x52, 0x41, 0xec, 0x1b, 0x51, 0x75, 0x80, 0x99, 0x57, 0xd1, 0x75, 0xd0, 0x94, 0x12, 0x0b, 0x89, 0xfc, 0x17, 0x44, 0x25, 0x20, 0xb9, 0x53, 0x79, 0x67, 0x3b, 0xf5, 0x22, 0x26, 0x69, 0x25, 0x42, 0xe5, 0x71, 0x9c, 0xa1, 0xd0, 0x31, 0x5f, 0x6c, 0x9b, 0x56, 0x35, 0x41, 0x71, 0x0b, 0x64, 0xe0, 0x8a, 0x2b, 0xd3, 0xd7, 0x41, 0x63, 0x00, 0x79, 0xdd, 0xd9, 0x2a, 0xe8, 0x51, 0x10, 0x40, 0x22, 0x7d, 0x0b, 0x3b, 0xe2, 0x45, 0xe8, 0xbf, 0x54, 0xf4, 0x60, 0xb0, 0xa5, 0x29, 0xe5, 0x11, 0x0d, 0x29, 0xab, 0xde, 0xa2, 0x45, 0x20, 0x2f, 0xea, 0xc8, 0xfa, 0x2e, 0x7e, 0x9c, 0x95, 0x12, 0x84, 0xae, 0x23, 0x07, 0x09, 0x93, 0x24, 0x09, 0x38, 0x3b, 0x86, 0x81, 0x35, 0x84, 0xda, 0xfb, 0x92, 0x2f, 0x10, 0x83, 0x82, 0x2e, 0xba, 0x10, 0xc8, 0xa4, 0x22, 0xdd, 0x07, 0x0d, 0x1f, 0x0d, 0xd9, 0xd0, 0x4d, 0xd7, 0x21, 0xd7, 0x98, 0x03, 0x81, 0x60, 0x7d, 0xd5, 0xe7, 0x21, 0x42, 0xe7, 0xe6, 0xa0, 0xab, 0x83, 0x82, 0x7d, 0xc8, 0x32, 0xe5, 0x07, 0x3e, 0x14, 0x9d, 0xd3, 0xf3, 0xa4, 0xa3, 0x10, 0xca, 0x83, 0x8e, 0xa6, 0xb1, 0x4a, 0xc4, 0xed, 0x74, 0x7d, 0x07, 0x02, 0xeb, 0xc3, 0x17, 0x9c, 0xa8, 0xc2, 0x4a, 0x9f, 0x5c, 0x5c, 0x69, 0x01, 0x36, 0x9d, 0xa4, 0xa0, 0xf3, 0xff, 0xff, 0xa0, 0x39, 0x32, 0x52, 0x45, 0x91, 0x2f, 0xc0, 0x9f, 0x06, 0x60, 0xe2, 0x5a, 0x77, 0x0a, 0x3f, 0x89, 0x24, 0x28, 0x5c, 0x22, 0xac, 0xc5, 0xf8, 0xb7, 0x6c, 0x40, 0x33, 0x7d, 0x58, 0x89, 0x72, 0x69, 0xea, 0xc0, 0xe1, 0x91, 0x1f, 0x57, 0xd9, 0x99, 0x27, 0x17, 0x47, 0x7a, 0x88, 0x26, 0xdb, 0xa6, 0xe5, 0xe4, 0x01, 0xe2, 0xa9, 0x0c, 0x05, 0x3b, 0x90, 0xda, 0x3e, 0x2c, 0x2b, 0x7e, 0x77, 0xa4, 0x7a, 0x73, 0xc8, 0x1c, 0x59, 0x0a, 0x41, 0x3f, 0x16, 0x61, 0x47, 0x01, 0xc4, 0xb3, 0x80, 0xba, 0xd3, 0x4d, 0x86, 0x21, 0x80, 0x52, 0xfa, 0x48, 0x8d, 0x10, 0xc4, 0x17, 0xd2, 0xf5, 0x14, 0x0a, 0xe2, 0x7d, 0x46, 0x54, 0x4b, 0x0c, 0x0d, 0x05, 0x58, 0xb0, 0x95, 0x4f, 0x50, 0x83, 0x91, 0x05, 0x39, 0x10, 0x39, 0x10, 0x38, 0x8f, 0x1b, 0xbc, 0x85, 0x01, 0x88, 0xd3, 0xb4, 0x13, 0xb5, 0xe5, 0x74, 0x4b, 0x03, 0x91, 0x10, 0x31, 0x8c, 0x0a, 0x25, 0x72, 0x5b, 0x06, 0x70, 0x9e, 0x51, 0x53, 0x55, 0x19, 0x28, 0x38, 0xa0, 0x8f, 0x83, 0x64, 0x21, 0x5e, 0xbb, 0x19, 0xcd, 0x18, 0x06, 0x20, 0xe3, 0xf3, 0x16, 0xe8, 0x38, 0x22, 0xd0, 0x12, 0x62, 0xac, 0x6c, 0x1d, 0x11, 0x9d, 0xbd, 0x28, 0x84, 0xfa, 0xfa, 0x95, 0x77, 0xa0, 0x3a, 0x86, 0x48, 0xa9, 0xa0, 0x8e, 0x2c, 0x50, 0x8f, 0xbc, 0x01, 0xc0, 0xb0, 0x05, 0xcc, 0xd5, 0x90, 0x41, 0x70, 0x4e, 0x9a, 0xeb, 0x22, 0x07, 0x14, 0x82, 0xeb, 0xe0, 0x9f, 0x4e, 0x2c, 0x07, 0xea, 0x80, 0x0d, 0x12, 0xc2, 0x81, 0x98, 0x38, 0x56, 0x99, 0x60, 0x38, 0x27, 0xa5, 0x00, 0xf3, 0xff, 0xff, 0x91, 0x99, 0x54, 0x8c, 0x4d, 0x9f, 0xab, 0xdd, 0x51, 0x57, 0x5c, 0x90, 0x60, 0xb1, 0xef, 0xca, 0x2b, 0xc0, 0xe2, 0x2a, 0x58, 0x94, 0xf1, 0x4a, 0x22, 0xc8, 0x5d, 0xdf, 0x50, 0x49, 0x46, 0x68, 0xc6, 0x51, 0xd1, 0x7b, 0x03, 0x00, 0x4d, 0xa5, 0x14, 0x1d, 0x51, 0x05, 0x4f, 0x8b, 0x76, 0x86, 0x6b, 0x03, 0x81, 0x3b, 0xd3, 0xb5, 0x1a, 0xa7, 0xb6, 0xce, 0x20, 0x9c, 0x5e, 0x2c, 0x6c, 0x86, 0x79, 0xc3, 0x64, 0x9d, 0x3f, 0xb8, 0x6c, 0x1c, 0x42, 0xd6, 0x5a, 0x76, 0x0a, 0x2a, 0x32, 0x3d, 0x77, 0x79, 0xc4, 0x16, 0x12, 0xd0, 0xa7, 0x41, 0x80, 0xaf, 0x76, 0x20, 0xec, 0x07, 0x05, 0x1f, 0x11, 0x85, 0x1c, 0xa8, 0x02, 0x8d, 0x7c, 0x0e, 0x21, 0x75, 0x4f, 0x60, 0x3a, 0xa2, 0x27, 0x9d, 0x06, 0x0c, 0x8d, 0x0a, 0xd9, 0x22, 0xf5, 0x4d, 0x07, 0x50, 0x4c, 0xed, 0xe2, 0x30, 0xcc, 0x07, 0xbb, 0x4f, 0x0c, 0xd1, 0x14, 0x83, 0x83, 0x3e, 0x0d, 0x67, 0x94, 0x62, 0x0e, 0x17, 0xf5, 0x00, 0xd1, 0xf0, 0x1c, 0xfd, 0x62, 0x04, 0x24, 0x18, 0x51, 0x53, 0xfc, 0x28, 0x07, 0x0d, 0x77, 0x03, 0x31, 0x5e, 0x51, 0xc8, 0x0e, 0x0a, 0xda, 0xd5, 0x0f, 0x16, 0x58, 0x1d, 0xc0, 0x71, 0xc6, 0x8b, 0x22, 0xc4, 0x66, 0xc2, 0x3d, 0x77, 0x6c, 0xd2, 0x47, 0x65, 0x15, 0x0f, 0x41, 0xc3, 0x31, 0x3f, 0xec, 0x36, 0x0b, 0xc7, 0x3b, 0x57, 0x44, 0x52, 0x6e, 0x8a, 0xa7, 0x37, 0x95, 0x6a, 0x09, 0x95, 0x37, 0xc4, 0x3c, 0x81, 0x98, 0x3a, 0x04, 0x9f, 0x8b, 0x1a, 0x19, 0x83, 0x83, 0x11, 0x35, 0x03, 0x90, 0x50, 0x72, 0x12, 0x39, 0xb0, 0xdf, 0x41, 0xc4, 0x71, 0x4a, 0x12, 0x6d, 0x3e, 0x58, 0xb8, 0xc9, 0x08, 0x2c, 0x20, 0x38, 0xf7, 0x58, 0xd7, 0x41, 0xc1, 0x3d, 0x70, 0x33, 0x05, 0xd4, 0xa8, 0x58, 0x1c, 0x18, 0xc8, 0x14, 0x77, 0xa2, 0xa8, 0xbf, 0xcb, 0x51, 0x83, 0x8e, 0xc5, 0x29, 0x5c, 0x17, 0x9e, 0xa0, 0x25, 0x44, 0x28, 0x9a, 0x2f, 0xa8, 0x43, 0x0a, 0x7a, 0xd8, 0x8f, 0xb6, 0x82, 0x66, 0x9f, 0x5e, 0x0c, 0x0d, 0x03, 0x97, 0x42, 0x8c, 0xf4, 0xf0, 0xda, 0x21, 0x3e, 0x47, 0xc3, 0x64, 0xcc, 0x66, 0x0e, 0x1a, 0x51, 0x5d, 0x5d, 0x3b, 0x8a, 0x0a, 0x0a, 0x62, 0x3e, 0x72, 0x3d, 0xdf, 0x83, 0x90, 0xa0, 0x05, 0xf7, 0xde, 0x45, 0xb8, 0x33, 0xe2, 0xc0, 0xb0, 0x19, 0x91, 0x3c, 0xef, 0x43, 0x75, 0xa2, 0x33, 0x6b, 0xf0, 0x33, 0x7e, 0x56, 0x28, 0xd3, 0xab, 0xd4, 0x52, 0x90, 0xfe, 0x21, 0x40, 0x52, 0xe8, 0x9e, 0xe7, 0x22, 0x00, 0xd5, 0x4d, 0x06, 0x09, 0xe7, 0x90, 0x16, 0x3c, 0xe1, 0x42, 0x10, 0xc0, 0x69, 0x10, 0x71, 0xd1, 0x3d, 0x27, 0x79, 0x08, 0xda, 0x81, 0x9a, 0x30, 0x72, 0x30, 0x4d, 0x72, 0x2e, 0x83, 0x9c, 0x07, 0x06, 0x42, 0xbd, 0xcb, 0xd2, 0x2e, 0x74, 0x51, 0xa7, 0xd4, 0x53, 0x70, 0x63, 0xc0, 0x70, 0x49, 0xb9, 0x06, 0x66, 0xd0, 0x02, 0xc4, 0x17, 0x9b, 0x84, 0x88, 0xc3, 0x30, 0x70, 0x55, 0xb8, 0x0e, 0x5c, 0x1c, 0x32, 0x09, 0x90, 0xe5, 0x5e, 0x6d, 0x01, 0xc4, 0x7d, 0x0a, 0xfd, 0x46, 0x48, 0x48, 0xb3, 0xb7, 0x06, 0x4b, 0x8c, 0x10, 0x03, 0x9f, 0xba, 0x2e, 0x46, 0x19, 0xbe, 0xf5, 0x1a, 0xc7, 0xb4, 0xe0, 0x65, 0x02, 0x7c, 0x30, 0x0c, 0x4d, 0x8a, 0x5f, 0x0d, 0x45, 0xca, 0x28, 0x4b, 0x2b, 0x03, 0xa0, 0x30, 0x2c, 0x42, 0x5c, 0xe6, 0x9e, 0x28, 0x82, 0xe0, 0x5c, 0xbe, 0xa3, 0x96, 0x06, 0x61, 0x2c, 0x40, 0x1d, 0xd2, 0x17, 0xc5, 0xc1, 0xc3, 0x5e, 0xce, 0x1a, 0xe0, 0xaf, 0x4f, 0x0c, 0xba, 0x19, 0x06, 0x40, 0x3c, 0x6b, 0xe7, 0x57, 0x58, 0xd4, 0x07, 0x1b, 0x14, 0x27, 0xce, 0x92, 0xc2, 0x94, 0x60, 0xbe, 0x60, 0xe0, 0x9f, 0x44, 0x85, 0xfa, 0xf8, 0xd8, 0x64, 0xa3, 0x80, 0x39, 0x10, 0x55, 0xed, 0x18, 0x9b, 0x0b, 0x32, 0x20, 0x58, 0x02, 0xe7, 0x1b, 0x21, 0xbd, 0x9d, 0xe9, 0x50, 0x26, 0xe9, 0xba, 0x1f, 0xa2, 0xee, 0x14, 0x2e, 0x03, 0xc8, 0xdd, 0x10, 0x4d, 0x66, 0x8c, 0xe9, 0x48, 0x2e, 0x51, 0xe0, 0x26, 0xa9, 0xc6, 0x43, 0x9c, 0x92, 0x20, 0x04, 0xd2, 0xd7, 0x43, 0x27, 0x01, 0x7d, 0xa7, 0x65, 0x7c, 0x0e, 0xb0, 0x11, 0xc2, 0x5b, 0xbf, 0x51, 0x57, 0xc0, 0x46, 0xb1, 0x71, 0x97, 0x5d, 0x62, 0x06, 0x68, 0xdf, 0xba, 0x6c, 0xad, 0x18, 0xc8, 0xe4, 0x28, 0xcc, 0x1b, 0x7b, 0x85, 0x10, 0x31, 0x3f, 0x41, 0xc8, 0x88, 0xb4, 0xde, 0x7f, 0x7e, 0x0c, 0x05, 0x3e, 0xb9, 0xb5, 0x10, 0x6b, 0x2a, 0x1b, 0xe7, 0x54, 0xe6, 0x12, 0x8d, 0xe8, 0x38, 0x62, 0x7b, 0xd2, 0x45, 0xe8, 0x51, 0xf8, 0x8d, 0x71, 0x78, 0x38, 0x62, 0x13, 0xb2, 0xfd, 0x09, 0x62, 0x6c, 0x0d, 0x60, 0x32, 0x1f, 0xb7, 0xfa, 0x53, 0xc8, 0x50, 0xb7, 0x06, 0x92, 0xa3, 0x32, 0xad, 0x38, 0x0e, 0x28, 0x3d, 0x27, 0x9f, 0x20, 0x63, 0xd7, 0xcb, 0xd4, 0x72, 0xf0, 0x90, 0x83, 0x5f, 0x5d, 0x18, 0x92, 0xa3, 0x0d, 0xd7, 0x3d, 0xaa, 0x91, 0x95, 0xe9, 0x48, 0xd1, 0xf4, 0x1f, 0xc2, 0x00, 0x3f, 0x6c, 0x44, 0xba, 0x00, 0x70, 0x72, 0x7e, 0x70, 0x57, 0x53, 0x64, 0x92, 0x0c, 0xcd, 0x92, 0x02, 0xeb, 0xae, 0x50, 0x2a, 0xca, 0x0a, 0x45, 0xc0, 0x3c, 0x1c, 0xee, 0x18, 0x03, 0x90, 0x84, 0x54, 0x35, 0xe8, 0x49, 0xa7, 0x35, 0x12, 0x00, 0x1c, 0x2e, 0x07, 0x3b, 0x49, 0x01, 0xdd, 0x19, 0x83, 0x90, 0x89, 0xa7, 0x85, 0x05, 0x01, 0x1b, 0x17, 0x14, 0x03, 0xb8, 0x0b, 0xe6, 0xc2, 0x9e, 0x94, 0x9c, 0xd3, 0xa0, 0x70, 0x66, 0x43, 0x3c, 0x07, 0x05, 0x49, 0x74, 0xd5, 0xe0, 0xc0, 0x07, 0xae, 0xea, 0x5f, 0xa6, 0xc1, 0xc3, 0x05, 0x85, 0xc2, 0xb8, 0xa4, 0x90, 0x2b, 0x89, 0xb8, 0x0e, 0x42, 0x12, 0x34, 0x46, 0x81, 0xc4, 0xa2, 0x96, 0xb8, 0x64, 0x6e, 0x02, 0xe7, 0xa3, 0x40, 0x32, 0x07, 0x40, 0x5c, 0x3d, 0xed, 0x5f, 0xa1, 0x55, 0x4b, 0xf9, 0x60, 0x70, 0xa2, 0x11, 0xf4, 0x32, 0x73, 0xe5, 0x29, 0x0c, 0x01, 0xc5, 0x03, 0x5b, 0x57, 0x20, 0x89, 0xd8, 0x39, 0x00, 0x39, 0x71, 0x80, 0xd1, 0x8c, 0x49, 0x3a, 0x09, 0xf0, 0xa2, 0x23, 0x07, 0x02, 0xfa, 0x54, 0x78, 0x94, 0x31, 0x13, 0xac, 0x2a, 0x15, 0xd5, 0xe1, 0x17, 0x51, 0x03, 0xa5, 0x3b, 0xa1, 0x2a, 0x37, 0xed, 0xd2, 0xa2, 0x52, 0x42, 0x8a, 0xb1, 0xa2, 0x83, 0xb2, 0xa4, 0xa2, 0x4a, 0x50, 0x8f, 0xa1, 0x80, 0x55, 0x29, 0xd8, 0x9e, 0x50, 0x87, 0xa7, 0x31, 0x50, 0x3b, 0x92, 0x0c, 0x0f, 0xf1, 0x99, 0x48, 0x38, 0x07, 0x22, 0x24, 0x3f, 0xc1, 0xcb, 0x83, 0x81, 0x60, 0x35, 0xc1, 0x75, 0x13, 0xf1, 0x74, 0x43, 0x12, 0x51, 0x98, 0x47, 0x84, 0x52, 0x81, 0x82, 0xc0, 0xe1, 0xac, 0x74, 0x16, 0x04, 0xa1, 0x81, 0xe6, 0x04, 0x83, 0x20, 0x89, 0xd6, 0x42, 0x7f, 0x4d, 0xd1, 0x81, 0x48, 0xa1, 0x46, 0x3f, 0x8c, 0xc5, 0x33, 0x9b, 0xe4, 0x1b, 0x9d, 0x5c, 0x63, 0x90, 0x1c, 0x83, 0xae, 0xc8, 0x51, 0x06, 0x50, 0x32, 0xa0, 0xbf, 0x2d, 0xc0, 0x71, 0x20, 0x38, 0x5c, 0x4a, 0xef, 0xa7, 0xb4, 0xd0, 0xb8, 0x4b, 0x45, 0xc2, 0xf0, 0x4e, 0x65, 0x21, 0x3f, 0x34, 0x8c, 0x1c, 0x4a, 0x0e, 0xeb, 0xe4, 0xa0, 0x1d, 0x46, 0x01, 0x5c, 0xe8, 0x9f, 0x5f, 0x14, 0xa2, 0x37, 0x49, 0x44, 0xcf, 0x9c, 0x18, 0x92, 0xa3, 0x07, 0x09, 0xe6, 0x1b, 0x09, 0x2b, 0x83, 0x10, 0x4c, 0xe2, 0x35, 0x9d, 0x13, 0x92, 0x80, 0x70, 0x66, 0x35, 0x6b, 0x77, 0x84, 0x6c, 0x64, 0xb9, 0xa5, 0x96, 0x13, 0xee, 0x0c, 0x41, 0xc8, 0xfa, 0x13, 0xb5, 0x9d, 0x25, 0x0a, 0x75, 0xde, 0x50, 0x70, 0x2f, 0xa7, 0x56, 0x37, 0x61, 0xb2, 0x42, 0x40, 0xae, 0x68, 0xcc, 0xa5, 0x07, 0x42, 0x4d, 0x0d, 0xad, 0xca, 0x0b, 0xd5, 0xa3, 0x21, 0x36, 0x9e, 0x8a, 0x22, 0xfd, 0x05, 0x88, 0x38, 0x82, 0x4a, 0x28, 0xc1, 0x6e, 0x92, 0xad, 0x43, 0x17, 0x4a, 0x34, 0x60, 0xfe, 0x10, 0x01, 0xe3, 0x75, 0x6e, 0x03, 0x82, 0x4b, 0xdc, 0xa2, 0xbd, 0x77, 0x28, 0x3b, 0xab, 0x77, 0x85, 0x21, 0x3c, 0xc1, 0x9b, 0x9c, 0xb6, 0x76, 0xdb, 0x67, 0x78, 0xb6, 0x5e, 0x21, 0x92, 0xde, 0x11, 0x4a, 0x20, 0x74, 0x08, 0xa4, 0xa1, 0xb8, 0xd3, 0x5e, 0x68, 0xd6, 0x57, 0x85, 0x01, 0x89, 0x0c, 0x5e, 0xa0, 0x07, 0x1a, 0x07, 0x09, 0xf7, 0x11, 0x02, 0xeb, 0x07, 0x1e, 0xd3, 0x46, 0xad, 0x11, 0x94, 0x74, 0x1d, 0xd7, 0x29, 0xc3, 0x62, 0xf7, 0x24, 0x1f, 0x7c, 0x18, 0x38, 0xf8, 0x30, 0xc2, 0x86, 0x12, 0x03, 0x9f, 0xea, 0x66, 0xc1, 0x83, 0x86, 0xc6, 0x5e, 0xa0, 0x39, 0xce, 0x51, 0x44, 0xda, 0xf8, 0x5f, 0x01, 0xc3, 0x4f, 0x61, 0xb5, 0xe8, 0x62, 0x8c, 0xa0, 0x17, 0x57, 0x75, 0x0f, 0x36, 0xf1, 0x65, 0xc8, 0x1c, 0x02, 0x53, 0xab, 0xd0, 0x58, 0xba, 0xf6, 0x44, 0x00, 0x9d, 0xaf, 0x48, 0x22, 0x38, 0x85, 0x09, 0x48, 0x45, 0xe5, 0x28, 0x1a, 0xfb, 0x20, 0x6f, 0x38, 0x32, 0x14, 0x54, 0xb4, 0x63, 0xd0, 0x70, 0xd6, 0x82, 0xef, 0x5d, 0xd1, 0x9f, 0x56, 0x3d, 0xc6, 0x1c, 0xe2, 0x11, 0x5b, 0x46, 0x6a, 0xfd, 0x6e, 0x04, 0xad, 0x62, 0x8c, 0x07, 0x00, 0xe2, 0x32, 0xf8, 0x1c, 0xf0, 0x51, 0x57, 0xc0, 0xe0, 0x1c, 0x2a, 0xf1, 0x07, 0x09, 0xb0, 0xbe, 0x03, 0xb8, 0x09, 0xfd, 0x62, 0x8b, 0x45, 0xe1, 0x5d, 0x07, 0x2c, 0xb0, 0x4f, 0x17, 0xf4, 0x95, 0x00, 0x26, 0xc9, 0x4a, 0x18, 0x13, 0xe2, 0xb4, 0x6b, 0xd0, 0xb1, 0xd4, 0x11, 0x69, 0x69, 0xc2, 0xc8, 0x75, 0xf2, 0xc0, 0xe4, 0x64, 0x1d, 0x71, 0x80, 0xb8, 0x4c, 0xc6, 0x36, 0x3b, 0x64, 0x90, 0x38, 0xb3, 0x56, 0x18, 0x65, 0x08, 0x8c, 0x46, 0xb9, 0xfa, 0xbf, 0x0c, 0xaa, 0xc1, 0x26, 0x90, 0x1e, 0x8f, 0xff, 0xf2, 0x36, 0xba, 0x34, 0x56, 0x54, 0x2b, 0x03, 0x90, 0x9e, 0x9a, 0x31, 0x44, 0x18, 0x11, 0xfb, 0xc8, 0x13, 0x6b, 0xe9, 0x61, 0x24, 0xc4, 0x68, 0x85, 0x33, 0x25, 0x29, 0xa1, 0x15, 0x5d, 0xa4, 0xb2, 0xda, 0x15, 0x7e, 0x62, 0x35, 0x96, 0x20, 0xf3, 0xa4, 0x51, 0x79, 0xb0, 0xa5, 0x1f, 0x20, 0xc7, 0x80, 0x9b, 0xed, 0x24, 0xe2, 0x11, 0xab, 0xe8, 0xcb, 0xa1, 0x54, 0xcc, 0x44, 0x8b, 0x66, 0x76, 0x3a, 0x62, 0x20, 0x4f, 0xd7, 0xe2, 0x29, 0xbe, 0x92, 0x93, 0xb5, 0x90, 0x03, 0xba, 0x27, 0x7d, 0xb0, 0x39, 0x2b, 0xea, 0x31, 0x9f, 0x02, 0x7f, 0x78, 0x50, 0x80, 0x30, 0x3f, 0x68, 0x38, 0x90, 0x5e, 0x73, 0x5f, 0x4e, 0xc5, 0x83, 0x80, 0x58, 0x53, 0x64, 0x0e, 0xf5, 0x75, 0xea, 0xfd, 0x28, 0x01, 0xc2, 0x7d, 0x25, 0x24, 0x18, 0x21, 0x26, 0x63, 0x2e, 0x14, 0x03, 0x89, 0xb0, 0x4b, 0xd7, 0xcb, 0x40, 0x1c, 0x0e, 0x27, 0xf1, 0x0a, 0x25, 0x08, 0xf8, 0x0b, 0x00, 0x96, 0x57, 0x24, 0xb4, 0x1c, 0xbb, 0xf2, 0xc8, 0x90, 0x13, 0xdb, 0xc5, 0xf8, 0x0b, 0x8d, 0x77, 0x68, 0xc5, 0x12, 0x15, 0xd6, 0x58, 0x1c, 0x41, 0x0a, 0x24, 0x17, 0x74, 0x99, 0x86, 0x6e, 0x7b, 0x56, 0x5b, 0x8a, 0x1e, 0xb3, 0xa8, 0xcf, 0x6b, 0xb5, 0x34, 0x66, 0x18, 0x0c, 0x90, 0x0c, 0x0f, 0x6e, 0x12, 0x2e, 0x50, 0x30, 0x15, 0xb8, 0xa5, 0x61, 0xbd, 0xe7, 0x21, 0x0b, 0x51, 0x94, 0xd4, 0xe7, 0x03, 0x00, 0x75, 0x0a, 0xfb, 0xce, 0x9c, 0xab, 0xb2, 0x94, 0x48, 0x17, 0x0c, 0x02, 0x67, 0xc1, 0x91, 0x45, 0xa6, 0xc1, 0x3e, 0x49, 0x62, 0x34, 0x41, 0x33, 0xb4, 0x67, 0xd1, 0x5c, 0x9d, 0xe2, 0xe7, 0x62, 0xee, 0x55, 0x08, 0x81, 0xdc, 0x42, 0x0e, 0x21, 0x85, 0xe4, 0xef, 0x00, 0x78, 0x39, 0x18, 0x55, 0x2b, 0x92, 0xde, 0xf4, 0xd1, 0x48, 0x2e, 0x7c, 0x90, 0x91, 0x6e, 0x83, 0x84, 0xee, 0x4b, 0x16, 0x14, 0x55, 0xf5, 0x45, 0x10, 0x03, 0x9c, 0xe7, 0x0d, 0xf4, 0x90, 0x64, 0x0b, 0x17, 0xcd, 0x84, 0x96, 0x4a, 0xbc, 0x09, 0x37, 0x4a, 0x3a, 0x0f, 0x3d, 0x00, 0x19, 0x34, 0x74, 0x5f, 0x59, 0x41, 0x18, 0x17, 0x33, 0x95, 0x75, 0xe7, 0x14, 0x80, 0xee, 0x84, 0xcc, 0xae, 0x12, 0x80, 0xf2, 0x0d, 0xa4, 0x9d, 0xc9, 0x00, 0x79, 0x03, 0x3b, 0x5f, 0x5b, 0xc4, 0x3d, 0x82, 0xf0, 0x71, 0xf9, 0xb3, 0x88, 0xfb, 0xd0, 0x72, 0x09, 0xd1, 0xa4, 0xe2, 0xc8, 0x33, 0x7a, 0x8d, 0x00, 0x39, 0x08, 0x2e, 0xb5, 0xc0, 0xd4, 0xd7, 0x68, 0x38, 0x17, 0x5a, 0x33, 0xfa, 0xf3, 0x38, 0x83, 0x8b, 0x12, 0x21, 0x39, 0x2b, 0x94, 0xf5, 0x18, 0x38, 0x33, 0x21, 0x9b, 0x41, 0xf1, 0xe0, 0x07, 0xd2, 0x52, 0x59, 0x11, 0x92, 0x92, 0x2f, 0x41, 0xc4, 0x3d, 0x5e, 0x1e, 0xd3, 0x95, 0xc0, 0x71, 0x0c, 0x7a, 0xc5, 0x38, 0x8c, 0x6e, 0xed, 0x31, 0xb0, 0xe2, 0x82, 0x35, 0x09, 0x27, 0x3d, 0xaa, 0x72, 0xdc, 0x43, 0x04, 0x47, 0xc5, 0xa9, 0xb0, 0x9b, 0x7f }; ocproxy-1.60/contrib/apps/shell/000077500000000000000000000000001303453231400166535ustar00rootroot00000000000000ocproxy-1.60/contrib/apps/shell/shell.c000066400000000000000000001032461303453231400201340ustar00rootroot00000000000000/* * Copyright (c) 2001-2003 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #include "shell.h" #include "lwip/opt.h" #if LWIP_NETCONN #include #include #include "lwip/mem.h" #include "lwip/debug.h" #include "lwip/def.h" #include "lwip/api.h" #include "lwip/stats.h" #ifdef WIN32 #define NEWLINE "\r\n" #else /* WIN32 */ #define NEWLINE "\n" #endif /* WIN32 */ /** Define this to 1 if you want to echo back all received characters * (e.g. so they are displayed on a remote telnet) */ #ifndef SHELL_ECHO #define SHELL_ECHO 0 #endif #define BUFSIZE 1024 static unsigned char buffer[BUFSIZE]; struct command { struct netconn *conn; s8_t (* exec)(struct command *); u8_t nargs; char *args[10]; }; #undef IP_HDRINCL #include #include #include #define ESUCCESS 0 #define ESYNTAX -1 #define ETOOFEW -2 #define ETOOMANY -3 #define ECLOSED -4 #define NCONNS 10 static struct netconn *conns[NCONNS]; /* help_msg is split into 2 strings to prevent exceeding the C89 maximum length of 509 per string */ static char help_msg1[] = "Available commands:"NEWLINE"\ open [IP address] [TCP port]: opens a TCP connection to the specified address."NEWLINE"\ lstn [TCP port]: sets up a server on the specified port."NEWLINE"\ acpt [connection #]: waits for an incoming connection request."NEWLINE"\ send [connection #] [message]: sends a message on a TCP connection."NEWLINE"\ udpc [local UDP port] [IP address] [remote port]: opens a UDP \"connection\"."NEWLINE"\ udpl [local UDP port] [IP address] [remote port]: opens a UDP-Lite \"connection\"."NEWLINE""; static char help_msg2[] = "udpn [local UDP port] [IP address] [remote port]: opens a UDP \"connection\" without checksums."NEWLINE"\ udpb [local port] [remote port]: opens a UDP broadcast \"connection\"."NEWLINE"\ usnd [connection #] [message]: sends a message on a UDP connection."NEWLINE"\ recv [connection #]: recieves data on a TCP or UDP connection."NEWLINE"\ clos [connection #]: closes a TCP or UDP connection."NEWLINE"\ stat: prints out lwIP statistics."NEWLINE"\ quit: quits."NEWLINE""; #if LWIP_STATS static char padding_10spaces[] = " "; #define PROTOCOL_STATS (LINK_STATS && ETHARP_STATS && IPFRAG_STATS && IP_STATS && ICMP_STATS && UDP_STATS && TCP_STATS) #if PROTOCOL_STATS static const char* shell_stat_proto_names[] = { #if LINK_STATS "LINK ", #endif #if ETHARP_STATS "ETHARP ", #endif #if IPFRAG_STATS "IP_FRAG ", #endif #if IP_STATS "IP ", #endif #if ICMP_STATS "ICMP ", #endif #if UDP_STATS "UDP ", #endif #if TCP_STATS "TCP ", #endif "last" }; static struct stats_proto* shell_stat_proto_stats[] = { #if LINK_STATS &lwip_stats.link, #endif #if ETHARP_STATS &lwip_stats.etharp, #endif #if IPFRAG_STATS &lwip_stats.ip_frag, #endif #if IP_STATS &lwip_stats.ip, #endif #if ICMP_STATS &lwip_stats.icmp, #endif #if UDP_STATS &lwip_stats.udp, #endif #if TCP_STATS &lwip_stats.tcp, #endif }; const size_t num_protostats = sizeof(shell_stat_proto_stats)/sizeof(struct stats_proto*); static const char *stat_msgs_proto[] = { " * transmitted ", " * received ", " forwarded ", " * dropped ", " * checksum errors ", " * length errors ", " * memory errors ", " routing errors ", " protocol errors ", " option errors ", " * misc errors ", " cache hits " }; #endif /* PROTOCOL_STATS */ #endif /* LWIP_STATS */ /*-----------------------------------------------------------------------------------*/ static void sendstr(const char *str, struct netconn *conn) { netconn_write(conn, (void *)str, strlen(str), NETCONN_NOCOPY); } /*-----------------------------------------------------------------------------------*/ static s8_t com_open(struct command *com) { ip_addr_t ipaddr; u16_t port; int i; err_t err; long tmp; if (ipaddr_aton(com->args[0], &ipaddr) == -1) { sendstr(strerror(errno), com->conn); return ESYNTAX; } tmp = strtol(com->args[1], NULL, 10); if((tmp < 0) || (tmp > 0xffff)) { sendstr("Invalid port number."NEWLINE, com->conn); return ESUCCESS; } port = (u16_t)tmp; /* Find the first unused connection in conns. */ for(i = 0; i < NCONNS && conns[i] != NULL; i++); if (i == NCONNS) { sendstr("No more connections available, sorry."NEWLINE, com->conn); return ESUCCESS; } sendstr("Opening connection to ", com->conn); netconn_write(com->conn, com->args[0], strlen(com->args[0]), NETCONN_COPY); sendstr(":", com->conn); netconn_write(com->conn, com->args[1], strlen(com->args[1]), NETCONN_COPY); sendstr(NEWLINE, com->conn); conns[i] = netconn_new(NETCONN_TCP); if (conns[i] == NULL) { sendstr("Could not create connection identifier (out of memory)."NEWLINE, com->conn); return ESUCCESS; } err = netconn_connect(conns[i], &ipaddr, port); if (err != ERR_OK) { fprintf(stderr, "error %s"NEWLINE, lwip_strerr(err)); sendstr("Could not connect to remote host: ", com->conn); #ifdef LWIP_DEBUG sendstr(lwip_strerr(err), com->conn); #else sendstr("(debugging must be turned on for error message to appear)", com->conn); #endif /* LWIP_DEBUG */ sendstr(NEWLINE, com->conn); netconn_delete(conns[i]); conns[i] = NULL; return ESUCCESS; } sendstr("Opened connection, connection identifier is ", com->conn); snprintf((char *)buffer, sizeof(buffer), "%d"NEWLINE, i); netconn_write(com->conn, buffer, strlen((const char *)buffer), NETCONN_COPY); return ESUCCESS; } /*-----------------------------------------------------------------------------------*/ static s8_t com_lstn(struct command *com) { u16_t port; int i; err_t err; long tmp; tmp = strtol(com->args[0], NULL, 10); if((tmp < 0) || (tmp > 0xffff)) { sendstr("Invalid port number."NEWLINE, com->conn); return ESUCCESS; } port = (u16_t)tmp; /* Find the first unused connection in conns. */ for(i = 0; i < NCONNS && conns[i] != NULL; i++); if (i == NCONNS) { sendstr("No more connections available, sorry."NEWLINE, com->conn); return ESUCCESS; } sendstr("Opening a listening connection on port ", com->conn); netconn_write(com->conn, com->args[0], strlen(com->args[0]), NETCONN_COPY); sendstr(NEWLINE, com->conn); conns[i] = netconn_new(NETCONN_TCP); if (conns[i] == NULL) { sendstr("Could not create connection identifier (out of memory)."NEWLINE, com->conn); return ESUCCESS; } err = netconn_bind(conns[i], IP_ADDR_ANY, port); if (err != ERR_OK) { netconn_delete(conns[i]); conns[i] = NULL; sendstr("Could not bind: ", com->conn); #ifdef LWIP_DEBUG sendstr(lwip_strerr(err), com->conn); #else sendstr("(debugging must be turned on for error message to appear)", com->conn); #endif /* LWIP_DEBUG */ sendstr(NEWLINE, com->conn); return ESUCCESS; } err = netconn_listen(conns[i]); if (err != ERR_OK) { netconn_delete(conns[i]); conns[i] = NULL; sendstr("Could not listen: ", com->conn); #ifdef LWIP_DEBUG sendstr(lwip_strerr(err), com->conn); #else sendstr("(debugging must be turned on for error message to appear)", com->conn); #endif /* LWIP_DEBUG */ sendstr(NEWLINE, com->conn); return ESUCCESS; } sendstr("Opened connection, connection identifier is ", com->conn); snprintf((char *)buffer, sizeof(buffer), "%d"NEWLINE, i); netconn_write(com->conn, buffer, strlen((const char *)buffer), NETCONN_COPY); return ESUCCESS; } /*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/ static s8_t com_clos(struct command *com) { int i; err_t err; i = strtol(com->args[0], NULL, 10); if (i > NCONNS) { sendstr("Connection identifier too high."NEWLINE, com->conn); return ESUCCESS; } if (conns[i] == NULL) { sendstr("Connection identifier not in use."NEWLINE, com->conn); return ESUCCESS; } err = netconn_close(conns[i]); if (err != ERR_OK) { sendstr("Could not close connection: ", com->conn); #ifdef LWIP_DEBUG sendstr(lwip_strerr(err), com->conn); #else sendstr("(debugging must be turned on for error message to appear)", com->conn); #endif /* LWIP_DEBUG */ sendstr(NEWLINE, com->conn); return ESUCCESS; } sendstr("Connection closed."NEWLINE, com->conn); netconn_delete(conns[i]); conns[i] = NULL; return ESUCCESS; } /*-----------------------------------------------------------------------------------*/ static s8_t com_acpt(struct command *com) { int i, j; err_t err; /* Find the first unused connection in conns. */ for(j = 0; j < NCONNS && conns[j] != NULL; j++); if (j == NCONNS) { sendstr("No more connections available, sorry."NEWLINE, com->conn); return ESUCCESS; } i = strtol(com->args[0], NULL, 10); if (i > NCONNS) { sendstr("Connection identifier too high."NEWLINE, com->conn); return ESUCCESS; } if (conns[i] == NULL) { sendstr("Connection identifier not in use."NEWLINE, com->conn); return ESUCCESS; } err = netconn_accept(conns[i], &conns[j]); if (err != ERR_OK) { sendstr("Could not accept connection: ", com->conn); #ifdef LWIP_DEBUG sendstr(lwip_strerr(err), com->conn); #else sendstr("(debugging must be turned on for error message to appear)", com->conn); #endif /* LWIP_DEBUG */ sendstr(NEWLINE, com->conn); return ESUCCESS; } sendstr("Accepted connection, connection identifier for new connection is ", com->conn); snprintf((char *)buffer, sizeof(buffer), "%d"NEWLINE, j); netconn_write(com->conn, buffer, strlen((const char *)buffer), NETCONN_COPY); return ESUCCESS; } /*-----------------------------------------------------------------------------------*/ #if LWIP_STATS static void com_stat_write_mem(struct netconn *conn, struct stats_mem *elem, int i) { u16_t len; char buf[100]; size_t slen; #ifdef LWIP_DEBUG LWIP_UNUSED_ARG(i); slen = strlen(elem->name); netconn_write(conn, elem->name, slen, NETCONN_COPY); #else /* LWIP_DEBUG */ len = (u16_t)sprintf(buf, "%d", i); slen = strlen(buf); netconn_write(conn, buf, slen, NETCONN_COPY); #endif /* LWIP_DEBUG */ if(slen < 10) { netconn_write(conn, padding_10spaces, 10-slen, NETCONN_COPY); } len = (u16_t)sprintf(buf, " * available %"MEM_SIZE_F NEWLINE, elem->avail); netconn_write(conn, buf, len, NETCONN_COPY); len = (u16_t)sprintf(buf, " * used %"MEM_SIZE_F NEWLINE, elem->used); netconn_write(conn, buf, len, NETCONN_COPY); len = (u16_t)sprintf(buf, " * high water mark %"MEM_SIZE_F NEWLINE, elem->max); netconn_write(conn, buf, len, NETCONN_COPY); len = (u16_t)sprintf(buf, " * errors %"STAT_COUNTER_F NEWLINE, elem->err); netconn_write(conn, buf, len, NETCONN_COPY); len = (u16_t)sprintf(buf, " * illegal %"STAT_COUNTER_F NEWLINE, elem->illegal); netconn_write(conn, buf, len, NETCONN_COPY); } static void com_stat_write_sys(struct netconn *conn, struct stats_syselem *elem, const char *name) { u16_t len; char buf[100]; size_t slen = strlen(name); netconn_write(conn, name, slen, NETCONN_COPY); if(slen < 10) { netconn_write(conn, padding_10spaces, 10-slen, NETCONN_COPY); } len = (u16_t)sprintf(buf, " * used %"STAT_COUNTER_F NEWLINE, elem->used); netconn_write(conn, buf, len, NETCONN_COPY); len = (u16_t)sprintf(buf, " * high water mark %"STAT_COUNTER_F NEWLINE, elem->max); netconn_write(conn, buf, len, NETCONN_COPY); len = (u16_t)sprintf(buf, " * errors %"STAT_COUNTER_F NEWLINE, elem->err); netconn_write(conn, buf, len, NETCONN_COPY); } static s8_t com_stat(struct command *com) { #if PROTOCOL_STATS || MEMP_STATS size_t i; #endif /* PROTOCOL_STATS || MEMP_STATS */ #if PROTOCOL_STATS size_t k; char buf[100]; u16_t len; /* protocol stats, @todo: add IGMP */ for(i = 0; i < num_protostats; i++) { size_t s = sizeof(struct stats_proto)/sizeof(STAT_COUNTER); STAT_COUNTER *c = &shell_stat_proto_stats[i]->xmit; LWIP_ASSERT("stats not in sync", s == sizeof(stat_msgs_proto)/sizeof(char*)); netconn_write(com->conn, shell_stat_proto_names[i], strlen(shell_stat_proto_names[i]), NETCONN_COPY); for(k = 0; k < s; k++) { len = (u16_t)sprintf(buf, "%s%"STAT_COUNTER_F NEWLINE, stat_msgs_proto[k], c[k]); netconn_write(com->conn, buf, len, NETCONN_COPY); } } #endif /* PROTOCOL_STATS */ #if MEM_STATS com_stat_write_mem(com->conn, &lwip_stats.mem, -1); #endif /* MEM_STATS */ #if MEMP_STATS for(i = 0; i < MEMP_MAX; i++) { com_stat_write_mem(com->conn, &lwip_stats.memp[i], -1); } #endif /* MEMP_STATS */ #if SYS_STATS com_stat_write_sys(com->conn, &lwip_stats.sys.sem, "SEM "); com_stat_write_sys(com->conn, &lwip_stats.sys.mutex, "MUTEX "); com_stat_write_sys(com->conn, &lwip_stats.sys.sem, "MBOX "); #endif /* SYS_STATS */ return ESUCCESS; } #endif /*-----------------------------------------------------------------------------------*/ static s8_t com_send(struct command *com) { int i; err_t err; size_t len; i = strtol(com->args[0], NULL, 10); if (i > NCONNS) { sendstr("Connection identifier too high."NEWLINE, com->conn); return ESUCCESS; } if (conns[i] == NULL) { sendstr("Connection identifier not in use."NEWLINE, com->conn); return ESUCCESS; } len = strlen(com->args[1]); com->args[1][len] = '\r'; com->args[1][len + 1] = '\n'; com->args[1][len + 2] = 0; err = netconn_write(conns[i], com->args[1], len + 3, NETCONN_COPY); if (err != ERR_OK) { sendstr("Could not send data: ", com->conn); #ifdef LWIP_DEBUG sendstr(lwip_strerr(err), com->conn); #else sendstr("(debugging must be turned on for error message to appear)", com->conn); #endif /* LWIP_DEBUG */ sendstr(NEWLINE, com->conn); return ESUCCESS; } sendstr("Data enqueued for sending."NEWLINE, com->conn); return ESUCCESS; } /*-----------------------------------------------------------------------------------*/ static s8_t com_recv(struct command *com) { int i; err_t err; struct netbuf *buf; u16_t len; i = strtol(com->args[0], NULL, 10); if (i > NCONNS) { sendstr("Connection identifier too high."NEWLINE, com->conn); return ESUCCESS; } if (conns[i] == NULL) { sendstr("Connection identifier not in use."NEWLINE, com->conn); return ESUCCESS; } err = netconn_recv(conns[i], &buf); if (err == ERR_OK) { netbuf_copy(buf, buffer, BUFSIZE); len = netbuf_len(buf); sendstr("Reading from connection:"NEWLINE, com->conn); netconn_write(com->conn, buffer, len, NETCONN_COPY); netbuf_delete(buf); } else { sendstr("EOF."NEWLINE, com->conn); } err = netconn_err(conns[i]); if (err != ERR_OK) { sendstr("Could not receive data: ", com->conn); #ifdef LWIP_DEBUG sendstr(lwip_strerr(err), com->conn); #else sendstr("(debugging must be turned on for error message to appear)", com->conn); #endif /* LWIP_DEBUG */ sendstr(NEWLINE, com->conn); return ESUCCESS; } return ESUCCESS; } /*-----------------------------------------------------------------------------------*/ static s8_t com_udpc(struct command *com) { ip_addr_t ipaddr; u16_t lport, rport; int i; err_t err; long tmp; tmp = strtol(com->args[0], NULL, 10); if((tmp < 0) || (tmp > 0xffff)) { sendstr("Invalid port number."NEWLINE, com->conn); return ESUCCESS; } lport = (u16_t)tmp; if (ipaddr_aton(com->args[1], &ipaddr) == -1) { sendstr(strerror(errno), com->conn); return ESYNTAX; } tmp = strtol(com->args[2], NULL, 10); if((tmp < 0) || (tmp > 0xffff)) { sendstr("Invalid port number."NEWLINE, com->conn); return ESUCCESS; } rport = (u16_t)tmp; /* Find the first unused connection in conns. */ for(i = 0; i < NCONNS && conns[i] != NULL; i++); if (i == NCONNS) { sendstr("No more connections available, sorry."NEWLINE, com->conn); return ESUCCESS; } sendstr("Setting up UDP connection from port ", com->conn); netconn_write(com->conn, com->args[0], strlen(com->args[0]), NETCONN_COPY); sendstr(" to ", com->conn); netconn_write(com->conn, com->args[1], strlen(com->args[1]), NETCONN_COPY); sendstr(":", com->conn); netconn_write(com->conn, com->args[2], strlen(com->args[2]), NETCONN_COPY); sendstr(NEWLINE, com->conn); conns[i] = netconn_new(NETCONN_UDP); if (conns[i] == NULL) { sendstr("Could not create connection identifier (out of memory)."NEWLINE, com->conn); return ESUCCESS; } err = netconn_connect(conns[i], &ipaddr, rport); if (err != ERR_OK) { netconn_delete(conns[i]); conns[i] = NULL; sendstr("Could not connect to remote host: ", com->conn); #ifdef LWIP_DEBUG sendstr(lwip_strerr(err), com->conn); #else sendstr("(debugging must be turned on for error message to appear)", com->conn); #endif /* LWIP_DEBUG */ sendstr(NEWLINE, com->conn); return ESUCCESS; } err = netconn_bind(conns[i], IP_ADDR_ANY, lport); if (err != ERR_OK) { netconn_delete(conns[i]); conns[i] = NULL; sendstr("Could not bind: ", com->conn); #ifdef LWIP_DEBUG sendstr(lwip_strerr(err), com->conn); #else sendstr("(debugging must be turned on for error message to appear)", com->conn); #endif /* LWIP_DEBUG */ sendstr(NEWLINE, com->conn); return ESUCCESS; } sendstr("Connection set up, connection identifier is ", com->conn); snprintf((char *)buffer, sizeof(buffer), "%d"NEWLINE, i); netconn_write(com->conn, buffer, strlen((const char *)buffer), NETCONN_COPY); return ESUCCESS; } /*-----------------------------------------------------------------------------------*/ static s8_t com_udpl(struct command *com) { ip_addr_t ipaddr; u16_t lport, rport; int i; err_t err; long tmp; tmp = strtol(com->args[0], NULL, 10); if((tmp < 0) || (tmp > 0xffff)) { sendstr("Invalid port number."NEWLINE, com->conn); return ESUCCESS; } lport = (u16_t)tmp; if (ipaddr_aton(com->args[1], &ipaddr) == -1) { sendstr(strerror(errno), com->conn); return ESYNTAX; } tmp = strtol(com->args[2], NULL, 10); if((tmp < 0) || (tmp > 0xffff)) { sendstr("Invalid port number."NEWLINE, com->conn); return ESUCCESS; } rport = (u16_t)tmp; /* Find the first unused connection in conns. */ for(i = 0; i < NCONNS && conns[i] != NULL; i++); if (i == NCONNS) { sendstr("No more connections available, sorry."NEWLINE, com->conn); return ESUCCESS; } sendstr("Setting up UDP-Lite connection from port ", com->conn); netconn_write(com->conn, com->args[0], strlen(com->args[0]), NETCONN_COPY); sendstr(" to ", com->conn); netconn_write(com->conn, com->args[1], strlen(com->args[1]), NETCONN_COPY); sendstr(":", com->conn); netconn_write(com->conn, com->args[2], strlen(com->args[2]), NETCONN_COPY); sendstr(NEWLINE, com->conn); conns[i] = netconn_new(NETCONN_UDPLITE); if (conns[i] == NULL) { sendstr("Could not create connection identifier (out of memory)."NEWLINE, com->conn); return ESUCCESS; } err = netconn_connect(conns[i], &ipaddr, rport); if (err != ERR_OK) { netconn_delete(conns[i]); conns[i] = NULL; sendstr("Could not connect to remote host: ", com->conn); #ifdef LWIP_DEBUG sendstr(lwip_strerr(err), com->conn); #else sendstr("(debugging must be turned on for error message to appear)", com->conn); #endif /* LWIP_DEBUG */ sendstr(NEWLINE, com->conn); return ESUCCESS; } err = netconn_bind(conns[i], IP_ADDR_ANY, lport); if (err != ERR_OK) { netconn_delete(conns[i]); conns[i] = NULL; sendstr("Could not bind: ", com->conn); #ifdef LWIP_DEBUG sendstr(lwip_strerr(err), com->conn); #else sendstr("(debugging must be turned on for error message to appear)", com->conn); #endif /* LWIP_DEBUG */ sendstr(NEWLINE, com->conn); return ESUCCESS; } sendstr("Connection set up, connection identifier is ", com->conn); snprintf((char *)buffer, sizeof(buffer), "%d"NEWLINE, i); netconn_write(com->conn, buffer, strlen((const char *)buffer), NETCONN_COPY); return ESUCCESS; } /*-----------------------------------------------------------------------------------*/ static s8_t com_udpn(struct command *com) { ip_addr_t ipaddr; u16_t lport, rport; int i; err_t err; long tmp; tmp = strtol(com->args[0], NULL, 10); if((tmp < 0) || (tmp > 0xffff)) { sendstr("Invalid port number."NEWLINE, com->conn); return ESUCCESS; } lport = (u16_t)tmp; if (ipaddr_aton(com->args[1], &ipaddr) == -1) { sendstr(strerror(errno), com->conn); return ESYNTAX; } tmp = strtol(com->args[2], NULL, 10); if((tmp < 0) || (tmp > 0xffff)) { sendstr("Invalid port number."NEWLINE, com->conn); return ESUCCESS; } rport = (u16_t)tmp; /* Find the first unused connection in conns. */ for(i = 0; i < NCONNS && conns[i] != NULL; i++); if (i == NCONNS) { sendstr("No more connections available, sorry."NEWLINE, com->conn); return ESUCCESS; } sendstr("Setting up UDP connection without checksums from port ", com->conn); netconn_write(com->conn, com->args[0], strlen(com->args[0]), NETCONN_COPY); sendstr(" to ", com->conn); netconn_write(com->conn, com->args[1], strlen(com->args[1]), NETCONN_COPY); sendstr(":", com->conn); netconn_write(com->conn, com->args[2], strlen(com->args[2]), NETCONN_COPY); sendstr(NEWLINE, com->conn); conns[i] = netconn_new(NETCONN_UDPNOCHKSUM); if (conns[i] == NULL) { sendstr("Could not create connection identifier (out of memory)."NEWLINE, com->conn); return ESUCCESS; } err = netconn_connect(conns[i], &ipaddr, rport); if (err != ERR_OK) { netconn_delete(conns[i]); conns[i] = NULL; sendstr("Could not connect to remote host: ", com->conn); #ifdef LWIP_DEBUG sendstr(lwip_strerr(err), com->conn); #else sendstr("(debugging must be turned on for error message to appear)", com->conn); #endif /* LWIP_DEBUG */ sendstr(NEWLINE, com->conn); return ESUCCESS; } err = netconn_bind(conns[i], IP_ADDR_ANY, lport); if (err != ERR_OK) { netconn_delete(conns[i]); conns[i] = NULL; sendstr("Could not bind: ", com->conn); #ifdef LWIP_DEBUG sendstr(lwip_strerr(err), com->conn); #else sendstr("(debugging must be turned on for error message to appear)", com->conn); #endif /* LWIP_DEBUG */ sendstr(NEWLINE, com->conn); return ESUCCESS; } sendstr("Connection set up, connection identifier is ", com->conn); snprintf((char *)buffer, sizeof(buffer), "%d"NEWLINE, i); netconn_write(com->conn, buffer, strlen((const char *)buffer), NETCONN_COPY); return ESUCCESS; } /*-----------------------------------------------------------------------------------*/ static s8_t com_udpb(struct command *com) { ip_addr_t ipaddr; u16_t lport, rport; int i; err_t err; ip_addr_t bcaddr; long tmp; tmp = strtol(com->args[0], NULL, 10); if((tmp < 0) || (tmp > 0xffff)) { sendstr("Invalid port number."NEWLINE, com->conn); return ESUCCESS; } lport = (u16_t)tmp; if (ipaddr_aton(com->args[1], &ipaddr) == -1) { sendstr(strerror(errno), com->conn); return ESYNTAX; } tmp = strtol(com->args[2], NULL, 10); if((tmp < 0) || (tmp > 0xffff)) { sendstr("Invalid port number."NEWLINE, com->conn); return ESUCCESS; } rport = (u16_t)tmp; /* Find the first unused connection in conns. */ for(i = 0; i < NCONNS && conns[i] != NULL; i++); if (i == NCONNS) { sendstr("No more connections available, sorry."NEWLINE, com->conn); return ESUCCESS; } sendstr("Setting up UDP broadcast connection from port ", com->conn); netconn_write(com->conn, com->args[0], strlen(com->args[0]), NETCONN_COPY); sendstr(" to ", com->conn); netconn_write(com->conn, com->args[1], strlen(com->args[1]), NETCONN_COPY); sendstr(NEWLINE, com->conn); conns[i] = netconn_new(NETCONN_UDP); if (conns[i] == NULL) { sendstr("Could not create connection identifier (out of memory)."NEWLINE, com->conn); return ESUCCESS; } err = netconn_connect(conns[i], &ipaddr, rport); if (err != ERR_OK) { netconn_delete(conns[i]); conns[i] = NULL; sendstr("Could not connect to remote host: ", com->conn); #ifdef LWIP_DEBUG sendstr(lwip_strerr(err), com->conn); #else sendstr("(debugging must be turned on for error message to appear)", com->conn); #endif /* LWIP_DEBUG */ sendstr(NEWLINE, com->conn); return ESUCCESS; } IP4_ADDR(&bcaddr, 255,255,255,255); err = netconn_bind(conns[i], &bcaddr, lport); if (err != ERR_OK) { netconn_delete(conns[i]); conns[i] = NULL; sendstr("Could not bind: ", com->conn); #ifdef LWIP_DEBUG sendstr(lwip_strerr(err), com->conn); #else sendstr("(debugging must be turned on for error message to appear)", com->conn); #endif /* LWIP_DEBUG */ sendstr(NEWLINE, com->conn); return ESUCCESS; } sendstr("Connection set up, connection identifier is ", com->conn); snprintf((char *)buffer, sizeof(buffer), "%d"NEWLINE, i); netconn_write(com->conn, buffer, strlen((const char *)buffer), NETCONN_COPY); return ESUCCESS; } /*-----------------------------------------------------------------------------------*/ static s8_t com_usnd(struct command *com) { long i; err_t err; struct netbuf *buf; char *mem; u16_t len; size_t tmp; i = strtol(com->args[0], NULL, 10); if (i > NCONNS) { sendstr("Connection identifier too high."NEWLINE, com->conn); return ESUCCESS; } if (conns[i] == NULL) { sendstr("Connection identifier not in use."NEWLINE, com->conn); return ESUCCESS; } tmp = strlen(com->args[1]) + 1; if (tmp > 0xffff) { sendstr("Invalid length."NEWLINE, com->conn); return ESUCCESS; } len = (u16_t)tmp; buf = netbuf_new(); mem = (char *)netbuf_alloc(buf, len); if (mem == NULL) { sendstr("Could not allocate memory for sending."NEWLINE, com->conn); return ESUCCESS; } strncpy(mem, com->args[1], len); err = netconn_send(conns[i], buf); netbuf_delete(buf); if (err != ERR_OK) { sendstr("Could not send data: ", com->conn); #ifdef LWIP_DEBUG sendstr(lwip_strerr(err), com->conn); #else sendstr("(debugging must be turned on for error message to appear)", com->conn); #endif /* LWIP_DEBUG */ sendstr(NEWLINE, com->conn); return ESUCCESS; } sendstr("Data sent."NEWLINE, com->conn); return ESUCCESS; } /*-----------------------------------------------------------------------------------*/ static s8_t com_help(struct command *com) { sendstr(help_msg1, com->conn); sendstr(help_msg2, com->conn); return ESUCCESS; } /*-----------------------------------------------------------------------------------*/ static s8_t parse_command(struct command *com, u32_t len) { u16_t i; u16_t bufp; if (strncmp((const char *)buffer, "open", 4) == 0) { com->exec = com_open; com->nargs = 2; } else if (strncmp((const char *)buffer, "lstn", 4) == 0) { com->exec = com_lstn; com->nargs = 1; } else if (strncmp((const char *)buffer, "acpt", 4) == 0) { com->exec = com_acpt; com->nargs = 1; } else if (strncmp((const char *)buffer, "clos", 4) == 0) { com->exec = com_clos; com->nargs = 1; #if LWIP_STATS } else if (strncmp((const char *)buffer, "stat", 4) == 0) { com->exec = com_stat; com->nargs = 0; #endif } else if (strncmp((const char *)buffer, "send", 4) == 0) { com->exec = com_send; com->nargs = 2; } else if (strncmp((const char *)buffer, "recv", 4) == 0) { com->exec = com_recv; com->nargs = 1; } else if (strncmp((const char *)buffer, "udpc", 4) == 0) { com->exec = com_udpc; com->nargs = 3; } else if (strncmp((const char *)buffer, "udpb", 4) == 0) { com->exec = com_udpb; com->nargs = 2; } else if (strncmp((const char *)buffer, "udpl", 4) == 0) { com->exec = com_udpl; com->nargs = 3; } else if (strncmp((const char *)buffer, "udpn", 4) == 0) { com->exec = com_udpn; com->nargs = 3; } else if (strncmp((const char *)buffer, "usnd", 4) == 0) { com->exec = com_usnd; com->nargs = 2; } else if (strncmp((const char *)buffer, "help", 4) == 0) { com->exec = com_help; com->nargs = 0; } else if (strncmp((const char *)buffer, "quit", 4) == 0) { printf("quit"NEWLINE); return ECLOSED; } else { return ESYNTAX; } if (com->nargs == 0) { return ESUCCESS; } bufp = 0; for(; bufp < len && buffer[bufp] != ' '; bufp++); for(i = 0; i < 10; i++) { for(; bufp < len && buffer[bufp] == ' '; bufp++); if (buffer[bufp] == '\r' || buffer[bufp] == '\n') { buffer[bufp] = 0; if (i < com->nargs - 1) { return ETOOFEW; } if (i > com->nargs - 1) { return ETOOMANY; } break; } if (bufp > len) { return ETOOFEW; } com->args[i] = (char *)&buffer[bufp]; for(; bufp < len && buffer[bufp] != ' ' && buffer[bufp] != '\r' && buffer[bufp] != '\n'; bufp++) { if (buffer[bufp] == '\\') { buffer[bufp] = ' '; } } if (bufp > len) { return ESYNTAX; } buffer[bufp] = 0; bufp++; if (i == com->nargs - 1) { break; } } return ESUCCESS; } /*-----------------------------------------------------------------------------------*/ static void shell_error(s8_t err, struct netconn *conn) { switch (err) { case ESYNTAX: sendstr("## Syntax error"NEWLINE, conn); break; case ETOOFEW: sendstr("## Too few arguments to command given"NEWLINE, conn); break; case ETOOMANY: sendstr("## Too many arguments to command given"NEWLINE, conn); break; case ECLOSED: sendstr("## Connection closed"NEWLINE, conn); break; default: /* unknown error, don't assert here */ break; } } /*-----------------------------------------------------------------------------------*/ static void prompt(struct netconn *conn) { sendstr("> ", conn); } /*-----------------------------------------------------------------------------------*/ static void shell_main(struct netconn *conn) { struct pbuf *p; u16_t len = 0, cur_len; struct command com; s8_t err; int i; err_t ret; #if SHELL_ECHO void *echomem; #endif /* SHELL_ECHO */ do { ret = netconn_recv_tcp_pbuf(conn, &p); if (ret == ERR_OK) { pbuf_copy_partial(p, &buffer[len], BUFSIZE - len, 0); cur_len = p->tot_len; len += cur_len; #if SHELL_ECHO echomem = mem_malloc(cur_len); if (echomem != NULL) { pbuf_copy_partial(p, echomem, cur_len, 0); netconn_write(conn, echomem, cur_len, NETCONN_COPY); mem_free(echomem); } #endif /* SHELL_ECHO */ pbuf_free(p); if (((len > 0) && ((buffer[len-1] == '\r') || (buffer[len-1] == '\n'))) || (len >= BUFSIZE)) { if (buffer[0] != 0xff && buffer[1] != 0xfe) { err = parse_command(&com, len); if (err == ESUCCESS) { com.conn = conn; err = com.exec(&com); } if (err == ECLOSED) { printf("Closed"NEWLINE); shell_error(err, conn); goto close; } if (err != ESUCCESS) { shell_error(err, conn); } } else { sendstr(NEWLINE NEWLINE "lwIP simple interactive shell."NEWLINE "(c) Copyright 2001, Swedish Institute of Computer Science."NEWLINE "Written by Adam Dunkels."NEWLINE "For help, try the \"help\" command."NEWLINE, conn); } if (ret == ERR_OK) { prompt(conn); } len = 0; } } } while (ret == ERR_OK); printf("err %s"NEWLINE, lwip_strerr(ret)); close: netconn_close(conn); for(i = 0; i < NCONNS; i++) { if (conns[i] != NULL) { netconn_delete(conns[i]); } conns[i] = NULL; } } /*-----------------------------------------------------------------------------------*/ static void shell_thread(void *arg) { struct netconn *conn, *newconn; err_t err; LWIP_UNUSED_ARG(arg); conn = netconn_new(NETCONN_TCP); netconn_bind(conn, NULL, 23); netconn_listen(conn); while (1) { err = netconn_accept(conn, &newconn); if (err == ERR_OK) { shell_main(newconn); netconn_delete(newconn); } } } /*-----------------------------------------------------------------------------------*/ void shell_init(void) { sys_thread_new("shell_thread", shell_thread, NULL, DEFAULT_THREAD_STACKSIZE, DEFAULT_THREAD_PRIO); } #endif /* LWIP_NETCONN */ ocproxy-1.60/contrib/apps/shell/shell.h000066400000000000000000000032451303453231400201370ustar00rootroot00000000000000/* * Copyright (c) 2001-2003 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #ifndef LWIP_SHELL_H #define LWIP_SHELL_H void shell_init(void); #endif /* LWIP_SHELL_H */ ocproxy-1.60/contrib/apps/smtp/000077500000000000000000000000001303453231400165275ustar00rootroot00000000000000ocproxy-1.60/contrib/apps/smtp/smtp.c000066400000000000000000001175611303453231400176710ustar00rootroot00000000000000/** * @file * SMTP client module * * Author: Simon Goldschmidt * * Example usage: * * void my_smtp_result_fn(void *arg, u8_t smtp_result, u16_t srv_err, err_t err) * { * printf("mail (%p) sent with results: 0x%02x, 0x%04x, 0x%08x\n", arg, * smtp_result, srv_err, err); * } * static void my_smtp_test(void) * { * smtp_set_server_addr("mymailserver.org"); * smtp_set_auth("username", "password"); * smtp_send_mail("recipient", "sender", "subject", "body", my_smtp_result_fn, * some_argument); * } * * When using from any other thread than the tcpip_thread (for NO_SYS==0), use * smtp_send_mail_int()! */ #include "lwip/opt.h" #include "smtp.h" #if LWIP_TCP #include "lwip/sys.h" #include "lwip/sockets.h" #include "lwip/tcp.h" #include "lwip/dns.h" #include /** This is simple SMTP client for raw API. * It is a minimal implementation of SMTP as specified in RFC 5321. * * @todo: * - attachments (the main difficulty here is streaming base64-encoding to * prevent having to allocate a buffer for the whole encoded file at once) * - test with more mail servers... */ /** * SMTP_DEBUG: Enable debugging for SNTP. */ #ifndef SMTP_DEBUG #define SMTP_DEBUG LWIP_DBG_OFF #endif /** Maximum length reserved for server name */ #ifndef SMTP_MAX_SERVERNAME_LEN #define SMTP_MAX_SERVERNAME_LEN 256 #endif /** Maximum length reserved for username */ #ifndef SMTP_MAX_USERNAME_LEN #define SMTP_MAX_USERNAME_LEN 32 #endif /** Maximum length reserved for password */ #ifndef SMTP_MAX_PASS_LEN #define SMTP_MAX_PASS_LEN 32 #endif /** Set this to 0 if you know the authentication data will not change * during the smtp session, which saves some heap space. */ #ifndef SMTP_COPY_AUTHDATA #define SMTP_COPY_AUTHDATA 1 #endif /** Set this to 0 to save some code space if you know for sure that all data * passed to this module conforms to the requirements in the SMTP RFC. * WARNING: use this with care! */ #ifndef SMTP_CHECK_DATA #define SMTP_CHECK_DATA 1 #endif /** Set this to 1 to enable AUTH PLAIN support */ #ifndef SMTP_SUPPORT_AUTH_PLAIN #define SMTP_SUPPORT_AUTH_PLAIN 1 #endif /** Set this to 1 to enable AUTH LOGIN support */ #ifndef SMTP_SUPPORT_AUTH_LOGIN #define SMTP_SUPPORT_AUTH_LOGIN 1 #endif /** TCP poll interval. Unit is 0.5 sec. */ #define SMTP_POLL_INTERVAL 4 /** TCP poll timeout while sending message body, reset after every * successful write. 3 minutes */ #define SMTP_TIMEOUT_DATABLOCK ( 3 * 60 * SMTP_POLL_INTERVAL / 2) /** TCP poll timeout while waiting for confirmation after sending the body. * 10 minutes */ #define SMTP_TIMEOUT_DATATERM (10 * 60 * SMTP_POLL_INTERVAL / 2) /** TCP poll timeout while not sending the body. * This is somewhat lower than the RFC states (5 minutes for initial, MAIL * and RCPT) but still OK for us here. * 2 minutes */ #define SMTP_TIMEOUT ( 2 * 60 * SMTP_POLL_INTERVAL / 2) /* the various debug levels for this file */ #define SMTP_DEBUG_TRACE (SMTP_DEBUG | LWIP_DBG_TRACE) #define SMTP_DEBUG_STATE (SMTP_DEBUG | LWIP_DBG_STATE) #define SMTP_DEBUG_WARN (SMTP_DEBUG | LWIP_DBG_LEVEL_WARNING) #define SMTP_DEBUG_WARN_STATE (SMTP_DEBUG | LWIP_DBG_LEVEL_WARNING | LWIP_DBG_STATE) #define SMTP_DEBUG_SERIOUS (SMTP_DEBUG | LWIP_DBG_LEVEL_SERIOUS) #define SMTP_RX_BUF_LEN 255 #define SMTP_TX_BUF_LEN 255 #define SMTP_CRLF "\r\n" #define SMTP_CRLF_LEN 2 #define SMTP_RESP_220 "220" #define SMTP_RESP_235 "235" #define SMTP_RESP_250 "250" #define SMTP_RESP_334 "334" #define SMTP_RESP_354 "354" #define SMTP_RESP_LOGIN_UNAME "VXNlcm5hbWU6" #define SMTP_RESP_LOGIN_PASS "UGFzc3dvcmQ6" #define SMTP_KEYWORD_AUTH_SP "AUTH " #define SMTP_KEYWORD_AUTH_EQ "AUTH=" #define SMTP_KEYWORD_AUTH_LEN 5 #define SMTP_AUTH_PARAM_PLAIN "PLAIN" #define SMTP_AUTH_PARAM_LOGIN "LOGIN" #define SMTP_CMD_EHLO_1 "EHLO [" #define SMTP_CMD_EHLO_1_LEN 6 #define SMTP_CMD_EHLO_2 "]\r\n" #define SMTP_CMD_EHLO_2_LEN 3 #define SMTP_CMD_AUTHPLAIN_1 "AUTH PLAIN " #define SMTP_CMD_AUTHPLAIN_1_LEN 11 #define SMTP_CMD_AUTHPLAIN_2 "\r\n" #define SMTP_CMD_AUTHPLAIN_2_LEN 2 #define SMTP_CMD_AUTHLOGIN "AUTH LOGIN\r\n" #define SMTP_CMD_AUTHLOGIN_LEN 12 #define SMTP_CMD_MAIL_1 "MAIL FROM: <" #define SMTP_CMD_MAIL_1_LEN 12 #define SMTP_CMD_MAIL_2 ">\r\n" #define SMTP_CMD_MAIL_2_LEN 3 #define SMTP_CMD_RCPT_1 "RCPT TO: <" #define SMTP_CMD_RCPT_1_LEN 10 #define SMTP_CMD_RCPT_2 ">\r\n" #define SMTP_CMD_RCPT_2_LEN 3 #define SMTP_CMD_DATA "DATA\r\n" #define SMTP_CMD_DATA_LEN 6 #define SMTP_CMD_HEADER_1 "From: <" #define SMTP_CMD_HEADER_1_LEN 7 #define SMTP_CMD_HEADER_2 ">\r\nTo: <" #define SMTP_CMD_HEADER_2_LEN 8 #define SMTP_CMD_HEADER_3 ">\r\nSubject: " #define SMTP_CMD_HEADER_3_LEN 12 #define SMTP_CMD_HEADER_4 "\r\n\r\n" #define SMTP_CMD_HEADER_4_LEN 4 #define SMTP_CMD_BODY_FINISHED "\r\n.\r\n" #define SMTP_CMD_BODY_FINISHED_LEN 5 #define SMTP_CMD_QUIT "QUIT\r\n" #define SMTP_CMD_QUIT_LEN 6 #if SMTP_STAT_TX_BUF_MAX #define SMTP_TX_BUF_MAX(len) LWIP_MACRO(if((len) > smtp_tx_buf_len_max) smtp_tx_buf_len_max = (len);) #else /* SMTP_STAT_TX_BUF_MAX */ #define SMTP_TX_BUF_MAX(len) #endif /* SMTP_STAT_TX_BUF_MAX */ #if SMTP_COPY_AUTHDATA #define SMTP_USERNAME(session) (session)->username #define SMTP_PASS(session) (session)->pass #define SMTP_AUTH_PLAIN_DATA(session) (session)->auth_plain #define SMTP_AUTH_PLAIN_LEN(session) (session)->auth_plain_len #else /* SMTP_COPY_AUTHDATA */ #define SMTP_USERNAME(session) smtp_username #define SMTP_PASS(session) smtp_pass #define SMTP_AUTH_PLAIN_DATA(session) smtp_auth_plain #define SMTP_AUTH_PLAIN_LEN(session) smtp_auth_plain_len #endif /* SMTP_COPY_AUTHDATA */ /** State for SMTP client state machine */ enum smtp_session_state { SMTP_NULL, SMTP_HELO, SMTP_AUTH_PLAIN, SMTP_AUTH_LOGIN_UNAME, SMTP_AUTH_LOGIN_PASS, SMTP_AUTH_LOGIN, SMTP_MAIL, SMTP_RCPT, SMTP_DATA, SMTP_BODY, SMTP_QUIT, SMTP_CLOSED }; #ifdef LWIP_DEBUG /** State-to-string table for debugging */ const char *smtp_state_str[] = { "SMTP_NULL", "SMTP_HELO", "SMTP_AUTH_PLAIN", "SMTP_AUTH_LOGIN_UNAME", "SMTP_AUTH_LOGIN_PASS", "SMTP_AUTH_LOGIN", "SMTP_MAIL", "SMTP_RCPT", "SMTP_DATA", "SMTP_BODY", "SMTP_QUIT", "SMTP_CLOSED", }; const char *smtp_result_strs[] = { "SMTP_RESULT_OK", "SMTP_RESULT_ERR_UNKNOWN", "SMTP_RESULT_ERR_CONNECT", "SMTP_RESULT_ERR_HOSTNAME", "SMTP_RESULT_ERR_CLOSED", "SMTP_RESULT_ERR_TIMEOUT", "SMTP_RESULT_ERR_SVR_RESP", }; #endif /* LWIP_DEBUG */ /** struct keeping the body and state of an smtp session */ struct smtp_session { /** keeping the state of the smtp session */ enum smtp_session_state state; /** timeout handling, if this reaches 0, the connection is closed */ u16_t timer; /** helper buffer for transmit, not used for sending body */ char tx_buf[SMTP_TX_BUF_LEN + 1]; struct pbuf* p; /** source email address */ const char* from; /** size of the sourceemail address */ u16_t from_len; /** target email address */ const char* to; /** size of the target email address */ u16_t to_len; /** subject of the email */ const char *subject; /** length of the subject string */ u16_t subject_len; /** this is the body of the mail to be sent */ const char* body; /** this is the length of the body to be sent */ u16_t body_len; /** amount of data from body already sent */ u16_t body_sent; /** callback function to call when closed */ smtp_result_fn callback_fn; /** argument for callback function */ void *callback_arg; #if SMTP_COPY_AUTHDATA /** Username to use for this request */ char *username; /** Password to use for this request */ char *pass; /** Username and password combined as necessary for PLAIN authentication */ char auth_plain[SMTP_MAX_USERNAME_LEN + SMTP_MAX_PASS_LEN + 3]; /** Length of smtp_auth_plain string (cannot use strlen since it includes \0) */ size_t auth_plain_len; #endif /* SMTP_COPY_AUTHDATA */ }; /** IP address or DNS name of the server to use for next SMTP request */ static char smtp_server[SMTP_MAX_SERVERNAME_LEN + 1]; /** TCP port of the server to use for next SMTP request */ static u16_t smtp_server_port = SMTP_DEFAULT_PORT; /** Username to use for the next SMTP request */ static char *smtp_username; /** Password to use for the next SMTP request */ static char *smtp_pass; /** Username and password combined as necessary for PLAIN authentication */ static char smtp_auth_plain[SMTP_MAX_USERNAME_LEN + SMTP_MAX_PASS_LEN + 3]; /** Length of smtp_auth_plain string (cannot use strlen since it includes \0) */ static size_t smtp_auth_plain_len; static size_t max_tx_buf_len; static size_t max_rx_buf_len; static err_t smtp_verify(const char *data, size_t data_len, u8_t linebreaks_allowed); static err_t smtp_tcp_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err); static void smtp_tcp_err(void *arg, err_t err); static err_t smtp_tcp_poll(void *arg, struct tcp_pcb *pcb); static err_t smtp_tcp_sent(void *arg, struct tcp_pcb *pcb, u16_t len); static err_t smtp_tcp_connected(void *arg, struct tcp_pcb *pcb, err_t err); static void smtp_dns_found(const char* hostname, ip_addr_t *ipaddr, void *arg); static size_t smtp_base64_encode(char* target, size_t target_len, const char* source, size_t source_len); static enum smtp_session_state smtp_prepare_mail(struct smtp_session *s, u16_t *tx_buf_len); static void smtp_send_body(struct smtp_session *s, struct tcp_pcb *pcb); static void smtp_process(void *arg, struct tcp_pcb *pcb, struct pbuf *p); #ifdef LWIP_DEBUG /** Convert an smtp result to a string */ const char* smtp_result_str(u8_t smtp_result) { if (smtp_result > SMTP_RESULT_ERR_SVR_RESP) { return "UNKNOWN"; } return smtp_result_strs[smtp_result]; } /** Null-terminates the payload of p for printing out messages. * WARNING: use this only if p is not needed any more as the last byte of * payload is deleted! */ static char* smtp_pbuf_str(struct pbuf* p) { if ((p == NULL) || (p->len == 0)) { return ""; } ((char*)p->payload)[p->len] = 0; return p->payload; } #endif /* LWIP_DEBUG */ /** Set IP address or DNS name for next SMTP connection * * @param server IP address (in ASCII representation) or DNS name of the server */ void smtp_set_server_addr(const char* server) { size_t len = 0; if (server != NULL) { len = strlen(server); } if (len > SMTP_MAX_SERVERNAME_LEN) { len = SMTP_MAX_SERVERNAME_LEN; } memcpy(smtp_server, server, len); } /** Set TCP port for next SMTP connection * * @param port TCP port */ void smtp_set_server_port(u16_t port) { smtp_server_port = port; } /** Set authentication parameters for next SMTP connection * * @param username login name as passed to the server * @param pass password passed to the server together with username */ err_t smtp_set_auth(const char* username, const char* pass) { size_t uname_len = 0; size_t pass_len = 0; memset(smtp_auth_plain, 0xfa, 64); if (username != NULL) { uname_len = strlen(username); if (uname_len > SMTP_MAX_USERNAME_LEN) { LWIP_DEBUGF(SMTP_DEBUG_SERIOUS, ("Username is too long, %d instead of %d\n", (int)uname_len, SMTP_MAX_USERNAME_LEN)); return ERR_ARG; } } if (pass != NULL) { #if SMTP_SUPPORT_AUTH_LOGIN || SMTP_SUPPORT_AUTH_PLAIN pass_len = strlen(pass); if (pass_len > SMTP_MAX_PASS_LEN) { LWIP_DEBUGF(SMTP_DEBUG_SERIOUS, ("Password is too long, %d instead of %d\n", (int)uname_len, SMTP_MAX_USERNAME_LEN)); return ERR_ARG; } #else /* SMTP_SUPPORT_AUTH_LOGIN || SMTP_SUPPORT_AUTH_PLAIN */ LWIP_DEBUGF(SMTP_DEBUG_WARN, ("Password not supported as no authentication methods are activated\n")); #endif /* SMTP_SUPPORT_AUTH_LOGIN || SMTP_SUPPORT_AUTH_PLAIN */ } *smtp_auth_plain = 0; if (username != NULL) { smtp_username = smtp_auth_plain + 1; strcpy(smtp_username, username); } if (pass != NULL) { smtp_pass = smtp_auth_plain + uname_len + 2; strcpy(smtp_pass, pass); } smtp_auth_plain_len = uname_len + pass_len + 2; return ERR_OK; } /** The actual mail-sending function, called by smtp_send_mail and * smtp_send_mail_static after setting up the struct smtp_session. */ static err_t smtp_send_mail_alloced(struct smtp_session *s) { err_t err; struct tcp_pcb* pcb; ip_addr_t addr; LWIP_ASSERT("no smtp_session supplied", s != NULL); #if SMTP_CHECK_DATA /* check that body conforms to RFC: * - convert all single-CR or -LF in body to CRLF * - only 7-bit ASCII is allowed */ if (smtp_verify(s->to, s->to_len, 0) != ERR_OK) { return ERR_ARG; } if (smtp_verify(s->from, s->from_len, 0) != ERR_OK) { return ERR_ARG; } if (smtp_verify(s->subject, s->subject_len, 0) != ERR_OK) { return ERR_ARG; } if (smtp_verify(s->body, s->body_len, 0) != ERR_OK) { return ERR_ARG; } #endif /* SMTP_CHECK_DATA */ pcb = tcp_new(); if (pcb == NULL) { err = ERR_MEM; goto leave; } #if SMTP_COPY_AUTHDATA /* copy auth data, ensuring the first byte is always zero */ memcpy(s->auth_plain + 1, smtp_auth_plain + 1, smtp_auth_plain_len - 1); s->auth_plain_len = smtp_auth_plain_len; /* default username and pass is empty string */ s->username = s->auth_plain; s->pass = s->auth_plain; if (smtp_username != NULL) { s->username += smtp_username - smtp_auth_plain; } if (smtp_pass != NULL) { s->pass += smtp_pass - smtp_auth_plain; } #endif /* SMTP_COPY_AUTHDATA */ s->state = SMTP_NULL; s->timer = SMTP_TIMEOUT; tcp_arg(pcb, s); tcp_recv(pcb, smtp_tcp_recv); tcp_err(pcb, smtp_tcp_err); tcp_poll(pcb, smtp_tcp_poll, SMTP_POLL_INTERVAL); tcp_sent(pcb, smtp_tcp_sent); #if LWIP_DNS err = dns_gethostbyname(smtp_server, &addr, smtp_dns_found, pcb); #else /* LWIP_DNS */ addr.addr = ipaddr_addr(smtp_server); err = addr.addr == IPADDR_NONE ? ERR_ARG : ERR_OK; #endif /* LWIP_DNS */ if (err == ERR_OK) { err = tcp_connect(pcb, &addr, smtp_server_port, smtp_tcp_connected); if (err != ERR_OK) { LWIP_DEBUGF(SMTP_DEBUG_WARN_STATE, ("tcp_connect failed: %d\n", (int)err)); goto deallocate_and_leave; } } else if (err != ERR_INPROGRESS) { LWIP_DEBUGF(SMTP_DEBUG_WARN_STATE, ("dns_gethostbyname failed: %d\n", (int)err)); goto deallocate_and_leave; } return ERR_OK; deallocate_and_leave: if (pcb != NULL) { tcp_arg(pcb, NULL); tcp_close(pcb); } leave: mem_free(s); /* no need to call the callback here since we return != ERR_OK */ return err; } /** Send an email via the currently selected server, username and password. * * @param from source email address (must be NULL-terminated) * @param to target email address (must be NULL-terminated) * @param subject email subject (must be NULL-terminated) * @param body email body (must be NULL-terminated) * @param * @returns - ERR_OK if structures were allocated and no error occured starting the connection * (this does not mean the email has been successfully sent!) * - another err_t on error. */ err_t smtp_send_mail(const char* from, const char* to, const char* subject, const char* body, smtp_result_fn callback_fn, void* callback_arg) { struct smtp_session* s; size_t from_len = strlen(from); size_t to_len = strlen(to); size_t subject_len = strlen(subject); size_t body_len = strlen(body); size_t mem_len = sizeof(struct smtp_session); mem_len += from_len + to_len + subject_len + body_len + 4; if (mem_len > 0xffff) { /* too long! */ return ERR_MEM; } /* Allocate memory to keep this email's session state */ s = (struct smtp_session *)mem_malloc((mem_size_t)mem_len); if (s == NULL) { return ERR_MEM; } /* initialize the structure */ memset(s, 0, mem_len); s->from = (char*)s + sizeof(struct smtp_session); s->from_len = (u16_t)from_len; s->to = s->from + from_len + 1; s->to_len = (u16_t)to_len; s->subject = s->to + to_len + 1; s->subject_len = (u16_t)subject_len; s->body = s->subject + subject_len + 1; s->body_len = (u16_t)body_len; /* copy source and target email address */ memcpy((char*)s->from, from, from_len + 1); memcpy((char*)s->to, to, to_len + 1); memcpy((char*)s->subject, subject, subject_len + 1); memcpy((char*)s->body, body, body_len + 1); s->callback_fn = callback_fn; s->callback_arg = callback_arg; /* call the actual implementation of this function */ return smtp_send_mail_alloced(s); } /** Same as smtp_send_mail, but doesn't copy from, to, subject and body into * an internal buffer to save memory. * WARNING: the above data must stay untouched until the callback function is * called (unless the function returns != ERR_OK) */ err_t smtp_send_mail_static(const char *from, const char* to, const char* subject, const char* body, smtp_result_fn callback_fn, void* callback_arg) { struct smtp_session* s; size_t len; s = mem_malloc(sizeof(struct smtp_session)); if (s == NULL) { return ERR_MEM; } memset(s, 0, sizeof(struct smtp_session)); /* initialize the structure */ s->from = from; len = strlen(from); LWIP_ASSERT("string is too long", len <= 0xffff); s->from_len = (u16_t)len; s->to = to; len = strlen(to); LWIP_ASSERT("string is too long", len <= 0xffff); s->to_len = (u16_t)len; s->subject = subject; len = strlen(subject); LWIP_ASSERT("string is too long", len <= 0xffff); s->subject_len = (u16_t)len; s->body = body; len = strlen(body); LWIP_ASSERT("string is too long", len <= 0xffff); s->body_len = (u16_t)len; s->callback_fn = callback_fn; s->callback_arg = callback_arg; /* call the actual implementation of this function */ return smtp_send_mail_alloced(s); } /** Same as smpt_send_mail but takes a struct smtp_send_request as single * parameter which contains all the other parameters. * To be used with tcpip_callback to send mail from interrupt context or from * another thread. * * WARNING: server and authentication must stay untouched until this function has run! * * Usage example: * - allocate a struct smtp_send_request (in a way that is allowed in interrupt context) * - fill the members of the struct as if calling smtp_send_mail * - specify a callback_function * - set callback_arg to the structure itself * - call this function * - wait for the callback function to be called * - in the callback function, deallocate the structure (passed as arg) */ void smtp_send_mail_int(void *arg) { struct smtp_send_request *req = arg; err_t err; LWIP_ASSERT("smtp_send_mail_int: no argument given", arg != NULL); if (req->static_data) { err = smtp_send_mail_static(req->from, req->to, req->subject, req->body, req->callback_fn, req->callback_arg); } else { err = smtp_send_mail(req->from, req->to, req->subject, req->body, req->callback_fn, req->callback_arg); } if ((err != ERR_OK) && (req->callback_fn != NULL)) { req->callback_fn(req->callback_arg, SMTP_RESULT_ERR_UNKNOWN, 0, err); } } #if SMTP_CHECK_DATA /** Verify that a given string conforms to the SMTP rules * (7-bit only, no single CR or LF, * @todo: no line consisting of a single dot only) */ static err_t smtp_verify(const char *data, size_t data_len, u8_t linebreaks_allowed) { size_t i; u8_t last_was_cr = 0; for (i = 0; i < data_len; i++) { char current = data[i]; if ((current & 0x80) != 0) { LWIP_DEBUGF(SMTP_DEBUG_WARN, ("smtp_verify: no 8-bit data supported: %s\n", data)); return ERR_ARG; } if (current == '\r') { if (!linebreaks_allowed) { LWIP_DEBUGF(SMTP_DEBUG_WARN, ("smtp_verify: found CR where no linebreaks allowed: %s\n", data)); return ERR_ARG; } if (last_was_cr) { LWIP_DEBUGF(SMTP_DEBUG_WARN, ("smtp_verify: found double CR: %s\n", data)); return ERR_ARG; } last_was_cr = 1; } else { if (current == '\n') { if (!last_was_cr) { LWIP_DEBUGF(SMTP_DEBUG_WARN, ("smtp_verify: found LF without CR before: %s\n", data)); return ERR_ARG; } } last_was_cr = 0; } } return ERR_OK; } #endif /* SMTP_CHECK_DATA */ /** Frees the smpt_session and calls the callback function */ static void smtp_free(struct smtp_session *s, u8_t result, u16_t srv_err, err_t err) { smtp_result_fn fn = s->callback_fn; void *arg = s->callback_arg; if (s->p != NULL) { pbuf_free(s->p); } mem_free(s); if (fn != NULL) { fn(arg, result, srv_err, err); } } /** Try to close a pcb and free the arg if successful */ static void smtp_close(struct smtp_session *s, struct tcp_pcb *pcb, u8_t result, u16_t srv_err, err_t err) { tcp_arg(pcb, NULL); if (tcp_close(pcb) == ERR_OK) { if (s != NULL) { smtp_free(s, result, srv_err, err); } } else { /* close failed, set back arg */ tcp_arg(pcb, s); } } /** Raw API TCP err callback: pcb is already deallocated */ static void smtp_tcp_err(void *arg, err_t err) { LWIP_UNUSED_ARG(err); if (arg != NULL) { LWIP_DEBUGF(SMTP_DEBUG_WARN_STATE, ("smtp_tcp_err: connection reset by remote host\n")); smtp_free(arg, SMTP_RESULT_ERR_CLOSED, 0, err); } } /** Raw API TCP poll callback */ static err_t smtp_tcp_poll(void *arg, struct tcp_pcb *pcb) { if (arg != NULL) { struct smtp_session *s = arg; if (s->timer != 0) { s->timer--; } } smtp_process(arg, pcb, NULL); return ERR_OK; } /** Raw API TCP sent callback */ static err_t smtp_tcp_sent(void *arg, struct tcp_pcb *pcb, u16_t len) { LWIP_UNUSED_ARG(len); smtp_process(arg, pcb, NULL); return ERR_OK; } /** Raw API TCP recv callback */ static err_t smtp_tcp_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err) { LWIP_UNUSED_ARG(err); if (p != NULL) { tcp_recved(pcb, p->tot_len); smtp_process(arg, pcb, p); } else { LWIP_DEBUGF(SMTP_DEBUG_WARN_STATE, ("smtp_tcp_recv: connection closed by remote host\n")); smtp_close(arg, pcb, SMTP_RESULT_ERR_CLOSED, 0, err); } return ERR_OK; } static err_t smtp_tcp_connected(void *arg, struct tcp_pcb *pcb, err_t err) { LWIP_UNUSED_ARG(arg); if (err == ERR_OK) { LWIP_DEBUGF(SMTP_DEBUG_STATE, ("smtp_connected: Waiting for 220\n")); } else { /* shouldn't happen, but we still check 'err', only to be sure */ LWIP_DEBUGF(SMTP_DEBUG_WARN, ("smtp_connected: %d\n", (int)err)); smtp_close(arg, pcb, SMTP_RESULT_ERR_CONNECT, 0, err); } return ERR_OK; } /** DNS callback * If ipaddr is non-NULL, resolving succeeded, otherwise it failed. */ static void smtp_dns_found(const char* hostname, ip_addr_t *ipaddr, void *arg) { struct tcp_pcb *pcb = arg; err_t err; u8_t result; LWIP_UNUSED_ARG(hostname); if (ipaddr != NULL) { LWIP_DEBUGF(SMTP_DEBUG_STATE, ("smtp_dns_found: hostname resolved, connecting\n")); err = tcp_connect(pcb, ipaddr, smtp_server_port, smtp_tcp_connected); if (err == ERR_OK) { return; } LWIP_DEBUGF(SMTP_DEBUG_WARN_STATE, ("tcp_connect failed: %d\n", (int)err)); result = SMTP_RESULT_ERR_CONNECT; } else { LWIP_DEBUGF(SMTP_DEBUG_WARN_STATE, ("smtp_dns_found: failed to resolve hostname: %s\n", hostname)); result = SMTP_RESULT_ERR_HOSTNAME; err = ERR_ARG; } smtp_close(pcb->callback_arg, pcb, result, 0, err); } #if SMTP_SUPPORT_AUTH_AUTH || SMTP_SUPPORT_AUTH_LOGIN /** Table 6-bit-index-to-ASCII used for base64-encoding */ const u8_t base64_table[] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/' }; /** Base64 encoding */ static size_t smtp_base64_encode(char* target, size_t target_len, const char* source, size_t source_len) { size_t i; s8_t j; size_t target_idx = 0; size_t longer = 3 - (source_len % 3); size_t source_len_b64 = source_len + longer; size_t len = (((source_len_b64) * 4) / 3); u8_t x = 5; u8_t current = 0; LWIP_UNUSED_ARG(target_len); LWIP_ASSERT("target_len is too short", target_len >= len); for (i = 0; i < source_len_b64; i++) { u8_t b = (i < source_len ? source[i] : 0); for (j = 7; j >= 0; j--, x--) { u8_t shift = ((b & (1 << j)) != 0) ? 1 : 0; current |= shift << x; if (x == 0) { target[target_idx++] = base64_table[current]; x = 6; current = 0; } } } for (i = len - longer; i < len; i++) { target[i] = '='; } return len; } #endif /* SMTP_SUPPORT_AUTH_AUTH || SMTP_SUPPORT_AUTH_LOGIN */ /** Parse pbuf to see if it contains the beginning of an answer. * If so, it returns the contained response code as number between 1 and 999. * If not, zero is returned. * * @param s smtp session struct */ static u16_t smtp_is_response(struct smtp_session *s) { char digits[4]; long num; if (s->p == NULL) { return 0; } /* copy three digits and convert them to int */ if (pbuf_copy_partial(s->p, digits, 3, 0) != 3) { /* pbuf was too short */ return 0; } digits[3] = 0; num = strtol(digits, NULL, 10); if ((num <= 0) || (num >= 1000)) { /* failed to find response code at start of line */ return 0; } return (u16_t)num; } /** Parse pbuf to see if it contains a fully received answer. * If one is found, ERR_OK is returned. * If none is found, ERR_VAL is returned. * * A fully received answer is a 3-digit number followed by a space, * some string and a CRLF as line ending. * * @param s smtp session struct */ static err_t smtp_is_response_finished(struct smtp_session *s) { u8_t sp; u16_t crlf; u16_t offset; if (s->p == NULL) { return ERR_VAL; } offset = 0; again: /* We could check the response number here, but we trust the * protocol definition which says the client can rely on it being * the same on every line. */ /* find CRLF */ crlf = pbuf_memfind(s->p, SMTP_CRLF, SMTP_CRLF_LEN, offset + 4); if (crlf == 0xFFFF) { /* no CRLF found */ return ERR_VAL; } sp = pbuf_get_at(s->p, offset + 3); if (sp == '-') { /* no space after response code -> try next line */ offset = crlf + 2; goto again; } else if (sp == ' ') { /* CRLF found after response code + space -> valid response */ return ERR_OK; } /* sp contains invalid character */ return ERR_VAL; } /** Prepare HELO/EHLO message */ static enum smtp_session_state smtp_prepare_helo(struct smtp_session *s, u16_t *tx_buf_len, struct tcp_pcb *pcb) { size_t ipa_len; char *ipa = ip_ntoa(&pcb->local_ip); LWIP_ASSERT("ip_ntoa returned NULL", ipa != NULL); ipa_len = strlen(ipa); LWIP_ASSERT("string too long", ipa_len <= 0xffff); *tx_buf_len = SMTP_CMD_EHLO_1_LEN + (u16_t)ipa_len + SMTP_CMD_EHLO_2_LEN; LWIP_ASSERT("tx_buf overflow detected", *tx_buf_len <= SMTP_TX_BUF_LEN); SMEMCPY(s->tx_buf, SMTP_CMD_EHLO_1, SMTP_CMD_EHLO_1_LEN); MEMCPY(&s->tx_buf[SMTP_CMD_EHLO_1_LEN], ipa, ipa_len); SMEMCPY(&s->tx_buf[SMTP_CMD_EHLO_1_LEN + ipa_len], SMTP_CMD_EHLO_2, SMTP_CMD_EHLO_2_LEN); return SMTP_HELO; } #if SMTP_SUPPORT_AUTH_AUTH || SMTP_SUPPORT_AUTH_LOGIN /** Parse last server response (in rx_buf) for supported authentication method, * create data to send out (to tx_buf), set tx_data_len correctly * and return the next state. */ static enum smtp_session_state smtp_prepare_auth_or_mail(struct smtp_session *s, u16_t *tx_buf_len) { /* check response for supported authentication method */ u16_t auth = pbuf_strstr(s->p, SMTP_KEYWORD_AUTH_SP); if (auth == 0xFFFF) { auth = pbuf_strstr(s->p, SMTP_KEYWORD_AUTH_EQ); } if (auth != 0xFFFF) { u16_t crlf = pbuf_memfind(s->p, SMTP_CRLF, SMTP_CRLF_LEN, auth); if ((crlf != 0xFFFF) && (crlf > auth)) { /* use tx_buf temporarily */ u16_t copied = pbuf_copy_partial(s->p, s->tx_buf, crlf - auth, auth); if (copied != 0) { char *sep = s->tx_buf + SMTP_KEYWORD_AUTH_LEN; s->tx_buf[copied] = 0; #if SMTP_SUPPORT_AUTH_PLAIN /* favour PLAIN over LOGIN since it involves less requests */ if (strstr(sep, SMTP_AUTH_PARAM_PLAIN) != NULL) { size_t auth_len; /* server supports AUTH PLAIN */ SMEMCPY(s->tx_buf, SMTP_CMD_AUTHPLAIN_1, SMTP_CMD_AUTHPLAIN_1_LEN); /* add base64-encoded string "\0username\0password" */ auth_len = smtp_base64_encode(&s->tx_buf[SMTP_CMD_AUTHPLAIN_1_LEN], SMTP_TX_BUF_LEN - SMTP_CMD_AUTHPLAIN_1_LEN, SMTP_AUTH_PLAIN_DATA(s), SMTP_AUTH_PLAIN_LEN(s)); LWIP_ASSERT("string too long", auth_len <= 0xffff); *tx_buf_len = SMTP_CMD_AUTHPLAIN_1_LEN + SMTP_CMD_AUTHPLAIN_2_LEN + (u16_t)auth_len; LWIP_ASSERT("tx_buf overflow detected", *tx_buf_len <= SMTP_TX_BUF_LEN); SMEMCPY(&s->tx_buf[SMTP_CMD_AUTHPLAIN_1_LEN + auth_len], SMTP_CMD_AUTHPLAIN_2, SMTP_CMD_AUTHPLAIN_2_LEN); return SMTP_AUTH_PLAIN; } else #endif /* SMTP_SUPPORT_AUTH_PLAIN */ { #if SMTP_SUPPORT_AUTH_LOGIN if (strstr(sep, SMTP_AUTH_PARAM_LOGIN) != NULL) { /* server supports AUTH LOGIN */ *tx_buf_len = SMTP_CMD_AUTHLOGIN_LEN; SMEMCPY(s->tx_buf, SMTP_CMD_AUTHLOGIN, SMTP_CMD_AUTHLOGIN_LEN); return SMTP_AUTH_LOGIN_UNAME; } #endif /* SMTP_SUPPORT_AUTH_LOGIN */ } } } } /* server didnt's send correct keywords for AUTH, try sending directly */ return smtp_prepare_mail(s, tx_buf_len); } #endif /* SMTP_SUPPORT_AUTH_AUTH || SMTP_SUPPORT_AUTH_LOGIN */ #if SMTP_SUPPORT_AUTH_LOGIN /** Send base64-encoded username */ static enum smtp_session_state smtp_prepare_auth_login_uname(struct smtp_session *s, u16_t *tx_buf_len) { size_t base64_len = smtp_base64_encode(s->tx_buf, SMTP_TX_BUF_LEN, SMTP_USERNAME(s), strlen(SMTP_USERNAME(s))); /* @todo: support base64-encoded longer than 64k */ LWIP_ASSERT("string too long", base64_len <= 0xffff); LWIP_ASSERT("tx_buf overflow detected", base64_len + SMTP_CRLF_LEN <= SMTP_TX_BUF_LEN); *tx_buf_len = (u16_t)base64_len + SMTP_CRLF_LEN; SMEMCPY(&s->tx_buf[base64_len], SMTP_CRLF, SMTP_CRLF_LEN); s->tx_buf[*tx_buf_len] = 0; return SMTP_AUTH_LOGIN_PASS; } /** Send base64-encoded password */ static enum smtp_session_state smtp_prepare_auth_login_pass(struct smtp_session *s, u16_t *tx_buf_len) { size_t base64_len = smtp_base64_encode(s->tx_buf, SMTP_TX_BUF_LEN, SMTP_PASS(s), strlen(SMTP_PASS(s))); /* @todo: support base64-encoded longer than 64k */ LWIP_ASSERT("string too long", base64_len <= 0xffff); LWIP_ASSERT("tx_buf overflow detected", base64_len + SMTP_CRLF_LEN <= SMTP_TX_BUF_LEN); *tx_buf_len = (u16_t)base64_len + SMTP_CRLF_LEN; SMEMCPY(&s->tx_buf[base64_len], SMTP_CRLF, SMTP_CRLF_LEN); s->tx_buf[*tx_buf_len] = 0; return SMTP_AUTH_LOGIN; } #endif /* SMTP_SUPPORT_AUTH_LOGIN */ /** Prepare MAIL message */ static enum smtp_session_state smtp_prepare_mail(struct smtp_session *s, u16_t *tx_buf_len) { char *target = s->tx_buf; *tx_buf_len = SMTP_CMD_MAIL_1_LEN + SMTP_CMD_MAIL_2_LEN + s->from_len; LWIP_ASSERT("tx_buf overflow detected", *tx_buf_len <= SMTP_TX_BUF_LEN); target[*tx_buf_len] = 0; SMEMCPY(target, SMTP_CMD_MAIL_1, SMTP_CMD_MAIL_1_LEN); target += SMTP_CMD_MAIL_1_LEN; memcpy(target, s->from, s->from_len); target += s->from_len; SMEMCPY(target, SMTP_CMD_MAIL_2, SMTP_CMD_MAIL_2_LEN); return SMTP_MAIL; } /** Prepare RCPT message */ static enum smtp_session_state smtp_prepare_rcpt(struct smtp_session *s, u16_t *tx_buf_len) { char *target = s->tx_buf; *tx_buf_len = SMTP_CMD_RCPT_1_LEN + SMTP_CMD_RCPT_2_LEN + s->to_len; LWIP_ASSERT("tx_buf overflow detected", *tx_buf_len <= SMTP_TX_BUF_LEN); target[*tx_buf_len] = 0; SMEMCPY(target, SMTP_CMD_RCPT_1, SMTP_CMD_RCPT_1_LEN); target += SMTP_CMD_RCPT_1_LEN; memcpy(target, s->to, s->to_len); target += s->to_len; SMEMCPY(target, SMTP_CMD_RCPT_2, SMTP_CMD_RCPT_2_LEN); return SMTP_RCPT; } /** Prepare header of body */ static enum smtp_session_state smtp_prepare_header(struct smtp_session *s, u16_t *tx_buf_len) { char *target = s->tx_buf; *tx_buf_len = SMTP_CMD_HEADER_1_LEN + SMTP_CMD_HEADER_2_LEN + SMTP_CMD_HEADER_3_LEN + SMTP_CMD_HEADER_4_LEN + s->from_len + s->to_len + s->subject_len; LWIP_ASSERT("tx_buf overflow detected", *tx_buf_len <= SMTP_TX_BUF_LEN); target[*tx_buf_len] = 0; SMEMCPY(target, SMTP_CMD_HEADER_1, SMTP_CMD_HEADER_1_LEN); target += SMTP_CMD_HEADER_1_LEN; memcpy(target, s->from, s->from_len); target += s->from_len; SMEMCPY(target, SMTP_CMD_HEADER_2, SMTP_CMD_HEADER_2_LEN); target += SMTP_CMD_HEADER_2_LEN; memcpy(target, s->to, s->to_len); target += s->to_len; SMEMCPY(target, SMTP_CMD_HEADER_3, SMTP_CMD_HEADER_3_LEN); target += SMTP_CMD_HEADER_3_LEN; memcpy(target, s->subject, s->subject_len); target += s->subject_len; SMEMCPY(target, SMTP_CMD_HEADER_4, SMTP_CMD_HEADER_4_LEN); return SMTP_BODY; } /** Prepare QUIT message */ static enum smtp_session_state smtp_prepare_quit(struct smtp_session *s, u16_t *tx_buf_len) { *tx_buf_len = SMTP_CMD_QUIT_LEN; s->tx_buf[*tx_buf_len] = 0; SMEMCPY(s->tx_buf, SMTP_CMD_QUIT, SMTP_CMD_QUIT_LEN); LWIP_ASSERT("tx_buf overflow detected", *tx_buf_len <= SMTP_TX_BUF_LEN); return SMTP_CLOSED; } /** If in state SMTP_BODY, try to send more body data */ static void smtp_send_body(struct smtp_session *s, struct tcp_pcb *pcb) { err_t err; if (s->state == SMTP_BODY) { u16_t send_len = s->body_len - s->body_sent; if (send_len > 0) { u16_t snd_buf = tcp_sndbuf(pcb); if (send_len > snd_buf) { send_len = snd_buf; } if (send_len > 0) { /* try to send something out */ err = tcp_write(pcb, &s->body[s->body_sent], (u16_t)send_len, TCP_WRITE_FLAG_COPY); if (err == ERR_OK) { s->timer = SMTP_TIMEOUT_DATABLOCK; s->body_sent += send_len; if (s->body_sent < s->body_len) { LWIP_DEBUGF(SMTP_DEBUG_STATE, ("smtp_send_body: %d of %d bytes written\n", s->body_sent, s->body_len)); } } } } if (s->body_sent == s->body_len) { /* the whole body has been written, write last line */ LWIP_DEBUGF(SMTP_DEBUG_STATE, ("smtp_send_body: body completely written (%d bytes), appending end-of-body\n", s->body_len)); err = tcp_write(pcb, SMTP_CMD_BODY_FINISHED, SMTP_CMD_BODY_FINISHED_LEN, 0); if (err == ERR_OK) { s->timer = SMTP_TIMEOUT_DATATERM; LWIP_DEBUGF(SMTP_DEBUG_STATE, ("smtp_send_body: end-of-body written, changing state to %s\n", smtp_state_str[SMTP_QUIT])); /* last line written, change state, wait for confirmation */ s->state = SMTP_QUIT; } } } } /** State machine-like implementation of an SMTP client. */ static void smtp_process(void *arg, struct tcp_pcb *pcb, struct pbuf *p) { struct smtp_session* s = arg; u16_t response_code = 0; u16_t tx_buf_len = 0; enum smtp_session_state next_state; if (arg == NULL) { /* already closed SMTP connection */ if (p != NULL) { LWIP_DEBUGF(SMTP_DEBUG_TRACE, ("Received %d bytes after closing: %s\n", p->tot_len, smtp_pbuf_str(p))); pbuf_free(p); } return; } next_state = s->state; if (p != NULL) { /* received data */ if (s->p == NULL) { s->p = p; } else { pbuf_cat(s->p, p); } } else { /* idle timer, close connection if timed out */ if (s->timer == 0) { LWIP_DEBUGF(SMTP_DEBUG_WARN_STATE, ("smtp_process: connection timed out, closing\n")); smtp_close(s, pcb, SMTP_RESULT_ERR_TIMEOUT, 0, ERR_TIMEOUT); return; } if (s->state == SMTP_BODY) { smtp_send_body(s, pcb); return; } } response_code = smtp_is_response(s); if (response_code) { LWIP_DEBUGF(SMTP_DEBUG_TRACE, ("smtp_process: received response code: %d\n", response_code)); if (smtp_is_response_finished(s) != ERR_OK) { LWIP_DEBUGF(SMTP_DEBUG_TRACE, ("smtp_process: partly received response code: %d\n", response_code)); /* wait for next packet to complete the respone */ return; } } else { if (s->p != NULL) { LWIP_DEBUGF(SMTP_DEBUG_WARN, ("smtp_process: unknown data received (%s)\n", smtp_pbuf_str(s->p))); pbuf_free(s->p); s->p = NULL; } return; } switch(s->state) { case(SMTP_NULL): /* wait for 220 */ if (response_code == 220) { /* then send EHLO */ next_state = smtp_prepare_helo(s, &tx_buf_len, pcb); } break; case(SMTP_HELO): /* wait for 250 */ if (response_code == 250) { #if SMTP_SUPPORT_AUTH_AUTH || SMTP_SUPPORT_AUTH_LOGIN /* then send AUTH or MAIL */ next_state = smtp_prepare_auth_or_mail(s, &tx_buf_len); } break; case(SMTP_AUTH_LOGIN): case(SMTP_AUTH_PLAIN): /* wait for 235 */ if (response_code == 235) { #endif /* SMTP_SUPPORT_AUTH_AUTH || SMTP_SUPPORT_AUTH_LOGIN */ /* send MAIL */ next_state = smtp_prepare_mail(s, &tx_buf_len); } break; #if SMTP_SUPPORT_AUTH_LOGIN case(SMTP_AUTH_LOGIN_UNAME): /* wait for 334 Username */ if (response_code == 334) { if (pbuf_strstr(s->p, SMTP_RESP_LOGIN_UNAME) != 0xFFFF) { /* send username */ next_state = smtp_prepare_auth_login_uname(s, &tx_buf_len); } } break; case(SMTP_AUTH_LOGIN_PASS): /* wait for 334 Password */ if (response_code == 334) { if (pbuf_strstr(s->p, SMTP_RESP_LOGIN_PASS) != 0xFFFF) { /* send username */ next_state = smtp_prepare_auth_login_pass(s, &tx_buf_len); } } break; #endif /* SMTP_SUPPORT_AUTH_LOGIN */ case(SMTP_MAIL): /* wait for 250 */ if (response_code == 250) { /* send RCPT */ next_state = smtp_prepare_rcpt(s, &tx_buf_len); } break; case(SMTP_RCPT): /* wait for 250 */ if (response_code == 250) { /* send DATA */ SMEMCPY(s->tx_buf, SMTP_CMD_DATA, SMTP_CMD_DATA_LEN); tx_buf_len = SMTP_CMD_DATA_LEN; next_state = SMTP_DATA; } break; case(SMTP_DATA): /* wait for 354 */ if (response_code == 354) { /* send email header */ next_state = smtp_prepare_header(s, &tx_buf_len); } break; case(SMTP_BODY): /* nothing to be done here, handled somewhere else */ break; case(SMTP_QUIT): /* wait for 250 */ if (response_code == 250) { /* send QUIT */ next_state = smtp_prepare_quit(s, &tx_buf_len); } break; case(SMTP_CLOSED): /* nothing to do, wait for connection closed from server */ return; default: LWIP_DEBUGF(SMTP_DEBUG_SERIOUS, ("Invalid state: %d/%s\n", (int)s->state, smtp_state_str[s->state])); break; } if (s->state == next_state) { LWIP_DEBUGF(SMTP_DEBUG_WARN_STATE, ("smtp_process[%s]: unexpected response_code, closing: %d (%s)\n", smtp_state_str[s->state], response_code, smtp_pbuf_str(s->p))); /* close connection */ smtp_close(s, pcb, SMTP_RESULT_ERR_SVR_RESP, response_code, ERR_OK); return; } if (tx_buf_len > 0) { SMTP_TX_BUF_MAX(tx_buf_len); if (tcp_write(pcb, s->tx_buf, tx_buf_len, TCP_WRITE_FLAG_COPY) == ERR_OK) { LWIP_DEBUGF(SMTP_DEBUG_TRACE, ("smtp_process[%s]: received command %d (%s)\n", smtp_state_str[s->state], response_code, smtp_pbuf_str(s->p))); LWIP_DEBUGF(SMTP_DEBUG_TRACE, ("smtp_process[%s]: sent %"U16_F" bytes: \"%s\"\n", smtp_state_str[s->state], tx_buf_len, s->tx_buf)); s->timer = SMTP_TIMEOUT; pbuf_free(s->p); s->p = NULL; LWIP_DEBUGF(SMTP_DEBUG_STATE, ("smtp_process: changing state from %s to %s\n", smtp_state_str[s->state], smtp_state_str[next_state])); s->state = next_state; if (next_state == SMTP_BODY) { /* try to stream-send body data right now */ smtp_send_body(s, pcb); } else if (next_state == SMTP_CLOSED) { /* sent out all data, delete structure */ tcp_arg(pcb, NULL); smtp_free(s, SMTP_RESULT_OK, 0, ERR_OK); } } } } #endif /* LWIP_TCP */ ocproxy-1.60/contrib/apps/smtp/smtp.h000066400000000000000000000050621303453231400176660ustar00rootroot00000000000000#ifndef LWIP_SMTP_H #define LWIP_SMTP_H #include "lwip/err.h" /** The default TCP port used for SMTP */ #define SMTP_DEFAULT_PORT 25 /** Email successfully sent */ #define SMTP_RESULT_OK 0 /** Unknown error */ #define SMTP_RESULT_ERR_UNKNOWN 1 /** Connection to server failed */ #define SMTP_RESULT_ERR_CONNECT 2 /** Failed to resolve server hostname */ #define SMTP_RESULT_ERR_HOSTNAME 3 /** Connection unexpectedly closed by remote server */ #define SMTP_RESULT_ERR_CLOSED 4 /** Connection timed out (server didn't respond in time) */ #define SMTP_RESULT_ERR_TIMEOUT 5 /** Server responded with an unknown response code */ #define SMTP_RESULT_ERR_SVR_RESP 6 /** Prototype of an smtp callback function * * @param arg argument specified when initiating the email * @param smtp_result result of the mail transfer (see defines SMTP_RESULT_*) * @param srv_err if aborted by the server, this contains the error code received * @param err an error returned by internal lwip functions, can help to specify * the source of the error but must not necessarily be != ERR_OK */ typedef void (*smtp_result_fn)(void *arg, u8_t smtp_result, u16_t srv_err, err_t err); /** This structure is used as argument for smtp_send_mail_int(), * which in turn can be used with tcpip_callback() to send mail * from interrupt context. * For member description, see parameter description of smtp_send_mail(). * When using with tcpip_callback, this structure has to stay allocated * (e.g. using mem_malloc/mem_free) until its 'callback_fn' is called. */ struct smtp_send_request { const char *from; const char* to; const char* subject; const char* body; smtp_result_fn callback_fn; void* callback_arg; /** If this is != 0, data is *not* copied into an extra buffer * but used from the pointers supplied in this struct. * This means less memory usage, but data must stay untouched until * the callback function is called. */ u8_t static_data; }; void smtp_set_server_addr(const char* server); void smtp_set_server_port(u16_t port); err_t smtp_set_auth(const char* username, const char* pass); err_t smtp_send_mail(const char *from, const char* to, const char* subject, const char* body, smtp_result_fn callback_fn, void* callback_arg); err_t smtp_send_mail_static(const char *from, const char* to, const char* subject, const char* body, smtp_result_fn callback_fn, void* callback_arg); void smtp_send_mail_int(void *arg); #ifdef LWIP_DEBUG const char* smtp_result_str(u8_t smtp_result); #endif #endif /* LWIP_SMTP_H */ ocproxy-1.60/contrib/apps/snmp_private_mib/000077500000000000000000000000001303453231400211025ustar00rootroot00000000000000ocproxy-1.60/contrib/apps/snmp_private_mib/lwip_prvmib.c000066400000000000000000000367221303453231400236120ustar00rootroot00000000000000/** * @file * lwip Private MIB * * @todo create MIB file for this example * @note the lwip enterprise tree root (26381) is owned by the lwIP project. * It is NOT allowed to allocate new objects under this ID (26381) without our, * the lwip developers, permission! * * Please apply for your own ID with IANA: http://www.iana.org/numbers.html * * lwip OBJECT IDENTIFIER ::= { enterprises 26381 } * example OBJECT IDENTIFIER ::= { lwip 1 } */ /* * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * Author: Christiaan Simons */ #include "private_mib.h" #if LWIP_SNMP /** Directory where the sensor files are */ #define SENSORS_DIR "w:\\sensors" /** Set to 1 to read sensor values from files (in directory defined by SENSORS_DIR) */ #define SENSORS_USE_FILES 0 /** Set to 1 to search sensor files at startup (in directory defined by SENSORS_DIR) */ #define SENSORS_SEARCH_FILES 0 #if SENSORS_SEARCH_FILES #include #include #include #include #include #include #endif /* SENSORS_SEARCH_FILES */ #include #include #include "lwip/snmp_msg.h" #include "lwip/snmp_asn1.h" #if !SENSORS_USE_FILES || !SENSORS_SEARCH_FILES /** When not using & searching files, defines the number of sensors */ #define SENSOR_COUNT 2 #endif /* !SENSORS_USE_FILES || !SENSORS_SEARCH_FILES */ #if !SENSORS_USE_FILES /** When not using files, contains the values of the sensors */ s32_t sensor_values[SENSOR_COUNT]; #endif /* !SENSORS_USE_FILES */ /* This example presents a table for a few (at most 10) sensors. Sensor detection takes place at initialization (once only). Sensors may and can not be added or removed after agent has started. Note this is only a limitation of this crude example, the agent does support dynamic object insertions and removals. You'll need to manually create a directory called "sensors" and a few single line text files with an integer temperature value. The files must be called [0..9].txt. ./sensors/0.txt [content: 20] ./sensors/3.txt [content: 75] The sensor values may be changed in runtime by editing the text files in the "sensors" directory. */ #define SENSOR_MAX 10 #define SENSOR_NAME_LEN 20 struct sensor_inf { char sensor_files[SENSOR_MAX][SENSOR_NAME_LEN + 1]; /* (Sparse) list of sensors (table index), the actual "hot insertion" is done in lwip_privmib_init() */ struct mib_list_rootnode sensor_list_rn; }; struct sensor_inf sensor_addr_inf = { {{0}}, { NULL, NULL, NULL, NULL, MIB_NODE_LR, 0, NULL, NULL, 0 } }; static u16_t sensorentry_length(void* addr_inf, u8_t level); static s32_t sensorentry_idcmp(void* addr_inf, u8_t level, u16_t idx, s32_t sub_id); static void sensorentry_get_subid(void* addr_inf, u8_t level, u16_t idx, s32_t *sub_id); static void sensorentry_get_object_def_q(void* addr_inf, u8_t rid, u8_t ident_len, s32_t *ident); static void sensorentry_get_object_def_a(u8_t rid, u8_t ident_len, s32_t *ident, struct obj_def *od); static void sensorentry_get_object_def_pc(u8_t rid, u8_t ident_len, s32_t *ident); static void sensorentry_get_value_q(u8_t rid, struct obj_def *od); static void sensorentry_get_value_a(u8_t rid, struct obj_def *od, u16_t len, void *value); static void sensorentry_get_value_pc(u8_t rid, struct obj_def *od); static void sensorentry_set_test_q(u8_t rid, struct obj_def *od); static u8_t sensorentry_set_test_a(u8_t rid, struct obj_def *od, u16_t len, void *value); static void sensorentry_set_test_pc(u8_t rid, struct obj_def *od); static void sensorentry_set_value_q(u8_t rid, struct obj_def *od, u16_t len, void *value); static void sensorentry_set_value_a(u8_t rid, struct obj_def *od, u16_t len, void *value); static void sensorentry_set_value_pc(u8_t rid, struct obj_def *od); /* sensorentry .1.3.6.1.4.1.26381.1.1.1 (.level0.level1) where level 0 is the object identifier (temperature) and level 1 the index */ static struct mib_external_node sensorentry = { &noleafs_get_object_def, &noleafs_get_value, &noleafs_set_test, &noleafs_set_value, MIB_NODE_EX, 0, &sensor_addr_inf, /* 0 tree_levels (empty table) at power-up, 2 when one or more sensors are detected */ 0, &sensorentry_length, &sensorentry_idcmp, &sensorentry_get_subid, &sensorentry_get_object_def_q, &sensorentry_get_value_q, &sensorentry_set_test_q, &sensorentry_set_value_q, &sensorentry_get_object_def_a, &sensorentry_get_value_a, &sensorentry_set_test_a, &sensorentry_set_value_a, &sensorentry_get_object_def_pc, &sensorentry_get_value_pc, &sensorentry_set_test_pc, &sensorentry_set_value_pc }; /* sensortable .1.3.6.1.4.1.26381.1.1 */ static const s32_t sensortable_ids[1] = { 1 }; static struct mib_node* const sensortable_nodes[1] = { (struct mib_node* const)&sensorentry }; static const struct mib_array_node sensortable = { &noleafs_get_object_def, &noleafs_get_value, &noleafs_set_test, &noleafs_set_value, MIB_NODE_AR, 1, sensortable_ids, sensortable_nodes }; /* example .1.3.6.1.4.1.26381.1 */ static const s32_t example_ids[1] = { 1 }; static struct mib_node* const example_nodes[1] = { (struct mib_node* const)&sensortable }; static const struct mib_array_node example = { &noleafs_get_object_def, &noleafs_get_value, &noleafs_set_test, &noleafs_set_value, MIB_NODE_AR, 1, example_ids, example_nodes }; /* lwip .1.3.6.1.4.1.26381 */ static const s32_t lwip_ids[1] = { 1 }; static struct mib_node* const lwip_nodes[1] = { (struct mib_node* const)&example }; static const struct mib_array_node lwip = { &noleafs_get_object_def, &noleafs_get_value, &noleafs_set_test, &noleafs_set_value, MIB_NODE_AR, 1, lwip_ids, lwip_nodes }; /* enterprises .1.3.6.1.4.1 */ static const s32_t enterprises_ids[1] = { 26381 }; static struct mib_node* const enterprises_nodes[1] = { (struct mib_node* const)&lwip }; static const struct mib_array_node enterprises = { &noleafs_get_object_def, &noleafs_get_value, &noleafs_set_test, &noleafs_set_value, MIB_NODE_AR, 1, enterprises_ids, enterprises_nodes }; /* private .1.3.6.1.4 */ static const s32_t private_ids[1] = { 1 }; static struct mib_node* const private_nodes[1] = { (struct mib_node* const)&enterprises }; const struct mib_array_node mib_private = { &noleafs_get_object_def, &noleafs_get_value, &noleafs_set_test, &noleafs_set_value, MIB_NODE_AR, 1, private_ids, private_nodes }; /** * Initialises this private MIB before use. * @see main.c */ void lwip_privmib_init(void) { #if SENSORS_USE_FILES && SENSORS_SEARCH_FILES char *buf, *ebuf, *cp; size_t bufsize; int nbytes; struct stat sb; struct dirent *dp; int fd; #else /* SENSORS_USE_FILES && SENSORS_SEARCH_FILES */ int i; #endif /* SENSORS_USE_FILES && SENSORS_SEARCH_FILES */ printf("SNMP private MIB start, detecting sensors.\n"); #if SENSORS_USE_FILES && SENSORS_SEARCH_FILES /* look for sensors in sensors directory */ fd = open(SENSORS_DIR, O_RDONLY); if (fd > -1) { fstat(fd, &sb); bufsize = sb.st_size; if (bufsize < sb.st_blksize) { bufsize = sb.st_blksize; } buf = malloc(bufsize); if (buf != NULL) { do { long base; nbytes = getdirentries(fd, buf, bufsize, &base); if (nbytes > 0) { ebuf = buf + nbytes; cp = buf; while (cp < ebuf) { dp = (struct dirent *)cp; if (isdigit(dp->d_name[0])) { struct mib_list_node *dummy; unsigned char idx; idx = dp->d_name[0] - '0'; snmp_mib_node_insert(&sensor_addr_inf.sensor_list_rn,idx,&dummy); strncpy(&sensor_addr_inf.sensor_files[idx][0],dp->d_name,SENSOR_NAME_LEN); printf("%s\n", sensor_addr_inf.sensor_files[idx]); } cp += dp->d_reclen; } } } while (nbytes > 0); free(buf); } close(fd); } #else /* SENSORS_USE_FILES && SENSORS_SEARCH_FILES */ for (i = 0; i < SENSOR_COUNT; i++) { struct mib_list_node *dummy; s32_t idx = i; char name[256]; sprintf(name, "%d.txt", i); snmp_mib_node_insert(&sensor_addr_inf.sensor_list_rn, idx, &dummy); strncpy(&sensor_addr_inf.sensor_files[idx][0], name, SENSOR_NAME_LEN); printf("%s\n", sensor_addr_inf.sensor_files[idx]); #if !SENSORS_USE_FILES /* initialize sensor value to != zero */ sensor_values[i] = 11 * (i+1); #endif /* !SENSORS_USE_FILES */ } #endif /* SENSORS_USE_FILE && SENSORS_SEARCH_FILES */ if (sensor_addr_inf.sensor_list_rn.count != 0) { /* enable sensor table, 2 tree_levels under this node one for the registers and one for the index */ sensorentry.tree_levels = 2; } } static u16_t sensorentry_length(void* addr_inf, u8_t level) { struct sensor_inf *sensors = (struct sensor_inf *)addr_inf; if (level == 0) { /* one object (temperature) */ return 1; } else if (level == 1) { /* number of sensor indexes */ return sensors->sensor_list_rn.count; } else { return 0; } } static s32_t sensorentry_idcmp(void* addr_inf, u8_t level, u16_t idx, s32_t sub_id) { struct sensor_inf *sensors = (struct sensor_inf *)addr_inf; if (level == 0) { return ((s32_t)(idx + 1) - sub_id); } else if (level == 1) { struct mib_list_node *ln; u16_t i; i = 0; ln = sensors->sensor_list_rn.head; while (i < idx) { i++; ln = ln->next; } LWIP_ASSERT("ln != NULL", ln != NULL); return (ln->objid - sub_id); } else { return -1; } } static void sensorentry_get_subid(void* addr_inf, u8_t level, u16_t idx, s32_t *sub_id) { struct sensor_inf *sensors = (struct sensor_inf *)addr_inf; if (level == 0) { *sub_id = idx + 1; } else if (level == 1) { struct mib_list_node *ln; u16_t i; i = 0; ln = sensors->sensor_list_rn.head; while (i < idx) { i++; ln = ln->next; } LWIP_ASSERT("ln != NULL", ln != NULL); *sub_id = ln->objid; } } /** * Async question for object definition */ static void sensorentry_get_object_def_q(void* addr_inf, u8_t rid, u8_t ident_len, s32_t *ident) { s32_t sensor_register, sensor_address; LWIP_UNUSED_ARG(addr_inf); LWIP_UNUSED_ARG(rid); ident_len += 1; ident -= 1; /* send request */ sensor_register = ident[0]; sensor_address = ident[1]; LWIP_DEBUGF(SNMP_MIB_DEBUG,("sensor_request reg=%"S32_F" addr=%"S32_F"\n", sensor_register, sensor_address)); /* fake async quesion/answer */ snmp_msg_event(rid); } static void sensorentry_get_object_def_a(u8_t rid, u8_t ident_len, s32_t *ident, struct obj_def *od) { LWIP_UNUSED_ARG(rid); /* return to object name, adding index depth (1) */ ident_len += 1; ident -= 1; if (ident_len == 2) { od->id_inst_len = ident_len; od->id_inst_ptr = ident; od->instance = MIB_OBJECT_TAB; od->access = MIB_OBJECT_READ_WRITE; od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG); od->v_len = sizeof(s32_t); } else { LWIP_DEBUGF(SNMP_MIB_DEBUG,("sensorentry_get_object_def_a: no scalar\n")); od->instance = MIB_OBJECT_NONE; } } static void sensorentry_get_object_def_pc(u8_t rid, u8_t ident_len, s32_t *ident) { LWIP_UNUSED_ARG(rid); LWIP_UNUSED_ARG(ident_len); LWIP_UNUSED_ARG(ident); /* nop */ } static void sensorentry_get_value_q(u8_t rid, struct obj_def *od) { LWIP_UNUSED_ARG(od); /* fake async quesion/answer */ snmp_msg_event(rid); } static void sensorentry_get_value_a(u8_t rid, struct obj_def *od, u16_t len, void *value) { s32_t i; s32_t *temperature = (s32_t *)value; #if SENSORS_USE_FILES FILE* sensf; char senspath[sizeof(SENSORS_DIR)+1+SENSOR_NAME_LEN+1] = SENSORS_DIR"/"; #endif /* SENSORS_USE_FILES */ LWIP_UNUSED_ARG(rid); LWIP_UNUSED_ARG(len); i = od->id_inst_ptr[1]; #if SENSORS_USE_FILES strncpy(&senspath[sizeof(SENSORS_DIR)], sensor_addr_inf.sensor_files[i], SENSOR_NAME_LEN); sensf = fopen(senspath,"r"); if (sensf != NULL) { fscanf(sensf,"%"S32_F,temperature); fclose(sensf); } #else /* SENSORS_USE_FILES */ if (i < SENSOR_COUNT) { *temperature = sensor_values[i]; } #endif /* SENSORS_USE_FILES */ } static void sensorentry_get_value_pc(u8_t rid, struct obj_def *od) { LWIP_UNUSED_ARG(rid); LWIP_UNUSED_ARG(od); /* nop */ } static void sensorentry_set_test_q(u8_t rid, struct obj_def *od) { LWIP_UNUSED_ARG(od); /* fake async quesion/answer */ snmp_msg_event(rid); } static u8_t sensorentry_set_test_a(u8_t rid, struct obj_def *od, u16_t len, void *value) { LWIP_UNUSED_ARG(rid); LWIP_UNUSED_ARG(od); LWIP_UNUSED_ARG(len); LWIP_UNUSED_ARG(value); /* sensors are read-only */ return 1; /* 0 -> read only, != 0 -> read/write */ } static void sensorentry_set_test_pc(u8_t rid, struct obj_def *od) { LWIP_UNUSED_ARG(rid); LWIP_UNUSED_ARG(od); /* nop */ } static void sensorentry_set_value_q(u8_t rid, struct obj_def *od, u16_t len, void *value) { LWIP_UNUSED_ARG(rid); LWIP_UNUSED_ARG(od); LWIP_UNUSED_ARG(len); LWIP_UNUSED_ARG(value); /* fake async quesion/answer */ snmp_msg_event(rid); } static void sensorentry_set_value_a(u8_t rid, struct obj_def *od, u16_t len, void *value) { s32_t i; s32_t *temperature = (s32_t *)value; #if SENSORS_USE_FILES FILE* sensf; char senspath[sizeof(SENSORS_DIR)+1+SENSOR_NAME_LEN+1] = SENSORS_DIR"/"; #endif /* SENSORS_USE_FILES */ LWIP_UNUSED_ARG(rid); LWIP_UNUSED_ARG(len); i = od->id_inst_ptr[1]; #if SENSORS_USE_FILES strncpy(&senspath[sizeof(SENSORS_DIR)], sensor_addr_inf.sensor_files[i], SENSOR_NAME_LEN); sensf = fopen(senspath, "w"); if (sensf != NULL) { fprintf(sensf, "%"S32_F, temperature); fclose(sensf); } #else /* SENSORS_USE_FILES */ if (i < SENSOR_COUNT) { sensor_values[i] = *temperature; } #endif /* SENSORS_USE_FILES */ } static void sensorentry_set_value_pc(u8_t rid, struct obj_def *od) { LWIP_UNUSED_ARG(rid); LWIP_UNUSED_ARG(od); /* nop */ } #endif /* LWIP_SNMP */ ocproxy-1.60/contrib/apps/snmp_private_mib/private_mib.h000066400000000000000000000006351303453231400235600ustar00rootroot00000000000000/** * @file * Exports Private lwIP MIB */ #ifndef LWIP_HDR_PRIVATE_MIB_H #define LWIP_HDR_PRIVATE_MIB_H #include "arch/cc.h" #include "lwip/opt.h" #if LWIP_SNMP #include "lwip/snmp_structs.h" extern const struct mib_array_node mib_private; /** @todo remove this?? */ struct private_msg { u8_t dummy; }; void lwip_privmib_init(void); #define SNMP_PRIVATE_MIB_INIT() lwip_privmib_init() #endif #endif ocproxy-1.60/contrib/apps/sntp/000077500000000000000000000000001303453231400165305ustar00rootroot00000000000000ocproxy-1.60/contrib/apps/sntp/sntp.c000066400000000000000000000473341303453231400176730ustar00rootroot00000000000000/** * @file * SNTP client module * * This is simple "SNTP" client for the lwIP raw API. * It is a minimal implementation of SNTPv4 as specified in RFC 4330. * * For a list of some public NTP servers, see this link : * http://support.ntp.org/bin/view/Servers/NTPPoolServers * * @todo: * - set/change servers at runtime * - complete SNTP_CHECK_RESPONSE checks 3 and 4 * - support broadcast/multicast mode? */ /* * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Simon Goldschmidt (lwIP raw API part) */ #include "lwip/opt.h" #include "sntp.h" #include "lwip/timers.h" #include "lwip/udp.h" #include "lwip/dns.h" #include "lwip/ip_addr.h" #include "lwip/pbuf.h" #include #include #if LWIP_UDP /** * SNTP_DEBUG: Enable debugging for SNTP. */ #ifndef SNTP_DEBUG #define SNTP_DEBUG LWIP_DBG_OFF #endif /** SNTP server port */ #ifndef SNTP_PORT #define SNTP_PORT 123 #endif /** Set this to 1 to allow SNTP_SERVER_ADDRESS to be a DNS name */ #ifndef SNTP_SERVER_DNS #define SNTP_SERVER_DNS 0 #endif /** Set this to 1 to support more than one server */ #ifndef SNTP_SUPPORT_MULTIPLE_SERVERS #define SNTP_SUPPORT_MULTIPLE_SERVERS 0 #endif /** \def SNTP_SERVER_ADDRESS * \brief SNTP server address: * - as IPv4 address in "u32_t" format * - as a DNS name if SNTP_SERVER_DNS is set to 1 * May contain multiple server names (e.g. "pool.ntp.org","second.time.server") */ #ifndef SNTP_SERVER_ADDRESS #if SNTP_SERVER_DNS #define SNTP_SERVER_ADDRESS "pool.ntp.org" #else #define SNTP_SERVER_ADDRESS "213.161.194.93" /* pool.ntp.org */ #endif #endif /** Sanity check: * Define this to * - 0 to turn off sanity checks (default; smaller code) * - >= 1 to check address and port of the response packet to ensure the * response comes from the server we sent the request to. * - >= 2 to check returned Originate Timestamp against Transmit Timestamp * sent to the server (to ensure response to older request). * - >= 3 @todo: discard reply if any of the LI, Stratum, or Transmit Timestamp * fields is 0 or the Mode field is not 4 (unicast) or 5 (broadcast). * - >= 4 @todo: to check that the Root Delay and Root Dispersion fields are each * greater than or equal to 0 and less than infinity, where infinity is * currently a cozy number like one second. This check avoids using a * server whose synchronization source has expired for a very long time. */ #ifndef SNTP_CHECK_RESPONSE #define SNTP_CHECK_RESPONSE 0 #endif /** According to the RFC, this shall be a random delay * between 1 and 5 minutes (in milliseconds) to prevent load peaks. * This can be defined to a random generation function, * which must return the delay in milliseconds as u32_t. * Turned off by default. */ #ifndef SNTP_STARTUP_DELAY #define SNTP_STARTUP_DELAY 0 #endif /** If you want the startup delay to be a function, define this * to a function (including the brackets) and define SNTP_STARTUP_DELAY to 1. */ #ifndef SNTP_STARTUP_DELAY_FUNC #define SNTP_STARTUP_DELAY_FUNC SNTP_STARTUP_DELAY #endif /** SNTP receive timeout - in milliseconds * Also used as retry timeout - this shouldn't be too low. * Default is 3 seconds. */ #ifndef SNTP_RECV_TIMEOUT #define SNTP_RECV_TIMEOUT 3000 #endif /** SNTP update delay - in milliseconds * Default is 1 hour. */ #ifndef SNTP_UPDATE_DELAY #define SNTP_UPDATE_DELAY 3600000 #endif #if (SNTP_UPDATE_DELAY < 15000) && !SNTP_SUPPRESS_DELAY_CHECK #error "SNTPv4 RFC 4330 enforces a minimum update time of 15 seconds!" #endif /** SNTP macro to change system time and/or the update the RTC clock */ #ifndef SNTP_SET_SYSTEM_TIME #define SNTP_SET_SYSTEM_TIME(sec) ((void)sec) #endif /** SNTP macro to change system time including microseconds */ #ifdef SNTP_SET_SYSTEM_TIME_US #define SNTP_CALC_TIME_US 1 #define SNTP_RECEIVE_TIME_SIZE 2 #else #define SNTP_SET_SYSTEM_TIME_US(sec, us) #define SNTP_CALC_TIME_US 0 #define SNTP_RECEIVE_TIME_SIZE 1 #endif /** SNTP macro to get system time, used with SNTP_CHECK_RESPONSE >= 2 * to send in request and compare in response. */ #ifndef SNTP_GET_SYSTEM_TIME #define SNTP_GET_SYSTEM_TIME(sec, us) do { (sec) = 0; (us) = 0; } while(0) #endif /** Default retry timeout (in milliseconds) if the response * received is invalid. * This is doubled with each retry until SNTP_RETRY_TIMEOUT_MAX is reached. */ #ifndef SNTP_RETRY_TIMEOUT #define SNTP_RETRY_TIMEOUT SNTP_RECV_TIMEOUT #endif /** Maximum retry timeout (in milliseconds). */ #ifndef SNTP_RETRY_TIMEOUT_MAX #define SNTP_RETRY_TIMEOUT_MAX (SNTP_RETRY_TIMEOUT * 10) #endif /** Increase retry timeout with every retry sent * Default is on to conform to RFC. */ #ifndef SNTP_RETRY_TIMEOUT_EXP #define SNTP_RETRY_TIMEOUT_EXP 1 #endif /* the various debug levels for this file */ #define SNTP_DEBUG_TRACE (SNTP_DEBUG | LWIP_DBG_TRACE) #define SNTP_DEBUG_STATE (SNTP_DEBUG | LWIP_DBG_STATE) #define SNTP_DEBUG_WARN (SNTP_DEBUG | LWIP_DBG_LEVEL_WARNING) #define SNTP_DEBUG_WARN_STATE (SNTP_DEBUG | LWIP_DBG_LEVEL_WARNING | LWIP_DBG_STATE) #define SNTP_DEBUG_SERIOUS (SNTP_DEBUG | LWIP_DBG_LEVEL_SERIOUS) #define SNTP_ERR_KOD 1 /* SNTP protocol defines */ #define SNTP_MSG_LEN 48 #define SNTP_OFFSET_LI_VN_MODE 0 #define SNTP_LI_MASK 0xC0 #define SNTP_LI_NO_WARNING 0x00 #define SNTP_LI_LAST_MINUTE_61_SEC 0x01 #define SNTP_LI_LAST_MINUTE_59_SEC 0x02 #define SNTP_LI_ALARM_CONDITION 0x03 /* (clock not synchronized) */ #define SNTP_VERSION_MASK 0x38 #define SNTP_VERSION (4/* NTP Version 4*/<<3) #define SNTP_MODE_MASK 0x07 #define SNTP_MODE_CLIENT 0x03 #define SNTP_MODE_SERVER 0x04 #define SNTP_MODE_BROADCAST 0x05 #define SNTP_OFFSET_STRATUM 1 #define SNTP_STRATUM_KOD 0x00 #define SNTP_OFFSET_ORIGINATE_TIME 24 #define SNTP_OFFSET_RECEIVE_TIME 32 #define SNTP_OFFSET_TRANSMIT_TIME 40 /* number of seconds between 1900 and 1970 */ #define DIFF_SEC_1900_1970 (2208988800UL) /** * SNTP packet format (without optional fields) * Timestamps are coded as 64 bits: * - 32 bits seconds since Jan 01, 1970, 00:00 * - 32 bits seconds fraction (0-padded) * For future use, if the MSB in the seconds part is set, seconds are based * on Feb 07, 2036, 06:28:16. */ #ifdef PACK_STRUCT_USE_INCLUDES # include "arch/bpstruct.h" #endif PACK_STRUCT_BEGIN struct sntp_msg { PACK_STRUCT_FIELD(u8_t li_vn_mode); PACK_STRUCT_FIELD(u8_t stratum); PACK_STRUCT_FIELD(u8_t poll); PACK_STRUCT_FIELD(u8_t precision); PACK_STRUCT_FIELD(u32_t root_delay); PACK_STRUCT_FIELD(u32_t root_dispersion); PACK_STRUCT_FIELD(u32_t reference_identifier); PACK_STRUCT_FIELD(u32_t reference_timestamp[2]); PACK_STRUCT_FIELD(u32_t originate_timestamp[2]); PACK_STRUCT_FIELD(u32_t receive_timestamp[2]); PACK_STRUCT_FIELD(u32_t transmit_timestamp[2]); } PACK_STRUCT_STRUCT; PACK_STRUCT_END #ifdef PACK_STRUCT_USE_INCLUDES # include "arch/epstruct.h" #endif /* function prototypes */ static void sntp_request(void *arg); /** The UDP pcb used by the SNTP client */ static struct udp_pcb* sntp_pcb; /** Addresses of servers */ static char* sntp_server_addresses[] = {SNTP_SERVER_ADDRESS}; #if SNTP_SUPPORT_MULTIPLE_SERVERS /** The currently used server (initialized to 0) */ static u8_t sntp_current_server; static u8_t sntp_num_servers = sizeof(sntp_server_addresses)/sizeof(char*); #else /* SNTP_SUPPORT_MULTIPLE_SERVERS */ #define sntp_current_server 0 #endif /* SNTP_SUPPORT_MULTIPLE_SERVERS */ #if SNTP_RETRY_TIMEOUT_EXP #define SNTP_RESET_RETRY_TIMEOUT() sntp_retry_timeout = SNTP_RETRY_TIMEOUT /** Retry time, initialized with SNTP_RETRY_TIMEOUT and doubled with each retry. */ static u32_t sntp_retry_timeout; #else /* SNTP_RETRY_TIMEOUT_EXP */ #define SNTP_RESET_RETRY_TIMEOUT() #define sntp_retry_timeout SNTP_RETRY_TIMEOUT #endif /* SNTP_RETRY_TIMEOUT_EXP */ #if SNTP_CHECK_RESPONSE >= 1 /** Saves the last server address to compare with response */ static ip_addr_t sntp_last_server_address; #endif /* SNTP_CHECK_RESPONSE >= 1 */ #if SNTP_CHECK_RESPONSE >= 2 /** Saves the last timestamp sent (which is sent back by the server) * to compare against in response */ static u32_t sntp_last_timestamp_sent[2]; #endif /* SNTP_CHECK_RESPONSE >= 2 */ /** * SNTP processing of received timestamp */ static void sntp_process(u32_t *receive_timestamp) { /* convert SNTP time (1900-based) to unix GMT time (1970-based) * @todo: if MSB is 1, SNTP time is 2036-based! */ time_t t = (ntohl(receive_timestamp[0]) - DIFF_SEC_1900_1970); #if SNTP_CALC_TIME_US u32_t us = ntohl(receive_timestamp[1]) / 4295; SNTP_SET_SYSTEM_TIME_US(t, us); /* display local time from GMT time */ LWIP_DEBUGF(SNTP_DEBUG_TRACE, ("sntp_process: %s, %"U32_F" us", ctime(&t), us)); #else /* SNTP_CALC_TIME_US */ /* change system time and/or the update the RTC clock */ SNTP_SET_SYSTEM_TIME(t); /* display local time from GMT time */ LWIP_DEBUGF(SNTP_DEBUG_TRACE, ("sntp_process: %s", ctime(&t))); #endif /* SNTP_CALC_TIME_US */ } /** * Initialize request struct to be sent to server. */ static void sntp_initialize_request(struct sntp_msg *req) { memset(req, 0, SNTP_MSG_LEN); req->li_vn_mode = SNTP_LI_NO_WARNING | SNTP_VERSION | SNTP_MODE_CLIENT; #if SNTP_CHECK_RESPONSE >= 2 { u32_t sntp_time_sec, sntp_time_us; /* fill in transmit timestamp and save it in 'sntp_last_timestamp_sent' */ SNTP_GET_SYSTEM_TIME(sntp_time_sec, sntp_time_us); sntp_last_timestamp_sent[0] = htonl(sntp_time_sec + DIFF_SEC_1900_1970); req->transmit_timestamp[0] = sntp_last_timestamp_sent[0]; /* we send/save us instead of fraction to be faster... */ sntp_last_timestamp_sent[1] = htonl(sntp_time_us); req->transmit_timestamp[1] = sntp_last_timestamp_sent[1]; } #endif /* SNTP_CHECK_RESPONSE >= 2 */ } /** * Retry: send a new request (and increase retry timeout). * * @param arg is unused (only necessary to conform to sys_timeout) */ static void sntp_retry(void* arg) { LWIP_UNUSED_ARG(arg); LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_retry: Next request will be sent in %"U32_F" ms\n", sntp_retry_timeout)); /* set up a timer to send a retry and increase the retry delay */ sys_timeout(sntp_retry_timeout, sntp_request, NULL); #if SNTP_RETRY_TIMEOUT_EXP { u32_t new_retry_timeout; /* increase the timeout for next retry */ new_retry_timeout = sntp_retry_timeout << 1; /* limit to maximum timeout and prevent overflow */ if ((new_retry_timeout <= SNTP_RETRY_TIMEOUT_MAX) && (new_retry_timeout > sntp_retry_timeout)) { sntp_retry_timeout = new_retry_timeout; } } #endif /* SNTP_RETRY_TIMEOUT_EXP */ } #if SNTP_SUPPORT_MULTIPLE_SERVERS /** * If Kiss-of-Death is received (or another packet parsing error), * try the next server or retry the current server and increase the retry * timeout if only one server is available. * * @param arg is unused (only necessary to conform to sys_timeout) */ static void sntp_try_next_server(void* arg) { LWIP_UNUSED_ARG(arg); if (sntp_num_servers > 1) { /* new server: reset retry timeout */ SNTP_RESET_RETRY_TIMEOUT(); sntp_current_server++; if (sntp_current_server >= sntp_num_servers) { sntp_current_server = 0; } LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_try_next_server: Sending request to server %"U16_F"\n", (u16_t)sntp_current_server)); /* instantly send a request to the next server */ sntp_request(NULL); } else { sntp_retry(NULL); } } #else /* SNTP_SUPPORT_MULTIPLE_SERVERS */ /* Always retry on error if only one server is supported */ #define sntp_try_next_server sntp_retry #endif /* SNTP_SUPPORT_MULTIPLE_SERVERS */ /** UDP recv callback for the sntp pcb */ static void sntp_recv(void *arg, struct udp_pcb* pcb, struct pbuf *p, ip_addr_t *addr, u16_t port) { u8_t mode; u8_t stratum; u32_t receive_timestamp[SNTP_RECEIVE_TIME_SIZE]; err_t err; LWIP_UNUSED_ARG(arg); LWIP_UNUSED_ARG(pcb); /* packet received: stop retry timeout */ sys_untimeout(sntp_try_next_server, NULL); sys_untimeout(sntp_request, NULL); err = ERR_ARG; #if SNTP_CHECK_RESPONSE >= 1 /* check server address and port */ if (ip_addr_cmp(addr, &sntp_last_server_address) && (port == SNTP_PORT)) #else /* SNTP_CHECK_RESPONSE >= 1 */ LWIP_UNUSED_ARG(addr); LWIP_UNUSED_ARG(port); #endif /* SNTP_CHECK_RESPONSE >= 1 */ { /* process the response */ if (p->tot_len == SNTP_MSG_LEN) { pbuf_copy_partial(p, &mode, 1, SNTP_OFFSET_LI_VN_MODE); mode &= SNTP_MODE_MASK; /* if this is a SNTP response... */ if ((mode == SNTP_MODE_SERVER) || (mode == SNTP_MODE_BROADCAST)) { pbuf_copy_partial(p, &stratum, 1, SNTP_OFFSET_STRATUM); if (stratum == SNTP_STRATUM_KOD) { /* Kiss-of-death packet. Use another server or increase UPDATE_DELAY. */ err = SNTP_ERR_KOD; LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_recv: Received Kiss-of-Death\n")); } else { #if SNTP_CHECK_RESPONSE >= 2 /* check originate_timetamp against sntp_last_timestamp_sent */ u32_t originate_timestamp[2]; pbuf_copy_partial(p, &originate_timestamp, 8, SNTP_OFFSET_ORIGINATE_TIME); if ((originate_timestamp[0] != sntp_last_timestamp_sent[0]) || (originate_timestamp[1] != sntp_last_timestamp_sent[1])) { LWIP_DEBUGF(SNTP_DEBUG_WARN, ("sntp_recv: Invalid originate timestamp in response\n")); } else #endif /* SNTP_CHECK_RESPONSE >= 2 */ /* @todo: add code for SNTP_CHECK_RESPONSE >= 3 and >= 4 here */ { /* correct answer */ err = ERR_OK; pbuf_copy_partial(p, &receive_timestamp, SNTP_RECEIVE_TIME_SIZE * 4, SNTP_OFFSET_RECEIVE_TIME); } } } else { LWIP_DEBUGF(SNTP_DEBUG_WARN, ("sntp_recv: Invalid mode in response: %"U16_F"\n", (u16_t)mode)); } } else { LWIP_DEBUGF(SNTP_DEBUG_WARN, ("sntp_recv: Invalid packet length: %"U16_F"\n", p->tot_len)); } } pbuf_free(p); if (err == ERR_OK) { /* Correct response, reset retry timeout */ SNTP_RESET_RETRY_TIMEOUT(); sntp_process(receive_timestamp); /* Set up timeout for next request */ sys_timeout((u32_t)SNTP_UPDATE_DELAY, sntp_request, NULL); LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_recv: Scheduled next time request: %"U32_F" ms\n", (u32_t)SNTP_UPDATE_DELAY)); } else if (err == SNTP_ERR_KOD) { /* Kiss-of-death packet. Use another server or increase UPDATE_DELAY. */ sntp_try_next_server(NULL); } else { /* another error, try the same server again */ sntp_retry(NULL); } } /** Actually send an sntp request to a server. * * @param server_addr resolved IP address of the SNTP server */ static void sntp_send_request(ip_addr_t *server_addr) { struct pbuf* p; p = pbuf_alloc(PBUF_TRANSPORT, SNTP_MSG_LEN, PBUF_RAM); if (p != NULL) { struct sntp_msg *sntpmsg = (struct sntp_msg *)p->payload; LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_send_request: Sending request to server\n")); /* initialize request message */ sntp_initialize_request(sntpmsg); /* send request */ udp_sendto(sntp_pcb, p, server_addr, SNTP_PORT); /* free the pbuf after sending it */ pbuf_free(p); /* set up receive timeout: try next server or retry on timeout */ sys_timeout((u32_t)SNTP_RECV_TIMEOUT, sntp_try_next_server, NULL); #if SNTP_CHECK_RESPONSE >= 1 /* save server address to verify it in sntp_recv */ ip_addr_set(&sntp_last_server_address, server_addr); #endif /* SNTP_CHECK_RESPONSE >= 1 */ } else { LWIP_DEBUGF(SNTP_DEBUG_SERIOUS, ("sntp_send_request: Out of memory, trying again in %"U32_F" ms\n", (u32_t)SNTP_RETRY_TIMEOUT)); /* out of memory: set up a timer to send a retry */ sys_timeout((u32_t)SNTP_RETRY_TIMEOUT, sntp_request, NULL); } } #if SNTP_SERVER_DNS /** * DNS found callback when using DNS names as server address. */ static void sntp_dns_found(const char* hostname, ip_addr_t *ipaddr, void *arg) { LWIP_UNUSED_ARG(hostname); LWIP_UNUSED_ARG(arg); if (ipaddr != NULL) { /* Address resolved, send request */ LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_dns_found: Server address resolved, sending request\n")); sntp_send_request(ipaddr); } else { /* DNS resolving failed -> try another server */ LWIP_DEBUGF(SNTP_DEBUG_WARN_STATE, ("sntp_dns_found: Failed to resolve server address resolved, trying next server\n")); sntp_try_next_server(NULL); } } #endif /* SNTP_SERVER_DNS */ /** * Send out an sntp request. * * @param arg is unused (only necessary to conform to sys_timeout) */ static void sntp_request(void *arg) { ip_addr_t sntp_server_address; err_t err; LWIP_UNUSED_ARG(arg); /* initialize SNTP server address */ #if SNTP_SERVER_DNS err = dns_gethostbyname(sntp_server_addresses[sntp_current_server], &sntp_server_address, sntp_dns_found, NULL); if (err == ERR_INPROGRESS) { /* DNS request sent, wait for sntp_dns_found being called */ LWIP_DEBUGF(SNTP_DEBUG_STATE, ("sntp_request: Waiting for server address to be resolved.\n")); return; } #else /* SNTP_SERVER_DNS */ err = ipaddr_aton(sntp_server_addresses[sntp_current_server], &sntp_server_address) ? ERR_OK : ERR_ARG; #endif /* SNTP_SERVER_DNS */ if (err == ERR_OK) { sntp_send_request(&sntp_server_address); } else { /* address conversion failed, try another server */ LWIP_DEBUGF(SNTP_DEBUG_WARN_STATE, ("sntp_request: Invalid server address, trying next server.\n")); sys_timeout((u32_t)SNTP_RETRY_TIMEOUT, sntp_try_next_server, NULL); } } /** * Initialize this module. * Send out request instantly or after SNTP_STARTUP_DELAY(_FUNC). */ void sntp_init(void) { if (sntp_pcb == NULL) { SNTP_RESET_RETRY_TIMEOUT(); sntp_pcb = udp_new(); LWIP_ASSERT("Failed to allocate udp pcb for sntp client", sntp_pcb != NULL); if (sntp_pcb != NULL) { udp_recv(sntp_pcb, sntp_recv, NULL); #if SNTP_STARTUP_DELAY sys_timeout((u32_t)SNTP_STARTUP_DELAY_FUNC, sntp_request, NULL); #else sntp_request(NULL); #endif } } } /** * Stop this module. */ void sntp_stop(void) { if (sntp_pcb != NULL) { sys_untimeout(sntp_request, NULL); udp_remove(sntp_pcb); sntp_pcb = NULL; } } #endif /* LWIP_UDP */ ocproxy-1.60/contrib/apps/sntp/sntp.h000066400000000000000000000002641303453231400176670ustar00rootroot00000000000000#ifndef LWIP_SNTP_H #define LWIP_SNTP_H #ifdef __cplusplus extern "C" { #endif void sntp_init(void); void sntp_stop(void); #ifdef __cplusplus } #endif #endif /* LWIP_SNTP_H */ ocproxy-1.60/contrib/apps/socket_examples/000077500000000000000000000000001303453231400207325ustar00rootroot00000000000000ocproxy-1.60/contrib/apps/socket_examples/socket_examples.c000066400000000000000000000323061303453231400242700ustar00rootroot00000000000000 #include "socket_examples.h" #include "lwip/opt.h" #if LWIP_SOCKET #include "lwip/sockets.h" #include "lwip/sys.h" #include #include #ifndef SOCK_TARGET_HOST #define SOCK_TARGET_HOST "192.168.1.1" #endif #ifndef SOCK_TARGET_PORT #define SOCK_TARGET_PORT 80 #endif /** This is an example function that tests blocking- and nonblocking connect. */ static void sockex_nonblocking_connect(void *arg) { int s; int ret; u32_t opt; struct sockaddr_in addr; fd_set readset; fd_set writeset; fd_set errset; struct timeval tv; u32_t ticks_a, ticks_b; int err; LWIP_UNUSED_ARG(arg); /* set up address to connect to */ memset(&addr, 0, sizeof(addr)); addr.sin_len = sizeof(addr); addr.sin_family = AF_INET; addr.sin_port = PP_HTONS(SOCK_TARGET_PORT); addr.sin_addr.s_addr = inet_addr(SOCK_TARGET_HOST); /* first try blocking: */ /* create the socket */ s = lwip_socket(AF_INET, SOCK_STREAM, 0); LWIP_ASSERT("s >= 0", s >= 0); /* connect */ ret = lwip_connect(s, (struct sockaddr*)&addr, sizeof(addr)); /* should succeed */ LWIP_ASSERT("ret == 0", ret == 0); /* write something */ ret = lwip_write(s, "test", 4); LWIP_ASSERT("ret == 4", ret == 4); /* close */ ret = lwip_close(s); LWIP_ASSERT("ret == 0", ret == 0); /* now try nonblocking and close before being connected */ /* create the socket */ s = lwip_socket(AF_INET, SOCK_STREAM, 0); LWIP_ASSERT("s >= 0", s >= 0); /* nonblocking */ opt = lwip_fcntl(s, F_GETFL, 0); LWIP_ASSERT("ret != -1", ret != -1); opt |= O_NONBLOCK; ret = lwip_fcntl(s, F_SETFL, opt); LWIP_ASSERT("ret != -1", ret != -1); /* connect */ ret = lwip_connect(s, (struct sockaddr*)&addr, sizeof(addr)); /* should have an error: "inprogress" */ LWIP_ASSERT("ret == -1", ret == -1); err = errno; LWIP_ASSERT("errno == EINPROGRESS", err == EINPROGRESS); /* close */ ret = lwip_close(s); LWIP_ASSERT("ret == 0", ret == 0); /* try to close again, should fail with EBADF */ ret = lwip_close(s); LWIP_ASSERT("ret == -1", ret == -1); err = errno; LWIP_ASSERT("errno == EBADF", err == EBADF); printf("closing socket in nonblocking connect succeeded\n"); /* now try nonblocking, connect should succeed: this test only works if it is fast enough, i.e. no breakpoints, please! */ /* create the socket */ s = lwip_socket(AF_INET, SOCK_STREAM, 0); LWIP_ASSERT("s >= 0", s >= 0); /* nonblocking */ opt = 1; ret = lwip_ioctl(s, FIONBIO, &opt); LWIP_ASSERT("ret == 0", ret == 0); /* connect */ ret = lwip_connect(s, (struct sockaddr*)&addr, sizeof(addr)); /* should have an error: "inprogress" */ LWIP_ASSERT("ret == -1", ret == -1); err = errno; LWIP_ASSERT("errno == EINPROGRESS", err == EINPROGRESS); /* write should fail, too */ ret = lwip_write(s, "test", 4); LWIP_ASSERT("ret == -1", ret == -1); err = errno; LWIP_ASSERT("errno == EINPROGRESS", err == EINPROGRESS); FD_ZERO(&readset); FD_SET(s, &readset); FD_ZERO(&writeset); FD_SET(s, &writeset); FD_ZERO(&errset); FD_SET(s, &errset); tv.tv_sec = 0; tv.tv_usec = 0; /* select without waiting should fail */ ret = lwip_select(s + 1, &readset, &writeset, &errset, &tv); LWIP_ASSERT("ret == 0", ret == 0); LWIP_ASSERT("!FD_ISSET(s, &writeset)", !FD_ISSET(s, &writeset)); LWIP_ASSERT("!FD_ISSET(s, &readset)", !FD_ISSET(s, &readset)); LWIP_ASSERT("!FD_ISSET(s, &errset)", !FD_ISSET(s, &errset)); FD_ZERO(&readset); FD_SET(s, &readset); FD_ZERO(&writeset); FD_SET(s, &writeset); FD_ZERO(&errset); FD_SET(s, &errset); ticks_a = sys_now(); /* select with waiting should succeed */ ret = lwip_select(s + 1, &readset, &writeset, &errset, NULL); ticks_b = sys_now(); LWIP_ASSERT("ret == 1", ret == 1); LWIP_ASSERT("FD_ISSET(s, &writeset)", FD_ISSET(s, &writeset)); LWIP_ASSERT("!FD_ISSET(s, &readset)", !FD_ISSET(s, &readset)); LWIP_ASSERT("!FD_ISSET(s, &errset)", !FD_ISSET(s, &errset)); /* now write should succeed */ ret = lwip_write(s, "test", 4); LWIP_ASSERT("ret == 4", ret == 4); /* close */ ret = lwip_close(s); LWIP_ASSERT("ret == 0", ret == 0); printf("select() needed %d ticks to return writable\n", ticks_b - ticks_a); /* now try nonblocking to invalid address: this test only works if it is fast enough, i.e. no breakpoints, please! */ /* create the socket */ s = lwip_socket(AF_INET, SOCK_STREAM, 0); LWIP_ASSERT("s >= 0", s >= 0); /* nonblocking */ opt = 1; ret = lwip_ioctl(s, FIONBIO, &opt); LWIP_ASSERT("ret == 0", ret == 0); addr.sin_addr.s_addr++; /* connect */ ret = lwip_connect(s, (struct sockaddr*)&addr, sizeof(addr)); /* should have an error: "inprogress" */ LWIP_ASSERT("ret == -1", ret == -1); err = errno; LWIP_ASSERT("errno == EINPROGRESS", err == EINPROGRESS); /* write should fail, too */ ret = lwip_write(s, "test", 4); LWIP_ASSERT("ret == -1", ret == -1); err = errno; LWIP_ASSERT("errno == EINPROGRESS", err == EINPROGRESS); FD_ZERO(&readset); FD_SET(s, &readset); FD_ZERO(&writeset); FD_SET(s, &writeset); FD_ZERO(&errset); FD_SET(s, &errset); tv.tv_sec = 0; tv.tv_usec = 0; /* select without waiting should fail */ ret = lwip_select(s + 1, &readset, &writeset, &errset, &tv); LWIP_ASSERT("ret == 0", ret == 0); FD_ZERO(&readset); FD_SET(s, &readset); FD_ZERO(&writeset); FD_SET(s, &writeset); FD_ZERO(&errset); FD_SET(s, &errset); ticks_a = sys_now(); /* select with waiting should eventually succeed and return errset! */ ret = lwip_select(s + 1, &readset, &writeset, &errset, NULL); ticks_b = sys_now(); LWIP_ASSERT("ret > 0", ret > 0); LWIP_ASSERT("FD_ISSET(s, &errset)", FD_ISSET(s, &errset)); LWIP_ASSERT("!FD_ISSET(s, &readset)", !FD_ISSET(s, &readset)); LWIP_ASSERT("!FD_ISSET(s, &writeset)", !FD_ISSET(s, &writeset)); /* close */ ret = lwip_close(s); LWIP_ASSERT("ret == 0", ret == 0); printf("select() needed %d ticks to return error\n", ticks_b - ticks_a); printf("all tests done, thread ending\n"); } /** This is an example function that tests the recv function (timeout etc.). */ static void sockex_testrecv(void *arg) { int s; int ret; int err; int opt; struct sockaddr_in addr; size_t len; char rxbuf[1024]; fd_set readset; fd_set errset; struct timeval tv; LWIP_UNUSED_ARG(arg); /* set up address to connect to */ memset(&addr, 0, sizeof(addr)); addr.sin_len = sizeof(addr); addr.sin_family = AF_INET; addr.sin_port = PP_HTONS(SOCK_TARGET_PORT); addr.sin_addr.s_addr = inet_addr(SOCK_TARGET_HOST); /* first try blocking: */ /* create the socket */ s = lwip_socket(AF_INET, SOCK_STREAM, 0); LWIP_ASSERT("s >= 0", s >= 0); /* connect */ ret = lwip_connect(s, (struct sockaddr*)&addr, sizeof(addr)); /* should succeed */ LWIP_ASSERT("ret == 0", ret == 0); /* set recv timeout (100 ms) */ opt = 100; ret = lwip_setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &opt, sizeof(int)); LWIP_ASSERT("ret == 0", ret == 0); /* write the start of a GET request */ #define SNDSTR1 "G" len = strlen(SNDSTR1); ret = lwip_write(s, SNDSTR1, len); LWIP_ASSERT("ret == len", ret == (int)len); /* should time out if the other side is a good HTTP server */ ret = lwip_read(s, rxbuf, 1); LWIP_ASSERT("ret == -1", ret == -1); err = errno; LWIP_ASSERT("errno == EAGAIN", err == EAGAIN); /* write the rest of a GET request */ #define SNDSTR2 "ET / HTTP_1.1\r\n\r\n" len = strlen(SNDSTR2); ret = lwip_write(s, SNDSTR2, len); LWIP_ASSERT("ret == len", ret == (int)len); /* wait a while: should be enough for the server to send a response */ sys_msleep(1000); /* should not time out but receive a response */ ret = lwip_read(s, rxbuf, 1024); LWIP_ASSERT("ret > 0", ret > 0); /* now select should directly return because the socket is readable */ FD_ZERO(&readset); FD_ZERO(&errset); FD_SET(s, &readset); FD_SET(s, &errset); tv.tv_sec = 10; tv.tv_usec = 0; ret = lwip_select(s + 1, &readset, NULL, &errset, &tv); LWIP_ASSERT("ret == 1", ret == 1); LWIP_ASSERT("!FD_ISSET(s, &errset)", !FD_ISSET(s, &errset)); LWIP_ASSERT("FD_ISSET(s, &readset)", FD_ISSET(s, &readset)); /* should not time out but receive a response */ ret = lwip_read(s, rxbuf, 1024); /* might receive a second packet for HTTP/1.1 servers */ if (ret > 0) { /* should return 0: closed */ ret = lwip_read(s, rxbuf, 1024); LWIP_ASSERT("ret == 0", ret == 0); } /* close */ ret = lwip_close(s); LWIP_ASSERT("ret == 0", ret == 0); printf("sockex_testrecv finished successfully\n"); } /** helper struct for the 2 functions below (multithreaded: thread-argument) */ struct sockex_select_helper { int socket; int wait_read; int expect_read; int wait_write; int expect_write; int wait_err; int expect_err; int wait_ms; sys_sem_t sem; }; /** helper thread to wait for socket events using select */ static void sockex_select_waiter(void *arg) { struct sockex_select_helper *helper = (struct sockex_select_helper *)arg; int ret; fd_set readset; fd_set writeset; fd_set errset; struct timeval tv; LWIP_ASSERT("helper != NULL", helper != NULL); FD_ZERO(&readset); FD_ZERO(&writeset); FD_ZERO(&errset); if (helper->wait_read) { FD_SET(helper->socket, &readset); } if (helper->wait_write) { FD_SET(helper->socket, &writeset); } if (helper->wait_err) { FD_SET(helper->socket, &errset); } tv.tv_sec = helper->wait_ms / 1000; tv.tv_usec = (helper->wait_ms % 1000) * 1000; ret = lwip_select(helper->socket, &readset, &writeset, &errset, &tv); if (helper->expect_read || helper->expect_write || helper->expect_err) { LWIP_ASSERT("ret > 0", ret > 0); } else { LWIP_ASSERT("ret == 0", ret == 0); } if (helper->expect_read) { LWIP_ASSERT("FD_ISSET(helper->socket, &readset)", FD_ISSET(helper->socket, &readset)); } else { LWIP_ASSERT("!FD_ISSET(helper->socket, &readset)", !FD_ISSET(helper->socket, &readset)); } if (helper->expect_write) { LWIP_ASSERT("FD_ISSET(helper->socket, &writeset)", FD_ISSET(helper->socket, &writeset)); } else { LWIP_ASSERT("!FD_ISSET(helper->socket, &writeset)", !FD_ISSET(helper->socket, &writeset)); } if (helper->expect_err) { LWIP_ASSERT("FD_ISSET(helper->socket, &errset)", FD_ISSET(helper->socket, &errset)); } else { LWIP_ASSERT("!FD_ISSET(helper->socket, &errset)", !FD_ISSET(helper->socket, &errset)); } sys_sem_signal(&helper->sem); } /** This is an example function that tests more than one thread being active in select. */ static void sockex_testtwoselects(void *arg) { int s1; int s2; int ret; struct sockaddr_in addr; size_t len; err_t lwiperr; struct sockex_select_helper h1, h2, h3, h4; LWIP_UNUSED_ARG(arg); /* set up address to connect to */ memset(&addr, 0, sizeof(addr)); addr.sin_len = sizeof(addr); addr.sin_family = AF_INET; addr.sin_port = PP_HTONS(SOCK_TARGET_PORT); addr.sin_addr.s_addr = inet_addr(SOCK_TARGET_HOST); /* create the sockets */ s1 = lwip_socket(AF_INET, SOCK_STREAM, 0); LWIP_ASSERT("s1 >= 0", s1 >= 0); s2 = lwip_socket(AF_INET, SOCK_STREAM, 0); LWIP_ASSERT("s2 >= 0", s2 >= 0); /* connect, should succeed */ ret = lwip_connect(s1, (struct sockaddr*)&addr, sizeof(addr)); LWIP_ASSERT("ret == 0", ret == 0); ret = lwip_connect(s2, (struct sockaddr*)&addr, sizeof(addr)); LWIP_ASSERT("ret == 0", ret == 0); /* write the start of a GET request */ #define SNDSTR1 "G" len = strlen(SNDSTR1); ret = lwip_write(s1, SNDSTR1, len); LWIP_ASSERT("ret == len", ret == (int)len); ret = lwip_write(s2, SNDSTR1, len); LWIP_ASSERT("ret == len", ret == (int)len); h1.wait_read = 1; h1.wait_write = 1; h1.wait_err = 1; h1.expect_read = 0; h1.expect_write = 0; h1.expect_err = 0; lwiperr = sys_sem_new(&h1.sem, 0); LWIP_ASSERT("lwiperr == ERR_OK", lwiperr == ERR_OK); h1.socket = s1; h1.wait_ms = 500; h2 = h1; lwiperr = sys_sem_new(&h2.sem, 0); LWIP_ASSERT("lwiperr == ERR_OK", lwiperr == ERR_OK); h2.socket = s2; h2.wait_ms = 1000; h3 = h1; lwiperr = sys_sem_new(&h3.sem, 0); LWIP_ASSERT("lwiperr == ERR_OK", lwiperr == ERR_OK); h3.socket = s2; h3.wait_ms = 1500; h4 = h1; lwiperr = sys_sem_new(&h4.sem, 0); LWIP_ASSERT("lwiperr == ERR_OK", lwiperr == ERR_OK); h4.socket = s2; h4.wait_ms = 2000; /* select: all sockets should time out if the other side is a good HTTP server */ sys_thread_new("sockex_select_waiter1", sockex_select_waiter, &h2, 0, 0); sys_msleep(100); sys_thread_new("sockex_select_waiter2", sockex_select_waiter, &h1, 0, 0); sys_msleep(100); sys_thread_new("sockex_select_waiter2", sockex_select_waiter, &h4, 0, 0); sys_msleep(100); sys_thread_new("sockex_select_waiter2", sockex_select_waiter, &h3, 0, 0); sys_sem_wait(&h1.sem); sys_sem_wait(&h2.sem); sys_sem_wait(&h3.sem); sys_sem_wait(&h4.sem); /* close */ ret = lwip_close(s1); LWIP_ASSERT("ret == 0", ret == 0); ret = lwip_close(s2); LWIP_ASSERT("ret == 0", ret == 0); printf("sockex_testtwoselects finished successfully\n"); } void socket_examples_init(void) { sys_thread_new("sockex_nonblocking_connect", sockex_nonblocking_connect, NULL, 0, 0); sys_thread_new("sockex_testrecv", sockex_testrecv, NULL, 0, 0); /*sys_thread_new("sockex_testtwoselects", sockex_testtwoselects, NULL, 0, 0);*/ } #endif /* LWIP_SOCKETS */ ocproxy-1.60/contrib/apps/socket_examples/socket_examples.h000066400000000000000000000002051303453231400242660ustar00rootroot00000000000000#ifndef LWIP_SOCKET_EXAMPLES_H #define LWIP_SOCKET_EXAMPLES_H void socket_examples_init(void); #endif /* LWIP_SOCKET_EXAMPLES_H */ ocproxy-1.60/contrib/apps/tcpecho/000077500000000000000000000000001303453231400171715ustar00rootroot00000000000000ocproxy-1.60/contrib/apps/tcpecho/tcpecho.c000066400000000000000000000064711303453231400207720ustar00rootroot00000000000000/* * Copyright (c) 2001-2003 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #include "tcpecho.h" #include "lwip/opt.h" #if LWIP_NETCONN #include "lwip/sys.h" #include "lwip/api.h" /*-----------------------------------------------------------------------------------*/ static void tcpecho_thread(void *arg) { struct netconn *conn, *newconn; err_t err; LWIP_UNUSED_ARG(arg); /* Create a new connection identifier. */ conn = netconn_new(NETCONN_TCP); /* Bind connection to well known port number 7. */ netconn_bind(conn, NULL, 7); /* Tell connection to go into listening mode. */ netconn_listen(conn); while (1) { /* Grab new connection. */ err = netconn_accept(conn, &newconn); /*printf("accepted new connection %p\n", newconn);*/ /* Process the new connection. */ if (err == ERR_OK) { struct netbuf *buf; void *data; u16_t len; while ((err = netconn_recv(newconn, &buf)) == ERR_OK) { /*printf("Recved\n");*/ do { netbuf_data(buf, &data, &len); err = netconn_write(newconn, data, len, NETCONN_COPY); #if 0 if (err != ERR_OK) { printf("tcpecho: netconn_write: error \"%s\"\n", lwip_strerr(err)); } #endif } while (netbuf_next(buf) >= 0); netbuf_delete(buf); } /*printf("Got EOF, looping\n");*/ /* Close connection and discard connection identifier. */ netconn_close(newconn); netconn_delete(newconn); } } } /*-----------------------------------------------------------------------------------*/ void tcpecho_init(void) { sys_thread_new("tcpecho_thread", tcpecho_thread, NULL, DEFAULT_THREAD_STACKSIZE, DEFAULT_THREAD_PRIO); } /*-----------------------------------------------------------------------------------*/ #endif /* LWIP_NETCONN */ ocproxy-1.60/contrib/apps/tcpecho/tcpecho.h000066400000000000000000000032561303453231400207750ustar00rootroot00000000000000/* * Copyright (c) 2001-2003 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #ifndef LWIP_TCPECHO_H #define LWIP_TCPECHO_H void tcpecho_init(void); #endif /* LWIP_TCPECHO_H */ ocproxy-1.60/contrib/apps/tcpecho_raw/000077500000000000000000000000001303453231400200425ustar00rootroot00000000000000ocproxy-1.60/contrib/apps/tcpecho_raw/echo.c000066400000000000000000000175171303453231400211370ustar00rootroot00000000000000/* * Copyright (c) 2001-2004 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of and a contribution to the lwIP TCP/IP stack. * * Credits go to Adam Dunkels (and the current maintainers) of this software. * * Christiaan Simons rewrote this file to get a more stable echo example. */ /** * @file * TCP echo server example using raw API. * * Echos all bytes sent by connecting client, * and passively closes when client is done. * */ #include "lwip/opt.h" #include "lwip/debug.h" #include "lwip/stats.h" #include "lwip/tcp.h" #include "echo.h" #if LWIP_TCP static struct tcp_pcb *echo_pcb; enum echo_states { ES_NONE = 0, ES_ACCEPTED, ES_RECEIVED, ES_CLOSING }; struct echo_state { u8_t state; u8_t retries; struct tcp_pcb *pcb; /* pbuf (chain) to recycle */ struct pbuf *p; }; err_t echo_accept(void *arg, struct tcp_pcb *newpcb, err_t err); err_t echo_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err); void echo_error(void *arg, err_t err); err_t echo_poll(void *arg, struct tcp_pcb *tpcb); err_t echo_sent(void *arg, struct tcp_pcb *tpcb, u16_t len); void echo_send(struct tcp_pcb *tpcb, struct echo_state *es); void echo_close(struct tcp_pcb *tpcb, struct echo_state *es); void echo_init(void) { echo_pcb = tcp_new(); if (echo_pcb != NULL) { err_t err; err = tcp_bind(echo_pcb, IP_ADDR_ANY, 7); if (err == ERR_OK) { echo_pcb = tcp_listen(echo_pcb); tcp_accept(echo_pcb, echo_accept); } else { /* abort? output diagnostic? */ } } else { /* abort? output diagnostic? */ } } err_t echo_accept(void *arg, struct tcp_pcb *newpcb, err_t err) { err_t ret_err; struct echo_state *es; LWIP_UNUSED_ARG(arg); LWIP_UNUSED_ARG(err); /* Unless this pcb should have NORMAL priority, set its priority now. When running out of pcbs, low priority pcbs can be aborted to create new pcbs of higher priority. */ tcp_setprio(newpcb, TCP_PRIO_MIN); es = (struct echo_state *)mem_malloc(sizeof(struct echo_state)); if (es != NULL) { es->state = ES_ACCEPTED; es->pcb = newpcb; es->retries = 0; es->p = NULL; /* pass newly allocated es to our callbacks */ tcp_arg(newpcb, es); tcp_recv(newpcb, echo_recv); tcp_err(newpcb, echo_error); tcp_poll(newpcb, echo_poll, 0); ret_err = ERR_OK; } else { ret_err = ERR_MEM; } return ret_err; } err_t echo_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err) { struct echo_state *es; err_t ret_err; LWIP_ASSERT("arg != NULL",arg != NULL); es = (struct echo_state *)arg; if (p == NULL) { /* remote host closed connection */ es->state = ES_CLOSING; if(es->p == NULL) { /* we're done sending, close it */ echo_close(tpcb, es); } else { /* we're not done yet */ tcp_sent(tpcb, echo_sent); echo_send(tpcb, es); } ret_err = ERR_OK; } else if(err != ERR_OK) { /* cleanup, for unkown reason */ if (p != NULL) { es->p = NULL; pbuf_free(p); } ret_err = err; } else if(es->state == ES_ACCEPTED) { /* first data chunk in p->payload */ es->state = ES_RECEIVED; /* store reference to incoming pbuf (chain) */ es->p = p; /* install send completion notifier */ tcp_sent(tpcb, echo_sent); echo_send(tpcb, es); ret_err = ERR_OK; } else if (es->state == ES_RECEIVED) { /* read some more data */ if(es->p == NULL) { es->p = p; tcp_sent(tpcb, echo_sent); echo_send(tpcb, es); } else { struct pbuf *ptr; /* chain pbufs to the end of what we recv'ed previously */ ptr = es->p; pbuf_chain(ptr,p); } ret_err = ERR_OK; } else if(es->state == ES_CLOSING) { /* odd case, remote side closing twice, trash data */ tcp_recved(tpcb, p->tot_len); es->p = NULL; pbuf_free(p); ret_err = ERR_OK; } else { /* unkown es->state, trash data */ tcp_recved(tpcb, p->tot_len); es->p = NULL; pbuf_free(p); ret_err = ERR_OK; } return ret_err; } void echo_error(void *arg, err_t err) { struct echo_state *es; LWIP_UNUSED_ARG(err); es = (struct echo_state *)arg; if (es != NULL) { mem_free(es); } } err_t echo_poll(void *arg, struct tcp_pcb *tpcb) { err_t ret_err; struct echo_state *es; es = (struct echo_state *)arg; if (es != NULL) { if (es->p != NULL) { /* there is a remaining pbuf (chain) */ tcp_sent(tpcb, echo_sent); echo_send(tpcb, es); } else { /* no remaining pbuf (chain) */ if(es->state == ES_CLOSING) { echo_close(tpcb, es); } } ret_err = ERR_OK; } else { /* nothing to be done */ tcp_abort(tpcb); ret_err = ERR_ABRT; } return ret_err; } err_t echo_sent(void *arg, struct tcp_pcb *tpcb, u16_t len) { struct echo_state *es; LWIP_UNUSED_ARG(len); es = (struct echo_state *)arg; es->retries = 0; if(es->p != NULL) { /* still got pbufs to send */ tcp_sent(tpcb, echo_sent); echo_send(tpcb, es); } else { /* no more pbufs to send */ if(es->state == ES_CLOSING) { echo_close(tpcb, es); } } return ERR_OK; } void echo_send(struct tcp_pcb *tpcb, struct echo_state *es) { struct pbuf *ptr; err_t wr_err = ERR_OK; while ((wr_err == ERR_OK) && (es->p != NULL) && (es->p->len <= tcp_sndbuf(tpcb))) { ptr = es->p; /* enqueue data for transmission */ wr_err = tcp_write(tpcb, ptr->payload, ptr->len, 1); if (wr_err == ERR_OK) { u16_t plen; u8_t freed; plen = ptr->len; /* continue with next pbuf in chain (if any) */ es->p = ptr->next; if(es->p != NULL) { /* new reference! */ pbuf_ref(es->p); } /* chop first pbuf from chain */ do { /* try hard to free pbuf */ freed = pbuf_free(ptr); } while(freed == 0); /* we can read more data now */ tcp_recved(tpcb, plen); } else if(wr_err == ERR_MEM) { /* we are low on memory, try later / harder, defer to poll */ es->p = ptr; } else { /* other problem ?? */ } } } void echo_close(struct tcp_pcb *tpcb, struct echo_state *es) { tcp_arg(tpcb, NULL); tcp_sent(tpcb, NULL); tcp_recv(tpcb, NULL); tcp_err(tpcb, NULL); tcp_poll(tpcb, NULL, 0); if (es != NULL) { mem_free(es); } tcp_close(tpcb); } #endif /* LWIP_TCP */ ocproxy-1.60/contrib/apps/tcpecho_raw/echo.h000066400000000000000000000031671303453231400211400ustar00rootroot00000000000000/* * Copyright (c) 2001-2004 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * */ #ifndef LWIP_ECHO_H #define LWIP_ECHO_H void echo_init(void); #endif /* LWIP_ECHO_H */ ocproxy-1.60/contrib/apps/udpecho/000077500000000000000000000000001303453231400171735ustar00rootroot00000000000000ocproxy-1.60/contrib/apps/udpecho/udpecho.c000066400000000000000000000055601303453231400207740ustar00rootroot00000000000000/* * Copyright (c) 2001-2003 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #include "udpecho.h" #include "lwip/opt.h" #if LWIP_NETCONN #include "lwip/api.h" #include "lwip/sys.h" /*-----------------------------------------------------------------------------------*/ static void udpecho_thread(void *arg) { struct netconn *conn; struct netbuf *buf; char buffer[4096]; err_t err; LWIP_UNUSED_ARG(arg); conn = netconn_new(NETCONN_UDP); LWIP_ASSERT("con != NULL", conn != NULL); netconn_bind(conn, NULL, 7); while (1) { err = netconn_recv(conn, &buf); if (err == ERR_OK) { /* no need netconn_connect here, since the netbuf contains the address */ if(netbuf_copy(buf, buffer, buf->p->tot_len) != buf->p->tot_len) { LWIP_DEBUGF(LWIP_DBG_ON, ("netbuf_copy failed\n")); } else { buffer[buf->p->tot_len] = '\0'; err = netconn_send(conn, buf); if(err != ERR_OK) { LWIP_DEBUGF(LWIP_DBG_ON, ("netconn_send failed: %d\n", (int)err)); } else { LWIP_DEBUGF(LWIP_DBG_ON, ("got %s\n", buffer)); } } netbuf_delete(buf); } } } /*-----------------------------------------------------------------------------------*/ void udpecho_init(void) { sys_thread_new("udpecho_thread", udpecho_thread, NULL, DEFAULT_THREAD_STACKSIZE, DEFAULT_THREAD_PRIO); } #endif /* LWIP_NETCONN */ ocproxy-1.60/contrib/apps/udpecho/udpecho.h000066400000000000000000000032551303453231400210000ustar00rootroot00000000000000/* * Copyright (c) 2001-2003 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #ifndef LWIP_UDPECHO_H #define LWIP_UDPECHO_H void udpecho_init(void); #endif /* LWIP_UDPECHO_H */ ocproxy-1.60/contrib/ports/000077500000000000000000000000001303453231400157505ustar00rootroot00000000000000ocproxy-1.60/contrib/ports/FILES000066400000000000000000000005661303453231400165440ustar00rootroot00000000000000unix/ - Architectural files for testing on unix-like systems (assuming gcc and pthreads). - Maintained by Kieran Mansley msvc6/ - Architectural files for Microsoft Visual C++ 6.0. - Maintained by Simon Goldschmidt old/ - Ports that are no longer actively maintained ocproxy-1.60/contrib/ports/old/000077500000000000000000000000001303453231400165265ustar00rootroot00000000000000ocproxy-1.60/contrib/ports/old/6502/000077500000000000000000000000001303453231400171225ustar00rootroot00000000000000ocproxy-1.60/contrib/ports/old/6502/README000066400000000000000000000000441303453231400200000ustar00rootroot00000000000000The 6502 code is far from complete. ocproxy-1.60/contrib/ports/old/6502/include/000077500000000000000000000000001303453231400205455ustar00rootroot00000000000000ocproxy-1.60/contrib/ports/old/6502/include/arch/000077500000000000000000000000001303453231400214625ustar00rootroot00000000000000ocproxy-1.60/contrib/ports/old/6502/include/arch/cc.h000066400000000000000000000040541303453231400222230ustar00rootroot00000000000000/* * Copyright (c) 2001-2003 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #ifndef __CC_H__ #define __CC_H__ typedef unsigned char u8_t; typedef signed char s8_t; typedef unsigned short u16_t; typedef signed short s16_t; typedef unsigned long u32_t; typedef signed long s32_t; #define U16_F "hu" #define S16_F "hd" #define X16_F "hx" #define U32_F "lu" #define S32_F "ld" #define X32_F "lx" #define PACK_STRUCT_BEGIN #define PACK_STRUCT_STRUCT #define PACK_STRUCT_END #define PACK_STRUCT_FIELD(x) x #endif /* __CC_H__ */ ocproxy-1.60/contrib/ports/old/6502/include/arch/cpu.h000066400000000000000000000032461303453231400224270ustar00rootroot00000000000000/* * Copyright (c) 2001-2003 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #ifndef __CPU_H__ #define __CPU_H__ #define BYTE_ORDER LITTLE_ENDIAN #endif /* __CPU_H__ */ ocproxy-1.60/contrib/ports/old/6502/include/arch/lib.h000066400000000000000000000033341303453231400224040ustar00rootroot00000000000000/* * Copyright (c) 2001-2003 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #ifndef __LIB_H__ #define __LIB_H__ int strlen(const char *str); int strncmp(const char *str1, const char *str2, int len); #endif /* __LIB_H__ */ ocproxy-1.60/contrib/ports/old/6502/include/arch/perf.h000066400000000000000000000033401303453231400225670ustar00rootroot00000000000000/* * Copyright (c) 2001-2003 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #ifndef __PERF_H__ #define __PERF_H__ #define PERF_START /* null definition */ #define PERF_STOP(x) /* null definition */ #endif /* __PERF_H__ */ ocproxy-1.60/contrib/ports/old/6502/include/arch/sys_arch.h000066400000000000000000000033631303453231400234530ustar00rootroot00000000000000/* * Copyright (c) 2001-2003 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #ifndef __SYS_C64_H__ #define __SYS_C64_H__ #define SYS_MBOX_NULL 0 typedef int sys_sem_t; typedef int sys_mbox_t; typedef int sys_thread_t; #endif /* __SYS_C64_H__ */ ocproxy-1.60/contrib/ports/old/6502/lib_arch.c000066400000000000000000000034531303453231400210360ustar00rootroot00000000000000/* * Copyright (c) 2001-2003 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ /* These are generic implementations of various library functions used * throughout the lwIP code. When porting, those should be optimized * for the particular processor architecture, preferably coded in * assembler. */ ocproxy-1.60/contrib/ports/old/6502/sys_c64.c000066400000000000000000000073361303453231400205710ustar00rootroot00000000000000/* * Copyright (c) 2001-2003 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #include #include #include "lwip/sys.h" #include "lwip/def.h" struct sys_timeouts timeouts; /*-----------------------------------------------------------------------------------*/ void sys_arch_block(u16_t time) { u16_t ticks; ticks = time * (CLK_TCK / 1000) + clock(); printf("ticks %d\n", ticks); while (clock() != ticks); } /*-----------------------------------------------------------------------------------*/ sys_mbox_t sys_mbox_new(void) { return SYS_MBOX_NULL; } /*-----------------------------------------------------------------------------------*/ void sys_mbox_free(sys_mbox_t mbox) { return; } /*-----------------------------------------------------------------------------------*/ void sys_mbox_post(sys_mbox_t mbox, void *data) { return; } /*-----------------------------------------------------------------------------------*/ u16_t sys_arch_mbox_fetch(sys_mbox_t mbox, void **data, u16_t timeout) { sys_arch_block(timeout); return 0; } /*-----------------------------------------------------------------------------------*/ sys_sem_t sys_sem_new(u8_t count) { return 0; } /*-----------------------------------------------------------------------------------*/ u16_t sys_arch_sem_wait(sys_sem_t sem, u16_t timeout) { sys_arch_block(timeout); return 0; } /*-----------------------------------------------------------------------------------*/ void sys_sem_signal(sys_sem_t sem) { return; } /*-----------------------------------------------------------------------------------*/ void sys_sem_free(sys_sem_t sem) { return; } /*-----------------------------------------------------------------------------------*/ void sys_init(void) { timeouts.next = NULL; return; } /*-----------------------------------------------------------------------------------*/ struct sys_timeouts * sys_arch_timeouts(void) { return &timeouts; } /*-----------------------------------------------------------------------------------*/ sys_thread_t sys_thread_new(char *name, void (* function)(void *arg), void *arg, int stacksize, int prio) { return 0; } /*-----------------------------------------------------------------------------------*/ ocproxy-1.60/contrib/ports/old/FILES000066400000000000000000000024661303453231400173230ustar00rootroot00000000000000This directory contains ports that are no longer actively maintained. 6502/ - Architectural files for the 6502 CPU. c16x/ - Architectural files for the C16x/ST10 uC. Supports lwIP Raw API only. CS8900a Ethernet driver for 16-bit mode. rtxc/ - Architectural files for the RTXC operating system. v2pro/ - Architectural files for the Xilinx Virtex-II PRO device with embedded PowerPC 405 Processor. Supports lwIP Raw API only. (requires EDK - http://www.xilinx.com/ise/embedded/edk.htm) coldfire/ - Architectural files for Motorola Coldfire 5272 CPU running under Nucleus OS. Supports DMA and ISRs in ethernet driver. ti_c6711/ - Architectural files for TI TMS320C6000 DSP running under uC/OS-II. Supports lwIP Raw API only. It's done with an 10/100M ethernet daughtercard. [more info at https://sourceforge.net/projects/ucos-lwip-c6x/] Each subdirectory (may) also include: perf.c - Optional file that should be implemented when running performance tests of lwIP. sys.c - Implementation of the operating system emulation layer. include/ - Architectural specific header files. netif/ - Architectural specific network interfaces. ocproxy-1.60/contrib/ports/old/c16x/000077500000000000000000000000001303453231400173075ustar00rootroot00000000000000ocproxy-1.60/contrib/ports/old/c16x/FILES000066400000000000000000000011421303453231400200720ustar00rootroot00000000000000This directory contains architecture and compiler specific stuff for porting lwIP to the C16x and ST10 microcontrollers. The compiler specifics are for Tasking EDE v7.5r2. The sequential API has not been ported; its functions are empties. If someone is interested in adding a sequential API, please contact the author (see below). Besides this, a Cirrus (formerly Crystal Semiconductors) CS8900a Ethernet driver is included, which assumes a 16-bit data bus configuration. When porting this driver, note that the CS8900a does not support interrupts in 8-bit mode. Leon Woestenberg ocproxy-1.60/contrib/ports/old/c16x/include/000077500000000000000000000000001303453231400207325ustar00rootroot00000000000000ocproxy-1.60/contrib/ports/old/c16x/include/arch/000077500000000000000000000000001303453231400216475ustar00rootroot00000000000000ocproxy-1.60/contrib/ports/old/c16x/include/arch/cc.h000066400000000000000000000027151303453231400224120ustar00rootroot00000000000000#ifndef __CC_H__ #define __CC_H__ /* memset(), memcpy() */ #include /* printf() and abort() */ #include #include /* isdigit() */ #include #include "arch/cpu.h" typedef unsigned char u8_t; typedef signed char s8_t; typedef unsigned short u16_t; typedef signed short s16_t; typedef unsigned long u32_t; typedef signed long s32_t; typedef u32_t mem_ptr_t; /* Define (sn)printf formatters for these lwIP types */ #define U16_F "hu" #define S16_F "hd" #define X16_F "hx" #define U32_F "lu" #define S32_F "ld" #define X32_F "lx" /* LW: Supported in at least >=v7.5 r2, but lwIP worked without the "_packed" attribute already */ #define PACK_STRUCT_BEGIN _packed #define PACK_STRUCT_STRUCT #define PACK_STRUCT_END #define PACK_STRUCT_FIELD(x) x #define LWIP_PLATFORM_BYTESWAP 1 #define LWIP_PLATFORM_HTONS(x) _ror(x,8) #define LWIP_PLATFORM_HTONL(x) c16x_htonl(x) _inline u32_t c16x_htonl(u32_t n) { u16_t msw, lsw; msw = n >> 16; msw = _ror(msw,8); lsw = n; lsw = _ror(lsw,8); n = ((u32_t)lsw << 16) | (u32_t)msw; return n; } #ifdef LWIP_DEBUG /* LW: forward declaration */ void debug_printf(char *format, ...); void page_printf(char *format, ...); /* Plaform specific diagnostic output */ #define LWIP_PLATFORM_DIAG(x) { debug_printf x; } #define LWIP_PLATFORM_ASSERT(x) { debug_printf("\fline %d in %s\n", __LINE__, __FILE__); while(1); } #endif/* LWIP_DEBUG */ #endif /* __CC_H__ */ ocproxy-1.60/contrib/ports/old/c16x/include/arch/cpu.h000066400000000000000000000001361303453231400226070ustar00rootroot00000000000000#ifndef __CPU_H__ #define __CPU_H__ #define BYTE_ORDER LITTLE_ENDIAN #endif /* __CPU_H__ */ ocproxy-1.60/contrib/ports/old/c16x/include/arch/lib.h000066400000000000000000000034331303453231400225710ustar00rootroot00000000000000/* * Copyright (c) 2001, Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the Institute nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * * $Id: lib.h,v 1.1 2007/06/14 12:33:57 kieranm Exp $ */ #ifndef __LIB_H__ #define __LIB_H__ #endif /* __LIB_H__ */ ocproxy-1.60/contrib/ports/old/c16x/include/arch/perf.h000066400000000000000000000035671303453231400227670ustar00rootroot00000000000000/* * Copyright (c) 2001, Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the Institute nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * * $Id: perf.h,v 1.1 2007/06/14 12:33:57 kieranm Exp $ */ #ifndef __PERF_H__ #define __PERF_H__ #define PERF_START /* null definition */ #define PERF_STOP(x) /* null definition */ #endif /* __PERF_H__ */ ocproxy-1.60/contrib/ports/old/c16x/include/netif/000077500000000000000000000000001303453231400220375ustar00rootroot00000000000000ocproxy-1.60/contrib/ports/old/c16x/include/netif/cs8900if.h000066400000000000000000000066241303453231400234650ustar00rootroot00000000000000/* * Copyright (c) 2001-2003 Leon Woestenberg * Copyright (c) 2001-2003 Axon Digital Design B.V., The Netherlands. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Leon Woestenberg * * This is a device driver for the Crystal Semiconductor CS8900 * chip in combination with the lwIP stack. * * This is work under development. Please coordinate changes * and requests with Leon Woestenberg * * The Swedish Institute of Computer Science and Adam Dunkels * are specifically granted permission to redistribute this * source code under any conditions they seem fit. * */ #ifndef __NETIF_CS8900IF_H__ #define __NETIF_CS8900IF_H__ #include "lwip/netif.h" /* interface statistics gathering * such as collisions, dropped packets, missed packets * 0 = no statistics, minimal memory requirements, no overhead * 1 = statistics on, but some have large granularity (0x200), very low overhead * 2 = statistics on, updated on every call to cs8900_service(), low overhead */ #define CS8900_STATS 2 /* Number of ISQ events that may be serviced by cs8900_service() (at least 1) */ #define CS8900_EVTS2SRV 10 struct cs8900if { //struct eth_addr *ethaddr; volatile u8_t needs_service; u8_t use_polling; #if (CS8900_STATS > 0) u32_t interrupts; // #interrupt requests of cs8900 u32_t missed; // #packets on medium that could not enter cs8900a chip due to buffer shortage u32_t dropped; // #packets dropped after they have been received in chip buffer u32_t collisions; // #collisions on medium when transmitting packets u32_t sentpackets; // #number of sent packets u32_t sentbytes; // #number of sent bytes #endif /* Add whatever per-interface state that is needed here. */ }; void cs8900if_reset(struct netif *netif); err_t cs8900if_init(struct netif *); void cs8900if_service(struct netif *); void cs8900if_input(struct netif *netif); void cs8900_send_debug(u8_t *p, u16_t len); #endif /* __NETIF_CS8900IF_H__ */ ocproxy-1.60/contrib/ports/old/c16x/lib.c000066400000000000000000000054071303453231400202270ustar00rootroot00000000000000/* * Copyright (c) 2001, Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the Institute nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * * $Id: lib.c,v 1.1 2007/06/14 12:33:57 kieranm Exp $ */ /* These are generic implementations of various library functions used * throughout the lwIP code. When porting, those should be optimized * for the particular processor architecture, preferably coded in * assembler. */ #include "lwip/arch.h" #if BYTE_ORDER == LITTLE_ENDIAN /*-----------------------------------------------------------------------------------*/ u16_t htons(u16_t n) { return ((n & 0xff) << 8) | ((n & 0xff00) >> 8); } /*-----------------------------------------------------------------------------------*/ u16_t ntohs(u16_t n) { return htons(n); } /*-----------------------------------------------------------------------------------*/ u32_t htonl(u32_t n) { return ((n & 0xff) << 24) | ((n & 0xff00) << 8) | ((n & 0xff0000) >> 8) | ((n & 0xff000000) >> 24); } /*-----------------------------------------------------------------------------------*/ u32_t ntohl(u32_t n) { return htonl(n); } /*-----------------------------------------------------------------------------------*/ #endif /* BYTE_ORDER == LITTLE_ENDIAN */ ocproxy-1.60/contrib/ports/old/c16x/netif/000077500000000000000000000000001303453231400204145ustar00rootroot00000000000000ocproxy-1.60/contrib/ports/old/c16x/netif/cs8900if.c000066400000000000000000000702471303453231400220370ustar00rootroot00000000000000/** @file * * Ethernet network driver for IP */ /* * Copyright (c) 2001-2003 Leon Woestenberg * Copyright (c) 2001-2003 Axon Digital Design B.V., The Netherlands. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Leon Woestenberg * * This is a device driver for the Crystal Semiconductor CS8900 * chip in combination with the lwIP stack. * * This is work under development. Please coordinate changes * and requests with Leon Woestenberg * * The Swedish Institute of Computer Science and Adam Dunkels * are specifically granted permission to redistribute this * source code under any conditions they seem fit. * * A quick function roadmap: * * cs8900_*() are low level, cs8900 hardware specific functions. * These are declared static in the device driver source and * SHOULD NOT need to be called from outside this source. * * cs8900if_*() are the lwIP network interface functions. * * cs8900_interrupt() is an early interrupt service routine (ISR). * It merely sets a flag to indicate the cs8900 needs servicing. * (This function MAY be tied to an interrupt vector, IF present). * * cs8900_service() is the actual interrupt event service routine. * It must be called whenever the cs8900 needs servicing. It MAY * be polled safely (so, you do NOT NEED interrupt support.) * * cs8900_init() sets up the cs8900, using its register set. When * using the driver on your particular hardware platform, make sure * the register setups match. * Function is called from cs8900if_init(). * * cs8900_input() transfers a received packet from the chip. * Function is called from cs8900if_input(). * * cs8900_output() transfers a packet to the chip for transmission. * Function is called as netif->linkoutput from etharp_output(). * * cs8900if_init() initializes the lwIP network interface, and * calls cs8900_init() to initialize the hardware. * Function is called from lwIP. * * cs8900if_service() is the service routine, which must be called * upon the need for service, or on a regular basis, in order to * service the Ethernet chip. * * cs8900if_input() calls cs8900_input() to get a received packet * and then forwards the packet to protocol(s) handler(s). * Function is called from cs8900_service(). * * netif->output() resolves the hardware address, then * calls cs8900_output() (as netif->linkoutput()) to transfer the packet. * Function is called from lwIP. * * Future development: * * Split the generic Ethernet functionality (a lot of the * cs8900if_*() functions) and the actual cs8900a dependencies. * * Enhance the interrupt handler to service the Ethernet * chip (to decrease latency); support early packet * inspection (during reception) to early drop unwanted * packets, minimize chip buffer use and maximize throughput. * * Statistics gathering, currently under development. * SNMP support, currently under development. * */ #include "lwip/opt.h" #include "lwip/def.h" #include "lwip/err.h" #include "lwip/mem.h" #include "lwip/pbuf.h" #include "lwip/stats.h" #include "lwip/sys.h" #include "netif/etharp.h" #if 0 // include some debugging help # define LWIP_DBG_LEVEL 1 # include "leds.h" # include "display.h" //# include "page.h" # define LED_NEED_SERVICE LED_FP1 #else // no debugging # define leds_on() # define leds_off() #endif /** * Dependend on physical layer. This is a safe minimum for 802.3 10base5/T. * @sa RFC1042 */ #define ETH_MIN_FRAME_LEN 60 #include "cs8900if.h" #include "lwip/snmp.h" // Define those to better describe your network interface #define IFNAME0 'e' #define IFNAME1 'n' // Forward declarations static err_t cs8900_output(struct netif *netif, struct pbuf *p); static struct pbuf *cs8900_input(struct netif *netif); static void cs8900_service(struct netif *netif); static u32_t cs8900_chksum(void *dataptr, s16_t len); static void cs8900_reset(struct netif *netif); // Define these to match your hardware setup #define MEM_BASE 0x00E000 #define IO_BASE 0x800 #define INT_NR 0x00 #define RXTXREG *((volatile u16_t *)(MEM_BASE + IO_BASE)) #define TXCMD *((volatile u16_t *)(MEM_BASE + IO_BASE + 0x04)) #define TXLENGTH *((volatile u16_t *)(MEM_BASE + IO_BASE + 0x06)) #define ISQ *((volatile u16_t *)(MEM_BASE + IO_BASE + 0x08)) #define PACKETPP *((volatile u16_t *)(MEM_BASE + IO_BASE + 0x0A)) #define PPDATA *((volatile u16_t *)(MEM_BASE + IO_BASE + 0x0C)) // CS8900 PacketPage register offsets #define CS_PP_EISA 0x0000 // EISA Registration number of CS8900 #define CS_PP_PRODID 0x0002 // Product ID Number #define CS_PP_IOBASE 0x0020 // I/O Base Address #define CS_PP_INTNUM 0x0022 // Interrupt number (0,1,2, or 3) #define CS_PP_RXCFG 0x0102 // Receiver Configuration #define CS_PP_RXCTL 0x0104 // Receiver Control #define CS_PP_TXCFG 0x0106 // Transmit Configuration #define CS_PP_BUFCFG 0x010A // Buffer Configuration #define CS_PP_LINECTL 0x0112 // Line Control Register offset #define CS_PP_SELFCTL 0x0114 // Self Control #define CS_PP_BUSCTL 0x0116 // Bus Control #define CS_PP_TESTCTL 0x0118 // Test Control #define CS_PP_ISQ 0x0120 // Interrupt status queue #define CS_PP_RXEVENT 0x0124 // Receiver Event #define CS_PP_TX_EVENT 0x0128 // Transmitter Event #define CS_PP_BUF_EVENT 0x012C // Buffer Event #define CS_PP_RXMISS 0x0130 // Receiver Miss Counter #define CS_PP_TXCOL 0x0132 // Transmit Collision Counter #define CS_PP_LINESTATUS 0x0134 // Line Status #define CS_PP_SELFTEST 0x0136 // Self Status #define CS_PP_BUSSTATUS 0x0138 // Bus Status #define CS_PP_TXCMD 0x0144 // Transmit Command Request #define CS_PP_TXLEN 0x0146 // Transmit Length #define CS_PP_IA1 0x0158 // Individual Address (IA) #define CS_PP_IA2 0x015A // Individual Address (IA) #define CS_PP_IA3 0x015C // Individual Address (IA) #define CS_PP_RXSTATUS 0x0400 // Receive Status #define CS_PP_RXLEN 0x0402 // Receive Length #define CS_PP_RXFRAME 0x0404 // Receive Frame Location #define CS_PP_TXFRAME 0x0A00 // Transmit Frame Location // removed interrupt from library #if 0 // hardware interrupt vector handler _interrupt(0x18) void cs8900_interrupt(void) { struct cs8900if *cs8900if = cs8900if_netif->state; // network interface is configured? if (cs8900if != NULL) { // chip needs service cs8900if->needs_service = 1; #if (CS8900_STATS > 0) cs8900if->interrupts++; #endif } } #endif /** * Reset the CS8900A chip-wide using a soft reset * * @note You MUST wait 30 ms before accessing the CS8900 * after calling this function. */ static void cs8900_reset(struct netif *netif) { (void)netif; /* set RESET bit */ PACKETPP = CS_PP_SELFCTL; PPDATA = 0x0055U; } // cs8900_init() // // initializes the CS8900A chip // static err_t cs8900_init(struct netif *netif) { #ifdef LED_NEED_SERVICE leds_off(LED_NEED_SERVICE); #endif // { the RESET bit will be cleared by the cs8900a // as a result of a hardware reset - wait for it} // RESET bit cleared? while ((PPDATA & 0x0040U) != 0); // TODO: add timeout // { after full initialization of the cs8900a // the INITD bit will be set } PACKETPP = CS_PP_SELFTEST; // INITD bit still clear? while ((PPDATA & 0x0080U) == 0); // TODO: add timeout // { INITD bit is set } // SIBUSY bit still set? while ((PPDATA & 0x0100U) == 0x0100); // TODO: add timeout // { SIBUSY bit clear } #if 1 { u16_t dummy; // datasheet section 3.3.3 dummy = *(u16_t *)(MEM_BASE + IO_BASE + 0x0D); // Dummy read, put chip in 16-bit mode dummy = *(u16_t *)(MEM_BASE + IO_BASE + 0x0D); } #endif // Set MAC address PACKETPP = CS_PP_IA1; PPDATA = (u16_t)(netif->hwaddr[0]) | (u16_t)(netif->hwaddr[1] << 8U); PACKETPP = CS_PP_IA2; PPDATA = (u16_t)(netif->hwaddr[2]) | (u16_t)(netif->hwaddr[3] << 8U); PACKETPP = CS_PP_IA3; PPDATA = (u16_t)(netif->hwaddr[4]) | (u16_t)(netif->hwaddr[5] << 8U); // accept valid unicast or broadcast frames PACKETPP = CS_PP_RXCTL; PPDATA = (0x0005U | 0x0800U/*broadcast*/ | 0x0400U/*individual*/ | 0x0100U/*RxOK*/); // enable receive interrupt PACKETPP = CS_PP_RXCFG; PPDATA = (0x0003U | 0x0100U/*RXIRQ*/); // disable transmit interrupt (is default) PACKETPP = CS_PP_TXCFG; PPDATA = (0x0007U | 0); // use interrupt number 0 PACKETPP = CS_PP_INTNUM; PPDATA = (0x0000U); // generate interrupt event on: // - the RxMISS counter reaches 0x200, or // - a received frame is lost PACKETPP = CS_PP_BUFCFG; PPDATA = (0x000bU | #if (CS8900_STATS > 0) // interrupt before counter overflow (0x2000U/*MissOvfloiE*/ | 0x1000U/*TxColOvfloiE*/) | #endif #if (CS8900_STATS > 1) // interrupt on counter increment (0x0400U/*RxMissiE*/) | #endif 0x0000); // enable interrupt generation PACKETPP = CS_PP_BUSCTL; PPDATA = (0x0017U | 0x8000U/*EnableIRQ*/); // enable: // - receiver // - transmitter PACKETPP = CS_PP_LINECTL; PPDATA = (0x0013U | 0x0080U/*SerTxOn*/ | 0x0040U/*SerRxOn*/); return ERR_OK; } /** * * * @return error code * - ERR_OK: packet transferred to hardware * - ERR_CONN: no link or link failure * - ERR_IF: could not transfer to link (hardware buffer full?) */ static err_t cs8900_output(struct netif *netif, struct pbuf *p) { s16_t tries = 0; err_t result; // exit if link has failed PACKETPP = CS_PP_LINESTATUS; if ((PPDATA & 0x0080U/*LinkOK*/) == 0) return ERR_CONN; // no Ethernet link result = ERR_OK; /* TODO: should this occur AFTER setting TXLENGTH??? */ /* drop the padding word */ #if ETH_PAD_SIZE pbuf_header(p, -ETH_PAD_SIZE); #endif /* issue 'transmit' command to CS8900 */ TXCMD = 0x00C9U; /* send length (in bytes) of packet to send, but at least minimum frame length */ TXLENGTH = (p->tot_len < ETH_MIN_FRAME_LEN? ETH_MIN_FRAME_LEN: p->tot_len); PACKETPP = CS_PP_BUSSTATUS; // not ready for transmission and still within 100 retries? while (((PPDATA & 0x0100U/*Rdy4TxNOW*/) == 0) && (tries++ < 100)) { // throw away the last committed received frame PACKETPP = CS_PP_RXCFG; PPDATA = (0x0003U | 0x0040U/*Skip_1*/ | 0x0100U/*RxOKiE*/); PACKETPP = CS_PP_BUSSTATUS; /* cs8900if->dropped++; // CHECK: we do not know if we actually will drop a frame here */ } // ready to transmit? if ((PPDATA & 0x0100U/*Rdy4TxNOW*/) != 0) { u16_t sent_bytes = 0; /* q traverses through linked list of pbuf's * This list MUST consist of a single packet ONLY */ struct pbuf *q; u16_t pbuf_index = 0; u8_t word_index = 0; u8_t word[2]; q = p; /* Write data into CS8900, two bytes at a time * Handling pbuf's with odd number of bytes correctly * No attempt to optimize for speed has been made */ while (q) { if (pbuf_index < q->len) { word[word_index++] = ((u8_t*)q->payload)[pbuf_index++]; if (word_index == 2) { RXTXREG = (word[1] << 8) | word[0]; word_index = 0; sent_bytes += 2; } } else { q = q->next; pbuf_index = 0; } } /* One byte could still be unsent */ if (word_index == 1) { RXTXREG = word[0]; sent_bytes += 2; } /* provide any additional padding to comply with minimum Ethernet * frame length (RFC10242) */ while (sent_bytes < ETH_MIN_FRAME_LEN) { RXTXREG = 0x0000; sent_bytes += 2; } /* { the packet has been sent } */ #if (CS8900_STATS > 0) ((struct cs8900if *)netif->state)->sentpackets++; ((struct cs8900if *)netif->state)->sentbytes += sent_bytes; #endif snmp_add_ifoutoctets(netif,sent_bytes); } else { // { not ready to transmit!? } snmp_inc_ifoutdiscards(netif); /* return not connected */ result = ERR_IF; } #if ETH_PAD_SIZE /* reclaim the padding word */ pbuf_header(p, ETH_PAD_SIZE); #endif return result; } /** * Move a received packet from the cs8900 into a new pbuf. * * Must be called after reading an ISQ event containing the * "Receiver Event" register, before reading new ISQ events. * * This function copies a frame from the CS8900A. * It is designed failsafe: * - It does not assume a frame is actually present. * - It checks for non-zero length * - It does not overflow the frame buffer */ static struct pbuf *cs8900_input(struct netif *netif) { volatile u16_t* rxtx_reg; volatile u32_t rxtx_num = (MEM_BASE + IO_BASE); u16_t* ptr = NULL; struct pbuf *p = NULL, *q = NULL; u16_t len = 0; u16_t event_type; u16_t i; /* optimized register mapping for Tasking c166 7.5 (default optimalisation setting) Using RXTXREG directly produces inefficient code with many const address loads. */ rxtx_reg = ((volatile u16_t *)(rxtx_num)); // read RxStatus event_type = *rxtx_reg; // correctly received frame, either broadcast or individual address? // TODO: maybe defer these conditions to cs8900_input() if ((event_type & 0x0100U/*RxOK*/) && (event_type & 0x0c00U/*Broadcast | Individual*/)) { #if LWIP_SNMP > 0 // update number of received MAC-unicast and non-MAC-unicast packets if (event_type & 0x0400U/*Individual*/) { snmp_inc_ifinucastpkts(netif); } else { snmp_inc_ifinnucastpkts(netif); } #endif event_type = 0; // read RxLength len = *rxtx_reg; LWIP_DEBUGF(NETIF_DEBUG, ("cs8900_input: packet len %"U16_F"\n", len)); snmp_add_ifinoctets(netif,len); // positive length? if (len > 0) { // allocate a pbuf chain with total length 'len + ETH_PAD_SIZE' p = pbuf_alloc(PBUF_RAW, len + ETH_PAD_SIZE, PBUF_POOL); if (p != NULL) { #if ETH_PAD_SIZE /* drop the padding word */ pbuf_header(p, -ETH_PAD_SIZE); /* drop the padding word */ #endif for (q = p; q != 0; q = q->next) { LWIP_DEBUGF(NETIF_DEBUG, ("cs8900_input: pbuf @%p tot_len %"U16_F" len %"U16_F"\n", q, q->tot_len, q->len)); /* read 8 bytes per iteration */ ptr = q->payload; i = q->len / 8; while(i > 0) { *ptr = *rxtx_reg; ptr++; *ptr = *rxtx_reg; ptr++; *ptr = *rxtx_reg; ptr++; *ptr = *rxtx_reg; ptr++; i--; } /* read remainder */ i = ((q->len % 8) + 1) / 2; while(i > 0) { *ptr = *rxtx_reg; ptr++; i--; } } #if ETH_PAD_SIZE /* reclaim the padding word */ pbuf_header(p, ETH_PAD_SIZE); /* reclaim the padding word */ #endif } // could not allocate a pbuf else { // skip received frame // TODO: maybe do not skip the frame at this point in time? PACKETPP = CS_PP_RXCFG; PPDATA = (0x0003U | 0x0100U/*RxOKiE*/ | 0x0040U/*Skip_1*/); #if (CS8900_STATS > 0) ((struct cs8900if *)netif->state)->dropped++; #endif snmp_inc_ifindiscards(netif); len = 0; } } // length was zero else { } } return p; } /** * To be called when the cs8900a needs service. Does * not assume the cs8900a needs service. Does test the * cs8900a whether it needs service. * * As such, may be used robustly called as a deferred * (or "late") interrupt handler, or may be called in * a loop to implement polling, or both. * * Use cs8900if_service() from your application instead * of this function. */ static void cs8900_service(struct netif *netif) { u8_t events2service = CS8900_EVTS2SRV; #if (CS8900_STATS > 0) u16_t miss_count = 0, coll_count = 0; #endif // NOTES: // static, so only initialized to zero at program start. // irq_status will always hold the last ISQ event register that // still needs service. As such, we may leave this function if // we encounter an event we cannot service yet, and return later // to try to service it. static u16_t irq_status = 0x0000U; // The "cs8900_needs_service" flag indicates whether any events // still need to be serviced. // clear flag here. // a receive interrupt can, *concurrently with this function*, // set this flag on new ISQ event occurences. // we will re-evaluate the correct setting of this flag at // function exit (below). ((struct cs8900if *)netif->state)->needs_service = 0; #ifdef LED_NEED_SERVICE leds_off(LED_NEED_SERVICE); #endif /* no unhandled irq_status left? */ if (irq_status == 0x0000U) { /* read ISQ register */ irq_status = ISQ; } /* ISQ interrupt event, and allowed to service in this loop? */ while ((irq_status != 0x0000U) && (events2service-- > 0)) { /* investigate event */ if ((irq_status & 0x003fU) == 0x0004U/*Receiver Event*/) { /* correctly received frame, either broadcast or individual address */ /* TODO: think where these checks should appear: here or in cs8900_input() */ if ((irq_status & 0x0100U/*RxOK*/) && (irq_status & 0x0c00U/*Broadcast | Individual*/)) { /* read the frame from the cs8900a */ cs8900if_input(netif); } else { /* skip this frame */ PACKETPP = CS_PP_RXCFG; PPDATA |= 0x0040U/*Skip_1*/; #if (CS8900_STATS > 0) ((struct cs8900if *)netif->state)->dropped++; #endif } } #if (CS8900_STATS > 0) else if ((irq_status & 0x003fU) == 0x0010U/*RxMISS Event*/) { miss_count += (irq_status >> 6); } else if ((irq_status & 0x003fU) == 0x0012U/*TxCOL Event*/) { coll_count += (irq_status >> 6); } #endif /* read ISQ register */ irq_status = ISQ; } /* we did not deplete the ISQ? */ if (irq_status != 0x0000U) { /* the cs8900a still needs service */ ((struct cs8900if *)netif->state)->needs_service = 1; #ifdef LED_NEED_SERVICE leds_on(LED_NEED_SERVICE); #endif } #if (CS8900_STATS > 1) /* follow misses and collisions on a per-packet basis? */ /* read RxMiss Counter (zeroes itself upon read) */ PACKETPP = CS_PP_RXMISS; miss_count += (PPDATA >> 6); /* read RxCol Counter (zeroes itself upon read) */ PACKETPP = CS_PP_TXCOL; coll_count += (PPDATA >> 6); #endif #if (CS8900_STATS > 0) /* copy statistics counters into netif state fields */ ((struct cs8900if *)netif->state)->missed += miss_count; if (miss_count > 0) LWIP_DEBUGF(NETIF_DEBUG | 1, ("cs8900_input: %"U16_F" missed packets due to rx buffer overrun\n", miss_count)); ((struct cs8900if *)netif->state)->collisions += coll_count; if (coll_count > 0) LWIP_DEBUGF(NETIF_DEBUG | 1, ("cs8900_input: %"U16_F" packet collisions\n", coll_count)); #endif } /** * Service the CS8900. * * Can be called in a polling manner, or only after the CS8900 has raised * an interrupt request. * * @param netif The lwIP network interface data structure belonging to this device. * */ void cs8900if_service(struct netif *netif) { // is there a reason to call the service routine? if ((((struct cs8900if *)netif->state)->needs_service) || (((struct cs8900if *)netif->state)->use_polling)) { cs8900_service(netif); } } /** * Read a received packet from the CS8900. * * This function should be called when a packet is received by the CS8900 * and is fully available to read. It moves the received packet to a pbuf * which is forwarded to the IP network layer or ARP module. It transmits * a resulting ARP reply or queued packet. * * @param netif The lwIP network interface to read from. * * @internal Uses cs8900_input() to move the packet from the CS8900 to a * newly allocated pbuf. * */ void cs8900if_input(struct netif *netif) { struct eth_hdr *ethhdr = NULL; struct pbuf *p = NULL; /* move received packet into a new pbuf */ p = cs8900_input(netif); /* no packet could be read */ if (p == NULL) { /* silently ignore this */ return; } /* points to packet payload, which starts with an Ethernet header */ ethhdr = p->payload; switch (htons(ethhdr->type)) { /* IP packet? */ case ETHTYPE_IP: #if 0 /* CSi disabled ARP table update on ingress IP packets. This seems to work but needs thorough testing. */ /* update ARP table */ etharp_ip_input(netif, p); #endif /* skip Ethernet header */ pbuf_header(p, -(s16_t)sizeof(struct eth_hdr)); LWIP_DEBUGF(NETIF_DEBUG, ("cs8900_input: passing packet up to IP\n")); /* pass to network layer */ netif->input(p, netif); break; /* ARP packet? */ case ETHTYPE_ARP: /* pass p to ARP module */ etharp_arp_input(netif, (struct eth_addr *)&netif->hwaddr, p); break; /* unsupported Ethernet packet type */ default: /* free pbuf */ pbuf_free(p); p = NULL; break; } } /** * Reset the CS8900 Ethernet MAC/PHY chip. * * @param netif The lwIP network interface data structure belonging to this device. * MAY be NULL as we do not support multiple devices yet. * @note You SHOULD call cs8900if_init() afterwards to * initialize and configure the chip. */ void cs8900if_reset(struct netif *netif) { /* reset the cs8900a chip */ cs8900_reset(netif); } /** * Initialize the CS8900 Ethernet MAC/PHY and its device driver. * * @param netif The lwIP network interface data structure belonging to this device. * MAY be NULL as we do not support multiple devices yet. * */ err_t cs8900if_init(struct netif *netif) { struct cs8900if *cs8900if; cs8900if = mem_malloc(sizeof(struct cs8900if)); if (cs8900if == NULL) { LWIP_DEBUGF(NETIF_DEBUG, ("cs8900_input: out of memory for cs8900if\n")); return ERR_MEM; } /* initialize lwip network interface ... */ #if LWIP_SNMP /* ifType ethernetCsmacd(6) */ netif->link_type = 6; netif->link_speed = 10000000; netif->ts = 0; netif->ifinoctets = 0; netif->ifinucastpkts = 0; netif->ifinnucastpkts = 0; netif->ifindiscards = 0; netif->ifoutoctets = 0; netif->ifoutucastpkts = 0; netif->ifoutnucastpkts = 0; netif->ifoutdiscards = 0; #endif /* administrative details */ netif->name[0] = IFNAME0; netif->name[1] = IFNAME1; /* downward functions */ netif->output = etharp_output; netif->linkoutput = cs8900_output; /* initialize cs8900 specific interface state data pointer */ netif->state = cs8900if; /* maximum transfer unit */ netif->mtu = 1500; /* broadcast capability */ netif->flags = NETIF_FLAG_BROADCAST; /* hardware address length */ netif->hwaddr_len = 6; /* initially assume no ISQ event */ cs8900if->needs_service = 0; /* set to 1 if polling method is used */ cs8900if->use_polling = 0; #if (CS8900_STATS > 0) /* number of interrupt service routine calls */ cs8900if->interrupts = 0; cs8900if->missed = 0; cs8900if->dropped = 0; cs8900if->collisions = 0; cs8900if->sentpackets = 0; cs8900if->sentbytes = 0; #endif /* intialize the cs8900a chip */ return cs8900_init(netif); } #if 1 /** * Dump an array of bytes inside a UDP message's data field. * * It is a self-contained function, independent of higher protocol layers or other * functions, so it allows you to debug these higher layers, such as lwIP. * * @param p pointer to an array of bytes, at least with length 'len' * @param len number of bytes available at the address pointed to by 'p' */ void cs8900_send_debug(u8_t *p, u16_t len) { s16_t tries = 0, i; // network interface state extern struct netif *ethif; // exit if link has failed PACKETPP = CS_PP_LINESTATUS; if ((PPDATA & 0x0080U/*LinkOK*/) == 0) return; // TODO: find a correct error code // transmit command TXCMD = 0x00C9U; // send at least 60 bytes TXLENGTH = (14 + 20 + 8 + len < 60) ? 60 : (14 + 20 + 8 + len); PACKETPP = CS_PP_BUSSTATUS; // not ready for transmission and still within 100 retries? while (((PPDATA & 0x0100U/*Rdy4TxNOW*/) == 0) && (tries++ < 100)) { // throw away the last committed received frame PACKETPP = CS_PP_RXCFG; PPDATA = (0x0003U | 0x0040U/*Skip_1*/ | 0x0100U/*RxOKiE*/); PACKETPP = CS_PP_BUSSTATUS; /* cs8900if->dropped++; CHECK: we do not know if we actually will drop a frame here, do we? */ } // ready to transmit? if ((PPDATA & 0x0100U/*Rdy4TxNOW*/) != 0) { u16_t data, checksum = 0; u32_t udp_checksum = 0; // destination Ethernet address RXTXREG = 0xa000U; RXTXREG = 0xc524U; RXTXREG = 0x6d72U; // source Ethernet address RXTXREG = htons(((u16_t)ethif->hwaddr[0] << 8U) | (u16_t)ethif->hwaddr[1]); RXTXREG = htons(((u16_t)ethif->hwaddr[2] << 8U) | (u16_t)ethif->hwaddr[3]); RXTXREG = htons(((u16_t)ethif->hwaddr[4] << 8U) | (u16_t)ethif->hwaddr[5]); // frame type RXTXREG = htons(0x0800); // TOS, version RXTXREG = htons(data = ((0x40 | 0x05) << 8) | 0x00); checksum += data; // length RXTXREG = htons(data = 20 + 8 + len); checksum += data; // identifier RXTXREG = htons(data = 0); checksum += data; // fragment offset RXTXREG = htons(data = 0); checksum += data; // TTL, UDP protocol RXTXREG = htons(data = (255U << 8) | 17U); checksum += data; checksum += (htonl(ethif->ip_addr.addr) & 0xffff0000U) >> 16; checksum += (htonl(ethif->ip_addr.addr) & 0x0000ffffU); checksum += 0xc0a8U; checksum += 0x0001U; checksum += 6; // LW: kludge/hack: checksum calculation seems to be wrong somehow // LW: this seems (?) to fix it // checksum RXTXREG = htons(~checksum); // source IP RXTXREG = htons((htonl(ethif->ip_addr.addr) & 0xffff0000U) >> 16); // source IP RXTXREG = htons( htonl(ethif->ip_addr.addr) & 0x0000ffffU); // destination IP RXTXREG = htons(0xc0a8U); // destination IP RXTXREG = htons(0x0001U); // source port 3000 RXTXREG = htons(3000U); // destination port 3000 RXTXREG = htons(3000U); // UDP length RXTXREG = htons(len); // UDP checksum (not present) udp_checksum = (htonl(ethif->ip_addr.addr) & 0xffff0000U) >> 16; udp_checksum += (htonl(ethif->ip_addr.addr) & 0x0000ffffU); udp_checksum += 0xc0a8U; udp_checksum += 0x0001U; udp_checksum += 0x0011U; udp_checksum += (8 + len); udp_checksum += 3000; udp_checksum += 3000; udp_checksum += (8 + len); udp_checksum += cs8900_chksum(p, len); while (udp_checksum >> 16) { udp_checksum = (udp_checksum & 0xffffUL) + (udp_checksum >> 16); } RXTXREG = htons(~(udp_checksum & 0xffff)); for (i = 0; i < len; i += 2) { RXTXREG = htons((p[i] << 8) | p[i + 1]); } // pad to 60 bytes while (i < 60) { RXTXREG = 0; i += 2; } } } static u32_t cs8900_chksum(void *dataptr, s16_t len) { u32_t acc = 0; u16_t *ptr = (u16_t *)dataptr; for(acc = 0; len > 1; len -= 2) { acc += *ptr; ptr++; } /* add up any odd byte */ if (len == 1) { acc += htons((u16_t)((*(u8_t *)ptr) & 0xffU) << 8); } return acc; } #endif ocproxy-1.60/contrib/ports/old/c16x/perf.c000066400000000000000000000034771303453231400204220ustar00rootroot00000000000000/* * Copyright (c) 2001, Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the Institute nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * * $Id: perf.c,v 1.1 2007/06/14 12:33:57 kieranm Exp $ */ #include "arch/perf.h" void perf_init(char *fname) { if (fname); // LEON: prevent warning } ocproxy-1.60/contrib/ports/old/coldfire/000077500000000000000000000000001303453231400203155ustar00rootroot00000000000000ocproxy-1.60/contrib/ports/old/coldfire/README000066400000000000000000000015661303453231400212050ustar00rootroot00000000000000### README --- c:/cygwin/home/dhaas/work/cfimage/lwip/arch/coldfire/ ## ## Author: dhaas@alum.rpi.edu These files are a port of lwip to coldfire (specifically the MCF5272 with on-board FEC) under the Nucleus OS. Nucleus is pretty generic so it should be fairly easy to port this to any other embedded OS. Nucleus memory managment is not used. It is assumed you have a working malloc (which at least long-word aligns memory). The compiler used was Diab 4.3b. You will almost certainly need to change cc.h for your compiler. IMPORTANT NOTE: If you use the fec driver for a different processor which has a data cache you will need to make sure the buffer descriptors and memory used for pbufs are not in a cachable area. Otherwise the fec driver is guarrenteed to malfunction. The 5272 which this was written for does not support data cache so it did not matter and malloc was used. ocproxy-1.60/contrib/ports/old/coldfire/include/000077500000000000000000000000001303453231400217405ustar00rootroot00000000000000ocproxy-1.60/contrib/ports/old/coldfire/include/arch/000077500000000000000000000000001303453231400226555ustar00rootroot00000000000000ocproxy-1.60/contrib/ports/old/coldfire/include/arch/cc.h000066400000000000000000000076131303453231400234220ustar00rootroot00000000000000/* * Copyright (c) 2001-2003, Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the Institute nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * * $Id: cc.h,v 1.1 2007/06/14 12:34:00 kieranm Exp $ */ #ifndef __CC_H__ #define __CC_H__ #include #include /* Specific code for NBS Card Technology */ #ifdef CARDTECH #include #endif #define BYTE_ORDER BIG_ENDIAN #define IMM_ADDRESS (0x10000000) #define FEC_LEVEL 4 // typedef unsigned char u8_t; // typedef signed char s8_t; // typedef unsigned short u16_t; // typedef signed short s16_t; // typedef unsigned long u32_t; // typedef signed long s32_t; typedef u32_t mem_ptr_t; /* Compiler hints for packing structures */ #define PACK_STRUCT_BEGIN #pragma pack(1,1,0) #define PACK_STRUCT_STRUCT #define ALIGN_STRUCT_8_BEGIN #pragma pack(1,8,0) #define ALIGN_STRUCT_END #pragma pack() #define PACK_STRUCT_END #pragma pack() #define PACK_STRUCT_FIELD(x) x #define _SYS_TYPES_FD_SET #define NBBY 8 /* number of bits in a byte */ #ifndef FD_SETSIZE #define FD_SETSIZE 64 #endif /* FD_SETSIZE */ typedef long fd_mask; #define NFDBITS (sizeof (fd_mask) * NBBY) /* bits per mask */ #ifndef howmany #define howmany(x,y) (((x)+((y)-1))/(y)) #endif /* howmany */ typedef struct _types_fd_set { fd_mask fds_bits[howmany(FD_SETSIZE, NFDBITS)]; } _types_fd_set; #define fd_set _types_fd_set #define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1L << ((n) % NFDBITS))) #define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= ~(1L << ((n) % NFDBITS))) #define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & (1L << ((n) % NFDBITS))) #define FD_ZERO(p) do { \ size_t __i; \ char *__tmp = (char *)p; \ for (__i = 0; __i < sizeof (*(p)); ++__i) \ *__tmp++ = 0; \ } while (0) /* prototypes for printf() and abort() */ #include #include /* Plaform specific diagnostic output */ #ifndef LWIP_PLATFORM_DIAG #define LWIP_PLATFORM_DIAG(x) do {printf x;} while(0) #endif #ifndef LWIP_PLATFORM_ASSERT #define LWIP_PLATFORM_ASSERT(x) do {printf("Assertion \"%s\" failed at line %d in %s\n", \ x, __LINE__, __FILE__); fflush(NULL); abort();} while(0) #endif asm u32_t GET_CALLER_PC (void) { ! "d0" move.l 4(a6),d0 } #endif /* __CC_H__ */ ocproxy-1.60/contrib/ports/old/coldfire/include/arch/errno.h000066400000000000000000000035241303453231400241570ustar00rootroot00000000000000/* * Copyright (c) 2001, Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the Institute nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: David Haas * * $Id: */ #ifndef __ERRNO_H__ #define __ERRNO_H__ /* This can be used to test whether errno is implemented */ #define ERRNO #define errno (*sys_arch_errno()) #endif ocproxy-1.60/contrib/ports/old/coldfire/include/arch/mcf5272.h000066400000000000000000002415601303453231400241230ustar00rootroot00000000000000/* * Copyright (c) 2001-2003, Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the Institute nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * * Notes: This file provided by Motorola as part of their example code. */ #ifndef _CPU_MCF5272_H #define _CPU_MCF5272_H /***********************************************************************/ /* * Misc. Defines */ #ifdef FALSE #undef FALSE #endif #define FALSE (0) #ifdef TRUE #undef TRUE #endif #define TRUE (1) #ifdef NULL #undef NULL #endif #define NULL (0) /***********************************************************************/ /* * The basic data types */ typedef volatile unsigned char vuint8; /* 8 bits */ typedef volatile unsigned short int vuint16; /* 16 bits */ typedef volatile unsigned long int vuint32; /* 32 bits */ typedef unsigned char uint8; /* 8 bits */ typedef unsigned short int uint16; /* 16 bits */ typedef unsigned long int uint32; /* 32 bits */ typedef signed char int8; /* 8 bits */ typedef signed short int int16; /* 16 bits */ typedef signed long int int32; /* 32 bits */ /***********************************************************************/ /* * Common M68K & ColdFire definitions */ #define ADDRESS uint32 #define INSTRUCTION uint16 #define ILLEGAL 0x4AFC #define CPU_WORD_SIZE 16 /***********************************************************************/ /* * Routines and macros for accessing Input/Output devices */ #define cpu_iord_8(ADDR) *((volatile uint8 *)(ADDR)) #define cpu_iord_16(ADDR) *((volatile uint16 *)(ADDR)) #define cpu_iord_32(ADDR) *((volatile uint32 *)(ADDR)) #define cpu_iowr_8(ADDR,DATA) *((volatile uint8 *)(ADDR)) = (DATA) #define cpu_iowr_16(ADDR,DATA) *((volatile uint16 *)(ADDR)) = (DATA) #define cpu_iowr_32(ADDR,DATA) *((volatile uint32 *)(ADDR)) = (DATA) /***********************************************************************/ #define MCF5200_SR_T (0x8000) #define MCF5200_SR_S (0x2000) #define MCF5200_SR_M (0x1000) #define MCF5200_SR_IPL (0x0700) #define MCF5200_SR_IPL_0 (0x0000) #define MCF5200_SR_IPL_1 (0x0100) #define MCF5200_SR_IPL_2 (0x0200) #define MCF5200_SR_IPL_3 (0x0300) #define MCF5200_SR_IPL_4 (0x0400) #define MCF5200_SR_IPL_5 (0x0500) #define MCF5200_SR_IPL_6 (0x0600) #define MCF5200_SR_IPL_7 (0x0700) #define MCF5200_SR_X (0x0010) #define MCF5200_SR_N (0x0008) #define MCF5200_SR_Z (0x0004) #define MCF5200_SR_V (0x0002) #define MCF5200_SR_C (0x0001) /***********************************************************************/ /* * The ColdFire family of processors has a simplified exception stack * frame that looks like the following: * * 3322222222221111 111111 * 1098765432109876 5432109876543210 * 8 +----------------+----------------+ * | Program Counter | * 4 +----------------+----------------+ * |FS/Fmt/Vector/FS| SR | * SP --> 0 +----------------+----------------+ * * The stack self-aligns to a 4-byte boundary at an exception, with * the FS/Fmt/Vector/FS field indicating the size of the adjustment * (SP += 0,1,2,3 bytes). */ #define MCF5200_RD_SF_FORMAT(PTR) \ ((*((uint16 *)(PTR)) >> 12) & 0x00FF) #define MCF5200_RD_SF_VECTOR(PTR) \ ((*((uint16 *)(PTR)) >> 2) & 0x00FF) #define MCF5200_RD_SF_FS(PTR) \ ( ((*((uint16 *)(PTR)) & 0x0C00) >> 8) | (*((uint16 *)(PTR)) & 0x0003) ) #define MCF5200_SF_SR(PTR) *((uint16 *)(PTR)+1) #define MCF5200_SF_PC(PTR) *((uint32 *)(PTR)+1) #if 0 typedef struct { uint16 SR; uint16 FS_FMT_VECTOR_FS; uint32 PC; } MCF5200_STACK_FRAME; #endif /********************************************************************** * * Macro for computing address of on-chip peripheral registers * ***********************************************************************/ #define Mcf5272_addr(IMMP,OFFSET) ((void *)&((uint8 *)IMMP)[OFFSET]) /* Macro that returns a pointer to the Internal Memory Map */ #define mcf5272_get_immp() ((MCF5272_IMM *)(IMM_ADDRESS)) /********************************************************************** * * Macros for accessing the on-chip I/O resources * ***********************************************************************/ #define Mcf5272_iord(IMMP,OFFSET,SIZE) \ *(volatile uint ## SIZE *)(Mcf5272_addr(IMMP,OFFSET)) #define Mcf5272_iowr(IMMP,OFFSET,SIZE,DATA) \ *(volatile uint ## SIZE *)(Mcf5272_addr(IMMP,OFFSET)) = (DATA) /********************************************************************** * * CPU Space Registers * ***********************************************************************/ /* Bit level definitions and macros */ #define MCF5272_CACR_CENB (0x80000000) #define MCF5272_CACR_CFRZ (0x08000000) #define MCF5272_CACR_CINV (0x01000000) #define MCF5272_CACR_CMOD (0x00000200) #define MCF5272_CACR_CWRP (0x00000020) #define MCF5272_CACR_CLNF_00 (0x00000000) #define MCF5272_CACR_CLNF_01 (0x00000001) #define MCF5272_CACR_CLNF_10 (0x00000002) #define MCF5272_ACR_BASE(a) ((a)&0xFF000000) #define MCF5272_ACR_MASK(a) (((a)&0xFF000000) >> 8) #define MCF5272_ACR_EN (0x00008000) #define MCF5272_ACR_S_USER (0x00000000) #define MCF5272_ACR_S_SUPER (0x00002000) #define MCF5272_ACR_S_IGNORE (0x00006000) #define MCF5272_ACR_ENIB (0x00000080) #define MCF5272_ACR_CM (0x00000040) #define MCF5272_ACR_WP (0x00000004) #define MCF5272_SRAMBAR_BASE(a) ((a)&0xFFFFF000) #define MCF5272_SRAMBAR_WP (0x00000100) #define MCF5272_SRAMBAR_CI (0x00000020) #define MCF5272_SRAMBAR_SC (0x00000010) #define MCF5272_SRAMBAR_SD (0x00000008) #define MCF5272_SRAMBAR_UC (0x00000004) #define MCF5272_SRAMBAR_UD (0x00000002) #define MCF5272_SRAMBAR_V (0x00000001) #define MCF5272_ROMBAR_BASE(a) ((a)&0xFFFFF000) #define MCF5272_ROMBAR_WP (0x00000100) #define MCF5272_ROMBAR_CI (0x00000080) #define MCF5272_ROMBAR_SC (0x00000040) #define MCF5272_ROMBAR_SD (0x00000020) #define MCF5272_ROMBAR_UC (0x00000004) #define MCF5272_ROMBAR_UD (0x00000002) #define MCF5272_ROMBAR_V (0x00000001) #define MCF5272_MBAR_BASE(a) ((a)&0xFFFFFC00) #define MCF5272_MBAR_SC (0x00000010) #define MCF5272_MBAR_SD (0x00000008) #define MCF5272_MBAR_UC (0x00000004) #define MCF5272_MBAR_UD (0x00000002) #define MCF5272_MBAR_V (0x00000001) /********************************************************************** * * System Configuration Registers * ***********************************************************************/ /* Offsets of the registers from the MBAR */ #define MCF5272_SIM_MBAR (0x0000) #define MCF5272_SIM_SCR (0x0004) #define MCF5272_SIM_SPR (0x0006) #define MCF5272_SIM_PMR (0x0008) #define MCF5272_SIM_ALPR (0x000E) #define MCF5272_SIM_DIR (0x0010) /* Read access macros for general use */ #define MCF5272_RD_SIM_MBAR(IMMP) Mcf5272_iord(IMMP,MCF5272_SIM_MBAR,32) #define MCF5272_RD_SIM_SCR(IMMP) Mcf5272_iord(IMMP,MCF5272_SIM_SCR,16) #define MCF5272_RD_SIM_SPR(IMMP) Mcf5272_iord(IMMP,MCF5272_SIM_SPR,16) #define MCF5272_RD_SIM_PMR(IMMP) Mcf5272_iord(IMMP,MCF5272_SIM_PMR,32) #define MCF5272_RD_SIM_DIR(IMMP) Mcf5272_iord(IMMP,MCF5272_SIM_DIR,32) /* Write access macros for general use */ #define MCF5272_WR_SIM_SCR(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_SIM_SCR,16,DATA) #define MCF5272_WR_SIM_SPR(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_SIM_SPR,16,DATA) #define MCF5272_WR_SIM_PMR(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_SIM_PMR,32,DATA) #define MCF5272_WR_SIM_ALPR(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_SIM_ALPR,16,DATA) /* Bit level definitions and macros */ #define MCF5272_SIM_SCR_HRST 0x1000 #define MCF5272_SIM_SCR_DRAMRST 0x3000 #define MCF5272_SIM_SCR_SWTR 0x2000 #define MCF5272_SIM_SCR_AR 0x0080 #define MCF5272_SIM_SCR_SOFT_RES 0x0040 #define MCF5272_SIM_SCR_HWWD_128 0x0000 #define MCF5272_SIM_SCR_HWWD_256 0x0001 #define MCF5272_SIM_SCR_HWWD_512 0x0002 #define MCF5272_SIM_SCR_HWWD_1024 0x0003 #define MCF5272_SIM_SCR_HWWD_2048 0x0004 #define MCF5272_SIM_SCR_HWWD_4096 0x0005 #define MCF5272_SIM_SCR_HWWD_8192 0x0006 #define MCF5272_SIM_SCR_HWWD_16384 0x0007 #define MCF5272_SIM_SPR_ADC 0x8000 #define MCF5272_SIM_SPR_ADCEN 0x0080 #define MCF5272_SIM_SPR_WPV 0x4000 #define MCF5272_SIM_SPR_WPVEN 0x0040 #define MCF5272_SIM_SPR_SMV 0x2000 #define MCF5272_SIM_SPR_SMVEN 0x0020 #define MCF5272_SIM_SPR_SBE 0x1000 #define MCF5272_SIM_SPR_SBEEN 0x0010 #define MCF5272_SIM_SPR_HWT 0x0800 #define MCF5272_SIM_SPR_HWTEN 0x0008 #define MCF5272_SIM_SPR_RPV 0x0400 #define MCF5272_SIM_SPR_RPVEN 0x0004 #define MCF5272_SIM_SPR_EXT 0x0200 #define MCF5272_SIM_SPR_EXTEN 0x0002 #define MCF5272_SIM_SPR_SUV 0x0100 #define MCF5272_SIM_SPR_SUVEN 0x0001 #define MCF5272_SIM_PMR_BDMPDN 0x80000000 #define MCF5272_SIM_PMR_ENETPDN 0x04000000 #define MCF5272_SIM_PMR_PLIPPDN 0x02000000 #define MCF5272_SIM_PMR_DRAMPDN 0x01000000 #define MCF5272_SIM_PMR_DMAPDN 0x00800000 #define MCF5272_SIM_PMR_PWMPDN 0x00400000 #define MCF5272_SIM_PMR_QSPIPDN 0x00200000 #define MCF5272_SIM_PMR_TIMERPDN 0x00100000 #define MCF5272_SIM_PMR_GPIOPDN 0x00080000 #define MCF5272_SIM_PMR_USBPDN 0x00040000 #define MCF5272_SIM_PMR_UART1PDN 0x00020000 #define MCF5272_SIM_PMR_UART0PDN 0x00010000 #define MCF5272_SIM_PMR_USBWK 0x00000400 #define MCF5272_SIM_PMR_UART1WK 0x00000200 #define MCF5272_SIM_PMR_UART0WK 0x00000100 #define MCF5272_SIM_PMR_MOS 0x00000020 #define MCF5272_SIM_PMR_SLPEN 0x00000010 /********************************************************************** * * Interrupt Controller Registers * ***********************************************************************/ /* Offsets of the registers from the MBAR */ #define MCF5272_SIM_ICR1 (0x0020) #define MCF5272_SIM_ICR2 (0x0024) #define MCF5272_SIM_ICR3 (0x0028) #define MCF5272_SIM_ICR4 (0x002C) #define MCF5272_SIM_ISR (0x0030) #define MCF5272_SIM_PITR (0x0034) #define MCF5272_SIM_PIWR (0x0038) #define MCF5272_SIM_PIVR (0x003F) /* Read access macros for general use */ #define MCF5272_RD_SIM_ICR1(IMMP) Mcf5272_iord(IMMP,MCF5272_SIM_ICR1,32) #define MCF5272_RD_SIM_ICR2(IMMP) Mcf5272_iord(IMMP,MCF5272_SIM_ICR2,32) #define MCF5272_RD_SIM_ICR3(IMMP) Mcf5272_iord(IMMP,MCF5272_SIM_ICR3,32) #define MCF5272_RD_SIM_ICR4(IMMP) Mcf5272_iord(IMMP,MCF5272_SIM_ICR4,32) #define MCF5272_RD_SIM_ISR(IMMP) Mcf5272_iord(IMMP,MCF5272_SIM_ISR,32) #define MCF5272_RD_SIM_PITR(IMMP) Mcf5272_iord(IMMP,MCF5272_SIM_PITR,32) #define MCF5272_RD_SIM_PIWR(IMMP) Mcf5272_iord(IMMP,MCF5272_SIM_PIWR,32) #define MCF5272_RD_SIM_PIVR(IMMP) Mcf5272_iord(IMMP,MCF5272_SIM_PIVR,8) /* Write access macros for general use */ #define MCF5272_WR_SIM_ICR1(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_SIM_ICR1,32,DATA) #define MCF5272_WR_SIM_ICR2(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_SIM_ICR2,32,DATA) #define MCF5272_WR_SIM_ICR3(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_SIM_ICR3,32,DATA) #define MCF5272_WR_SIM_ICR4(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_SIM_ICR4,32,DATA) #define MCF5272_WR_SIM_PITR(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_SIM_PITR,32,DATA) #define MCF5272_WR_SIM_PIWR(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_SIM_PIWR,32,DATA) #define MCF5272_WR_SIM_PIVR(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_SIM_PIVR,8,DATA) /* Bit level definitions and macros */ #define MCF5272_SIM_ICR_INT1_IL(a) ( 0x80000000 | (((a)&0x07)<<28) ) #define MCF5272_SIM_ICR_INT2_IL(a) ( 0x08000000 | (((a)&0x07)<<24) ) #define MCF5272_SIM_ICR_INT3_IL(a) ( 0x00800000 | (((a)&0x07)<<20) ) #define MCF5272_SIM_ICR_INT4_IL(a) ( 0x00080000 | (((a)&0x07)<<16) ) #define MCF5272_SIM_ICR_TMR0_IL(a) ( 0x00008000 | (((a)&0x07)<<12) ) #define MCF5272_SIM_ICR_TMR1_IL(a) ( 0x00000800 | (((a)&0x07)<<8) ) #define MCF5272_SIM_ICR_TMR2_IL(a) ( 0x00000080 | (((a)&0x07)<<4) ) #define MCF5272_SIM_ICR_TMR3_IL(a) ( 0x00000008 | ((a)&0x07) ) #define MCF5272_SIM_ICR_TMR_IL(a,x) ( (0x8 | ((a)&0x07)) << ((3-x)*4)) #define MCF5272_SIM_ICR_UART0_IL(a) ( 0x80000000 | (((a)&0x07)<<28) ) #define MCF5272_SIM_ICR_UART1_IL(a) ( 0x08000000 | (((a)&0x07)<<24) ) #define MCF5272_SIM_ICR_PLIP_IL(a) ( 0x00800000 | (((a)&0x07)<<20) ) #define MCF5272_SIM_ICR_PLIA_IL(a) ( 0x00080000 | (((a)&0x07)<<16) ) #define MCF5272_SIM_ICR_USB0_IL(a) ( 0x00008000 | (((a)&0x07)<<12) ) #define MCF5272_SIM_ICR_USB1_IL(a) ( 0x00000800 | (((a)&0x07)<<8) ) #define MCF5272_SIM_ICR_USB2_IL(a) ( 0x00000800 | (((a)&0x07)<<4) ) #define MCF5272_SIM_ICR_USB3_IL(a) ( 0x00000800 | ((a)&0x07) ) #define MCF5272_SIM_ICR_USB4_IL(a) ( 0x80000000 | (((a)&0x07)<<28) ) #define MCF5272_SIM_ICR_USB5_IL(a) ( 0x08000000 | (((a)&0x07)<<24) ) #define MCF5272_SIM_ICR_USB6_IL(a) ( 0x00800000 | (((a)&0x07)<<20) ) #define MCF5272_SIM_ICR_USB7_IL(a) ( 0x00080000 | (((a)&0x07)<<16) ) #define MCF5272_SIM_ICR_DMA_IL(a) ( 0x00008000 | (((a)&0x07)<<12) ) #define MCF5272_SIM_ICR_ERX_IL(a) ( 0x00000800 | (((a)&0x07)<<8) ) #define MCF5272_SIM_ICR_ETX_IL(a) ( 0x00000080 | (((a)&0x07)<<4) ) #define MCF5272_SIM_ICR_ENTC_IL(a) ( 0x00000008 | ((a)&0x07) ) #define MCF5272_SIM_ICR_QSPI_IL(a) ( 0x80000000 | (((a)&0x07)<<28) ) #define MCF5272_SIM_ICR_INT5_IL(a) ( 0x08000000 | (((a)&0x07)<<24) ) #define MCF5272_SIM_ICR_INT6_IL(a) ( 0x00800000 | (((a)&0x07)<<20) ) #define MCF5272_SIM_ICR_SWTO_IL(a) ( 0x00080000 | (((a)&0x07)<<16) ) #define MCF5272_SIM_PITR_POS_EDGE (0xF0000060) #define MCF5272_SIM_PITR_NEG_EDGE (0x00000000) #define MCF5272_SIM_PIWR_INT1 (0x80000000) #define MCF5272_SIM_PIWR_INT2 (0x40000000) #define MCF5272_SIM_PIWR_INT3 (0x20000000) #define MCF5272_SIM_PIWR_INT4 (0x10000000) #define MCF5272_SIM_PIWR_TMR0 (0x08000000) #define MCF5272_SIM_PIWR_TMR1 (0x04000000) #define MCF5272_SIM_PIWR_TMR2 (0x02000000) #define MCF5272_SIM_PIWR_TMR3 (0x01000000) #define MCF5272_SIM_PIWR_UART0 (0x00800000) #define MCF5272_SIM_PIWR_UART1 (0x00400000) #define MCF5272_SIM_PIWR_PLIP (0x00200000) #define MCF5272_SIM_PIWR_PLIA (0x00100000) #define MCF5272_SIM_PIWR_USB_0 (0x00080000) #define MCF5272_SIM_PIWR_USB_1 (0x00040000) #define MCF5272_SIM_PIWR_USB_2 (0x00020000) #define MCF5272_SIM_PIWR_USB_3 (0x00010000) #define MCF5272_SIM_PIWR_USB_4 (0x00008000) #define MCF5272_SIM_PIWR_USB_5 (0x00004000) #define MCF5272_SIM_PIWR_USB_6 (0x00002000) #define MCF5272_SIM_PIWR_USB_7 (0x00001000) #define MCF5272_SIM_PIWR_DMA (0x00000800) #define MCF5272_SIM_PIWR_ERx (0x00000400) #define MCF5272_SIM_PIWR_ETx (0x00000200) #define MCF5272_SIM_PIWR_ENTC (0x00000100) #define MCF5272_SIM_PIWR_QSPI (0x00000080) #define MCF5272_SIM_PIWR_INT5 (0x00000040) #define MCF5272_SIM_PIWR_INT6 (0x00000020) #define MCF5272_SIM_PIWR_SWTO (0x00000010) #define MCF5272_SIM_PIVR_IL(a) (((a)&0x07)<<5) #define MCF5272_SIM_PIVR_NORMAL (0x40) /********************************************************************** * * Interrupt Vectors * **********************************************************************/ #define MCF5272_VECTOR_INT1 65 #define MCF5272_VECTOR_INT2 66 #define MCF5272_VECTOR_INT3 67 #define MCF5272_VECTOR_INT4 68 #define MCF5272_VECTOR_TMR1 69 #define MCF5272_VECTOR_TMR2 70 #define MCF5272_VECTOR_TMR3 71 #define MCF5272_VECTOR_TMR4 72 #define MCF5272_VECTOR_UART1 73 #define MCF5272_VECTOR_UART2 74 #define MCF5272_VECTOR_PLIP 75 #define MCF5272_VECTOR_PLIA 76 #define MCF5272_VECTOR_USB0 77 #define MCF5272_VECTOR_USB1 78 #define MCF5272_VECTOR_USB2 79 #define MCF5272_VECTOR_USB3 80 #define MCF5272_VECTOR_USB4 81 #define MCF5272_VECTOR_USB5 82 #define MCF5272_VECTOR_USB6 83 #define MCF5272_VECTOR_USB7 84 #define MCF5272_VECTOR_DMA 85 #define MCF5272_VECTOR_ERx 86 #define MCF5272_VECTOR_ETx 87 #define MCF5272_VECTOR_ENTC 88 #define MCF5272_VECTOR_QSPI 89 #define MCF5272_VECTOR_INT5 90 #define MCF5272_VECTOR_INT6 91 #define MCF5272_VECTOR_SWTO 92 /********************************************************************** * * Chip Select Registers * ***********************************************************************/ /* Offsets of the registers from the MBAR */ #define MCF5272_CS_CSBR0 (0x0040) #define MCF5272_CS_CSOR0 (0x0044) #define MCF5272_CS_CSBR1 (0x0048) #define MCF5272_CS_CSOR1 (0x004C) #define MCF5272_CS_CSBR2 (0x0050) #define MCF5272_CS_CSOR2 (0x0054) #define MCF5272_CS_CSBR3 (0x0058) #define MCF5272_CS_CSOR3 (0x005C) #define MCF5272_CS_CSBR4 (0x0060) #define MCF5272_CS_CSOR4 (0x0064) #define MCF5272_CS_CSBR5 (0x0068) #define MCF5272_CS_CSOR5 (0x006C) #define MCF5272_CS_CSBR6 (0x0070) #define MCF5272_CS_CSOR6 (0x0074) #define MCF5272_CS_CSBR7 (0x0078) #define MCF5272_CS_CSOR7 (0x007C) /* Read access macros for general use */ #define MCF5272_RD_CS_CSBR0(IMMP) Mcf5272_iord(IMMP,MCF5272_CS_CSBR0,32) #define MCF5272_RD_CS_CSOR0(IMMP) Mcf5272_iord(IMMP,MCF5272_CS_CSOR0,32) #define MCF5272_RD_CS_CSBR1(IMMP) Mcf5272_iord(IMMP,MCF5272_CS_CSBR1,32) #define MCF5272_RD_CS_CSOR1(IMMP) Mcf5272_iord(IMMP,MCF5272_CS_CSOR1,32) #define MCF5272_RD_CS_CSBR2(IMMP) Mcf5272_iord(IMMP,MCF5272_CS_CSBR2,32) #define MCF5272_RD_CS_CSOR2(IMMP) Mcf5272_iord(IMMP,MCF5272_CS_CSOR2,32) #define MCF5272_RD_CS_CSBR3(IMMP) Mcf5272_iord(IMMP,MCF5272_CS_CSBR3,32) #define MCF5272_RD_CS_CSOR3(IMMP) Mcf5272_iord(IMMP,MCF5272_CS_CSOR3,32) #define MCF5272_RD_CS_CSBR4(IMMP) Mcf5272_iord(IMMP,MCF5272_CS_CSBR4,32) #define MCF5272_RD_CS_CSOR4(IMMP) Mcf5272_iord(IMMP,MCF5272_CS_CSOR4,32) #define MCF5272_RD_CS_CSBR5(IMMP) Mcf5272_iord(IMMP,MCF5272_CS_CSBR5,32) #define MCF5272_RD_CS_CSOR5(IMMP) Mcf5272_iord(IMMP,MCF5272_CS_CSOR5,32) #define MCF5272_RD_CS_CSBR6(IMMP) Mcf5272_iord(IMMP,MCF5272_CS_CSBR6,32) #define MCF5272_RD_CS_CSOR6(IMMP) Mcf5272_iord(IMMP,MCF5272_CS_CSOR6,32) #define MCF5272_RD_CS_CSBR7(IMMP) Mcf5272_iord(IMMP,MCF5272_CS_CSBR7,32) #define MCF5272_RD_CS_CSOR7(IMMP) Mcf5272_iord(IMMP,MCF5272_CS_CSOR7,32) /* Write access macros for general use */ #define MCF5272_WR_CS_CSBR0(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_CS_CSBR0,32,DATA) #define MCF5272_WR_CS_CSOR0(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_CS_CSOR0,32,DATA) #define MCF5272_WR_CS_CSBR1(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_CS_CSBR1,32,DATA) #define MCF5272_WR_CS_CSOR1(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_CS_CSOR1,32,DATA) #define MCF5272_WR_CS_CSBR2(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_CS_CSBR2,32,DATA) #define MCF5272_WR_CS_CSOR2(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_CS_CSOR2,32,DATA) #define MCF5272_WR_CS_CSBR3(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_CS_CSBR3,32,DATA) #define MCF5272_WR_CS_CSOR3(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_CS_CSOR3,32,DATA) #define MCF5272_WR_CS_CSBR4(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_CS_CSBR4,32,DATA) #define MCF5272_WR_CS_CSOR4(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_CS_CSOR4,32,DATA) #define MCF5272_WR_CS_CSBR5(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_CS_CSBR5,32,DATA) #define MCF5272_WR_CS_CSOR5(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_CS_CSOR5,32,DATA) #define MCF5272_WR_CS_CSBR6(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_CS_CSBR6,32,DATA) #define MCF5272_WR_CS_CSOR6(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_CS_CSOR6,32,DATA) #define MCF5272_WR_CS_CSBR7(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_CS_CSBR7,32,DATA) #define MCF5272_WR_CS_CSOR7(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_CS_CSOR7,32,DATA) /* Bit level definitions and macros */ #define MCF5272_CS_BR_BASE(a) ((a)&0xFFFFF000) #define MCF5272_CS_OR_MASK_32M (0xFE000000) #define MCF5272_CS_OR_MASK_16M (0xFF000000) #define MCF5272_CS_OR_MASK_8M (0xFF800000) #define MCF5272_CS_OR_MASK_4M (0xFFC00000) #define MCF5272_CS_OR_MASK_2M (0xFFE00000) #define MCF5272_CS_OR_MASK_1M (0xFFF00000) #define MCF5272_CS_OR_MASK_512K (0xFFF80000) #define MCF5272_CS_OR_MASK_256K (0xFFFC0000) #define MCF5272_CS_OR_MASK_128K (0xFFFE0000) #define MCF5272_CS_OR_MASK_64K (0xFFFF0000) #define MCF5272_CS_OR_MASK_32K (0xFFFF8000) #define MCF5272_CS_OR_MASK_16K (0xFFFFC000) #define MCF5272_CS_OR_MASK_8K (0xFFFFE000) #define MCF5272_CS_OR_MASK_4K (0xFFFFF000) #define MCF5272_CS_OR_WS_MASK (0x007C) #define MCF5272_CS_OR_WS(a) (((a)&0x1F)<<2) #define MCF5272_CS_OR_BRST (0x0100) #define MCF5272_CS_OR_RD (0x0003) #define MCF5272_CS_OR_WR (0x0001) #define MCF5272_CS_BR_PS_8 (0x0100) #define MCF5272_CS_BR_PS_16 (0x0200) #define MCF5272_CS_BR_PS_32 (0x0000) #define MCF5272_CS_BR_PS_LINE (0x0300) #define MCF5272_CS_BR_ROM (0x0000) #define MCF5272_CS_BR_SRAM (0x0000) #define MCF5272_CS_BR_SRAM_8 (0x0C00) #define MCF5272_CS_BR_SDRAM (0x0400) #define MCF5272_CS_BR_ISA (0x0800) #define MCF5272_CS_BR_SV (0x0080) #define MCF5272_CS_BR_EN (0x0001) /********************************************************************** * * Ports Registers Description * ***********************************************************************/ /* Offsets of the registers from the MBAR */ #define MCF5272_GPIO_PACNT (0x0080) #define MCF5272_GPIO_PADDR (0x0084) #define MCF5272_GPIO_PADAT (0x0086) #define MCF5272_GPIO_PBCNT (0x0088) #define MCF5272_GPIO_PBDDR (0x008C) #define MCF5272_GPIO_PBDAT (0x008E) #define MCF5272_GPIO_PCDDR (0x0094) #define MCF5272_GPIO_PCDAT (0x0096) #define MCF5272_GPIO_PDCNT (0x0098) /* Read access macros for general use */ #define MCF5272_RD_GPIO_PACNT(IMMP) Mcf5272_iord(IMMP,MCF5272_GPIO_PACNT,32) #define MCF5272_RD_GPIO_PADDR(IMMP) Mcf5272_iord(IMMP,MCF5272_GPIO_PADDR,16) #define MCF5272_RD_GPIO_PADAT(IMMP) Mcf5272_iord(IMMP,MCF5272_GPIO_PADAT,16) #define MCF5272_RD_GPIO_PBCNT(IMMP) Mcf5272_iord(IMMP,MCF5272_GPIO_PBCNT,32) #define MCF5272_RD_GPIO_PBDDR(IMMP) Mcf5272_iord(IMMP,MCF5272_GPIO_PBDDR,16) #define MCF5272_RD_GPIO_PBDAT(IMMP) Mcf5272_iord(IMMP,MCF5272_GPIO_PBDAT,16) #define MCF5272_RD_GPIO_PCDDR(IMMP) Mcf5272_iord(IMMP,MCF5272_GPIO_PCDDR,16) #define MCF5272_RD_GPIO_PCDAT(IMMP) Mcf5272_iord(IMMP,MCF5272_GPIO_PCDAT,16) #define MCF5272_RD_GPIO_PDCNT(IMMP) Mcf5272_iord(IMMP,MCF5272_GPIO_PDCNT,32) /* Write access macros for general use */ #define MCF5272_WR_GPIO_PACNT(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_GPIO_PACNT,32,DATA) #define MCF5272_WR_GPIO_PADDR(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_GPIO_PADDR,16,DATA) #define MCF5272_WR_GPIO_PADAT(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_GPIO_PADAT,16,DATA) #define MCF5272_WR_GPIO_PBCNT(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_GPIO_PBCNT,32,DATA) #define MCF5272_WR_GPIO_PBDDR(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_GPIO_PBDDR,16,DATA) #define MCF5272_WR_GPIO_PBDAT(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_GPIO_PBDAT,16,DATA) #define MCF5272_WR_GPIO_PCDDR(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_GPIO_PCDDR,16,DATA) #define MCF5272_WR_GPIO_PCDAT(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_GPIO_PCDAT,16,DATA) #define MCF5272_WR_GPIO_PDCNT(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_GPIO_PDCNT,32,DATA) /* Bit level definitions and macros */ #define MCF5272_GPIO_DDR15_INPUT (~0x80) #define MCF5272_GPIO_DDR15_OUTPUT ( 0x80) #define MCF5272_GPIO_DDR14_INPUT (~0x40) #define MCF5272_GPIO_DDR14_OUTPUT ( 0x40) #define MCF5272_GPIO_DDR13_INPUT (~0x20) #define MCF5272_GPIO_DDR13_OUTPUT ( 0x20) #define MCF5272_GPIO_DDR12_INPUT (~0x10) #define MCF5272_GPIO_DDR12_OUTPUT ( 0x10) #define MCF5272_GPIO_DDR11_INPUT (~0x08) #define MCF5272_GPIO_DDR11_OUTPUT ( 0x08) #define MCF5272_GPIO_DDR10_INPUT (~0x04) #define MCF5272_GPIO_DDR10_OUTPUT ( 0x04) #define MCF5272_GPIO_DDR9_INPUT (~0x02) #define MCF5272_GPIO_DDR9_OUTPUT ( 0x02) #define MCF5272_GPIO_DDR8_INPUT (~0x01) #define MCF5272_GPIO_DDR8_OUTPUT ( 0x01) #define MCF5272_GPIO_DDR7_INPUT (~0x80) #define MCF5272_GPIO_DDR7_OUTPUT ( 0x80) #define MCF5272_GPIO_DDR6_INPUT (~0x40) #define MCF5272_GPIO_DDR6_OUTPUT ( 0x40) #define MCF5272_GPIO_DDR5_INPUT (~0x20) #define MCF5272_GPIO_DDR5_OUTPUT ( 0x20) #define MCF5272_GPIO_DDR4_INPUT (~0x10) #define MCF5272_GPIO_DDR4_OUTPUT ( 0x10) #define MCF5272_GPIO_DDR3_INPUT (~0x08) #define MCF5272_GPIO_DDR3_OUTPUT ( 0x08) #define MCF5272_GPIO_DDR2_INPUT (~0x04) #define MCF5272_GPIO_DDR2_OUTPUT ( 0x04) #define MCF5272_GPIO_DDR1_INPUT (~0x02) #define MCF5272_GPIO_DDR1_OUTPUT ( 0x02) #define MCF5272_GPIO_DDR0_INPUT (~0x01) #define MCF5272_GPIO_DDR0_OUTPUT ( 0x01) #define MCF5272_GPIO_DAT15 ( 0x80) #define MCF5272_GPIO_DAT14 ( 0x40) #define MCF5272_GPIO_DAT13 ( 0x20) #define MCF5272_GPIO_DAT12 ( 0x10) #define MCF5272_GPIO_DAT11 ( 0x08) #define MCF5272_GPIO_DAT10 ( 0x04) #define MCF5272_GPIO_DAT9 ( 0x02) #define MCF5272_GPIO_DAT8 ( 0x01) #define MCF5272_GPIO_DAT7 ( 0x80) #define MCF5272_GPIO_DAT6 ( 0x40) #define MCF5272_GPIO_DAT5 ( 0x20) #define MCF5272_GPIO_DAT4 ( 0x10) #define MCF5272_GPIO_DAT3 ( 0x08) #define MCF5272_GPIO_DAT2 ( 0x04) #define MCF5272_GPIO_DAT1 ( 0x02) #define MCF5272_GPIO_DAT0 ( 0x01) /********************************************************************** * * QSPI Module Registers Description * ***********************************************************************/ /* Offsets of the registers from the MBAR */ #define MCF5272_QSPI_QMR (0x00A0) #define MCF5272_QSPI_QDLYR (0x00A4) #define MCF5272_QSPI_QWR (0x00A8) #define MCF5272_QSPI_QIR (0x00AC) #define MCF5272_QSPI_QAR (0x00B0) #define MCF5272_QSPI_QDR (0x00B4) /* Read access macros for general use */ #define MCF5272_RD_QSPI_QMR(IMMP) \ Mcf5272_iord(IMMP,MCF5272_QSPI_QMR,16) #define MCF5272_RD_QSPI_QDLYR(IMMP) \ Mcf5272_iord(IMMP,MCF5272_QSPI_QDLYR,16) #define MCF5272_RD_QSPI_QWR(IMMP) \ Mcf5272_iord(IMMP,MCF5272_QSPI_QWR,16) #define MCF5272_RD_QSPI_QIR(IMMP) \ Mcf5272_iord(IMMP,MCF5272_QSPI_QIR,16) #define MCF5272_RD_QSPI_QAR(IMMP) \ Mcf5272_iord(IMMP,MCF5272_QSPI_QAR,16) #define MCF5272_RD_QSPI_QDR(IMMP) \ Mcf5272_iord(IMMP,MCF5272_QSPI_QDR,16) /* Write access macros for general use */ #define MCF5272_WR_QSPI_QMR(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_QSPI_QMR,16,DATA) #define MCF5272_WR_QSPI_QDLYR(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_QSPI_QDLYR,16,DATA) #define MCF5272_WR_QSPI_QWR(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_QSPI_QWR,16,DATA) #define MCF5272_WR_QSPI_QIR(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_QSPI_QIR,16,DATA) #define MCF5272_WR_QSPI_QAR(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_QSPI_QAR,16,DATA) #define MCF5272_WR_QSPI_QDR(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_QSPI_QDR,16,DATA) /********************************************************************** * * PWM Module Registers Description * ***********************************************************************/ /* Offsets of the registers from the MBAR */ #define MCF5272_PWM_PWMCR1 (0x00C0) #define MCF5272_PWM_PWMCR2 (0x00C4) #define MCF5272_PWM_PWMCR3 (0x00C8) #define MCF5272_PWM_PWMWD1 (0x00D0) #define MCF5272_PWM_PWMWD2 (0x00D4) #define MCF5272_PWM_PWMWD3 (0x00D8) /* Read access macros for general use */ #define MCF5272_RD_PWM_PWMCR1(IMMP) Mcf5272_iord(IMMP,MCF5272_PWM_PWMCR1,8) #define MCF5272_RD_PWM_PWMCR2(IMMP) Mcf5272_iord(IMMP,MCF5272_PWM_PWMCR2,8) #define MCF5272_RD_PWM_PWMCR3(IMMP) Mcf5272_iord(IMMP,MCF5272_PWM_PWMCR3,8) #define MCF5272_RD_PWM_PWMWD1(IMMP) Mcf5272_iord(IMMP,MCF5272_PWM_PWMWD1,8) #define MCF5272_RD_PWM_PWMWD2(IMMP) Mcf5272_iord(IMMP,MCF5272_PWM_PWMWD2,8) #define MCF5272_RD_PWM_PWMWD3(IMMP) Mcf5272_iord(IMMP,MCF5272_PWM_PWMWD3,8) /* Write access macros for general use */ #define MCF5272_WR_PWM_PWMCR1(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_PWM_PWMCR1,8,DATA) #define MCF5272_WR_PWM_PWMCR2(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_PWM_PWMCR2,8,DATA) #define MCF5272_WR_PWM_PWMCR3(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_PWM_PWMCR3,8,DATA) #define MCF5272_WR_PWM_PWMWD1(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_PWM_PWMWD1,8,DATA) #define MCF5272_WR_PWM_PWMWD2(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_PWM_PWMWD2,8,DATA) #define MCF5272_WR_PWM_PWMWD3(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_PWM_PWMWD3,8,DATA) /********************************************************************** * * DMA Module Registers Description * ***********************************************************************/ /* Offsets of the registers from the MBAR */ #define MCF5272_DMA_DCMR (0x00E0) #define MCF5272_DMA_DCIR (0x00E6) #define MCF5272_DMA_DBCR (0x00E8) #define MCF5272_DMA_DSAR (0x00EC) #define MCF5272_DMA_DDAR (0x00F0) /* Read access macros for general use */ #define MCF5272_RD_DMA_DCMR(IMMP) Mcf5272_iord(IMMP,MCF5272_DMA_DCMR,32) #define MCF5272_RD_DMA_DCIR(IMMP) Mcf5272_iord(IMMP,MCF5272_DMA_DCIR,16) #define MCF5272_RD_DMA_DBCR(IMMP) Mcf5272_iord(IMMP,MCF5272_DMA_DBCR,32) #define MCF5272_RD_DMA_DSAR(IMMP) Mcf5272_iord(IMMP,MCF5272_DMA_DSAR,32) #define MCF5272_RD_DMA_DDAR(IMMP) Mcf5272_iord(IMMP,MCF5272_DMA_DDAR,32) /* Write access macros for general use */ #define MCF5272_WR_DMA_DCMR(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_DMA_DCMR,32,DATA) #define MCF5272_WR_DMA_DCIR(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_DMA_DCIR,16,DATA) #define MCF5272_WR_DMA_DBCR(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_DMA_DBCR,32,DATA) #define MCF5272_WR_DMA_DSAR(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_DMA_DSAR,32,DATA) #define MCF5272_WR_DMA_DDAR(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_DMA_DDAR,32,DATA) /* Bit level definitions and macros */ #define MCF5272_DMA_DCMR_RESET (0x80000000) #define MCF5272_DMA_DCMR_EN (0x40000000) #define MCF5272_DMA_DCMR_RQM (0x000C0000) #define MCF5272_DMA_DCMR_DSTM_INC (0x00002000) #define MCF5272_DMA_DCMR_DSTT_UD (0x00000400) #define MCF5272_DMA_DCMR_DSTT_UC (0x00000800) #define MCF5272_DMA_DCMR_DSTT_SD (0x00001400) #define MCF5272_DMA_DCMR_DSTT_SC (0x00001800) #define MCF5272_DMA_DCMR_DSTS_LW (0x00000000) #define MCF5272_DMA_DCMR_DSTS_B (0x00000100) #define MCF5272_DMA_DCMR_DSTS_W (0x00000200) #define MCF5272_DMA_DCMR_DSTS_LINE (0x00000300) #define MCF5272_DMA_DCMR_SRCM_INC (0x00000020) #define MCF5272_DMA_DCMR_SRCT_UD (0x00000004) #define MCF5272_DMA_DCMR_SRCT_UC (0x00000008) #define MCF5272_DMA_DCMR_SRCT_SD (0x00000014) #define MCF5272_DMA_DCMR_SRCT_SC (0x00000018) #define MCF5272_DMA_DCMR_SRCS_LW (0x00000000) #define MCF5272_DMA_DCMR_SRCS_B (0x00000001) #define MCF5272_DMA_DCMR_SRCS_W (0x00000002) #define MCF5272_DMA_DCMR_SRCS_LINE (0x00000003) #define MCF5272_DMA_DCIR_INVEN (0x1000) #define MCF5272_DMA_DCIR_ASCEN (0x0800) #define MCF5272_DMA_DCIR_TEEN (0x0200) #define MCF5272_DMA_DCIR_TCEN (0x0100) #define MCF5272_DMA_DCIR_INV (0x0010) #define MCF5272_DMA_DCIR_ASC (0x0008) #define MCF5272_DMA_DCIR_TE (0x0002) #define MCF5272_DMA_DCIR_TC (0x0001) /********************************************************************** * * USART Module Registers Description * ***********************************************************************/ /* Offsets of the registers from the MBAR */ #define MCF5272_UART0_UMR (0x0100) /* RW */ #define MCF5272_UART0_USR (0x0104) /* USR RO, UCSR WO */ #define MCF5272_UART0_UCR (0x0108) /* WO */ #define MCF5272_UART0_UBUF (0x010C) /* URB RO, UTB WO */ #define MCF5272_UART0_UCCR (0x0110) /* UCCR RO, UACR WO */ #define MCF5272_UART0_UISR (0x0114) /* UISR RO, UIMR WO */ #define MCF5272_UART0_UBG1 (0x0118) /* WO */ #define MCF5272_UART0_UBG2 (0x011C) /* WO */ #define MCF5272_UART0_UABR1 (0x0120) /* RO */ #define MCF5272_UART0_UABR2 (0x0124) /* RO */ #define MCF5272_UART0_UTFCSR (0x0128) /* RW */ #define MCF5272_UART0_URFCSR (0x012C) /* RW */ #define MCF5272_UART0_UIP (0x0134) /* RO */ #define MCF5272_UART0_UOP1 (0x0138) /* WO */ #define MCF5272_UART0_UOP0 (0x013C) /* WO */ #define MCF5272_UART1_UMR (0x0140) /* RW */ #define MCF5272_UART1_USR (0x0144) /* USR RO, UCSR WO */ #define MCF5272_UART1_UCR (0x0148) /* WO */ #define MCF5272_UART1_UBUF (0x014C) /* URB RO, UTB WO */ #define MCF5272_UART1_UCCR (0x0150) /* UCCR RO, UACR WO */ #define MCF5272_UART1_UISR (0x0154) /* UISR RO, UIMR WO */ #define MCF5272_UART1_UBG1 (0x0158) /* WO */ #define MCF5272_UART1_UBG2 (0x015C) /* WO */ #define MCF5272_UART1_UABR1 (0x0160) /* RO */ #define MCF5272_UART1_UABR2 (0x0164) /* RO */ #define MCF5272_UART1_UTFCSR (0x0168) /* RW */ #define MCF5272_UART1_URFCSR (0x016C) /* RW */ #define MCF5272_UART1_UIP (0x0174) /* RO */ #define MCF5272_UART1_UOP1 (0x0178) /* WO */ #define MCF5272_UART1_UOP0 (0x017C) /* WO */ /* Read access macros for general use */ #define MCF5272_RD_UART0_UMR(IMMP) \ Mcf5272_iord(IMMP,MCF5272_UART0_UMR,8) #define MCF5272_RD_UART0_USR(IMMP) \ Mcf5272_iord(IMMP,MCF5272_UART0_USR,8) #define MCF5272_RD_UART0_URB(IMMP) \ Mcf5272_iord(IMMP,MCF5272_UART0_UBUF,8) #define MCF5272_RD_UART0_UCCR(IMMP) \ Mcf5272_iord(IMMP,MCF5272_UART0_UCCR,8) #define MCF5272_RD_UART0_UISR(IMMP) \ Mcf5272_iord(IMMP,MCF5272_UART0_UISR,8) #define MCF5272_RD_UART0_UABR1(IMMP) \ Mcf5272_iord(IMMP,MCF5272_UART0_UABR1,8) #define MCF5272_RD_UART0_UABR2(IMMP) \ Mcf5272_iord(IMMP,MCF5272_UART1_UABR2,8) #define MCF5272_RD_UART0_UTFCSR(IMMP) \ Mcf5272_iord(IMMP,MCF5272_UART0_UTFCSR,8) #define MCF5272_RD_UART0_URFCSR(IMMP) \ Mcf5272_iord(IMMP,MCF5272_UART0_URFCSR,8) #define MCF5272_RD_UART0_UIP(IMMP) \ Mcf5272_iord(IMMP,MCF5272_UART0_UIP,8) #define MCF5272_RD_UART1_UMR(IMMP) \ Mcf5272_iord(IMMP,MCF5272_UART1_UMR,8) #define MCF5272_RD_UART1_USR(IMMP) \ Mcf5272_iord(IMMP,MCF5272_UART1_USR,8) #define MCF5272_RD_UART1_URB(IMMP) \ Mcf5272_iord(IMMP,MCF5272_UART1_UBUF,8) #define MCF5272_RD_UART1_UCCR(IMMP) \ Mcf5272_iord(IMMP,MCF5272_UART1_UCCR,8) #define MCF5272_RD_UART1_UISR(IMMP) \ Mcf5272_iord(IMMP,MCF5272_UART1_UISR,8) #define MCF5272_RD_UART1_UABR1(IMMP) \ Mcf5272_iord(IMMP,MCF5272_UART1_UABR1,8) #define MCF5272_RD_UART1_UABR2(IMMP) \ Mcf5272_iord(IMMP,MCF5272_UART1_UABR2,8) #define MCF5272_RD_UART1_UTFCSR(IMMP) \ Mcf5272_iord(IMMP,MCF5272_UART1_UTFCSR,8) #define MCF5272_RD_UART1_URFCSR(IMMP) \ Mcf5272_iord(IMMP,MCF5272_UART1_URFCSR,8) #define MCF5272_RD_UART1_UIP(IMMP) \ Mcf5272_iord(IMMP,MCF5272_UART1_UIP,8) /* Write access macros for general use */ #define MCF5272_WR_UART0_UMR(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_UART0_UMR,8,DATA) #define MCF5272_WR_UART0_UCSR(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_UART0_USR,8,DATA) #define MCF5272_WR_UART0_UCR(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_UART0_UCR,8,DATA) #define MCF5272_WR_UART0_UTB(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_UART0_UBUF,8,DATA) #define MCF5272_WR_UART0_UACR(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_UART0_UCCR,8,DATA) #define MCF5272_WR_UART0_UIMR(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_UART0_UISR,8,DATA) #define MCF5272_WR_UART0_UBG1(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_UART0_UBG1,8,DATA) #define MCF5272_WR_UART0_UBG2(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_UART0_UBG2,8,DATA) #define MCF5272_WR_UART0_UTFCSR(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_UART0_UTFCSR,8,DATA) #define MCF5272_WR_UART0_URFCSR(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_UART0_URFCSR,8,DATA) #define MCF5272_WR_UART0_UOP1(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_UART0_UOP1,8,DATA) #define MCF5272_WR_UART0_UOP0(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_UART0_UOP0,8,DATA) #define MCF5272_WR_UART1_UMR(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_UART1_UMR,8,DATA) #define MCF5272_WR_UART1_UCSR(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_UART1_USR,8,DATA) #define MCF5272_WR_UART1_UCR(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_UART1_UCR,8,DATA) #define MCF5272_WR_UART1_UTB(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_UART1_UBUF,8,DATA) #define MCF5272_WR_UART1_UACR(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_UART1_UCCR,8,DATA) #define MCF5272_WR_UART1_UIMR(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_UART1_UISR,8,DATA) #define MCF5272_WR_UART1_UBG1(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_UART1_UBG1,8,DATA) #define MCF5272_WR_UART1_UBG2(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_UART1_UBG2,8,DATA) #define MCF5272_WR_UART1_UTFCSR(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_UART1_UTFCSR,8,DATA) #define MCF5272_WR_UART1_URFCSR(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_UART1_URFCSR,8,DATA) #define MCF5272_WR_UART1_UOP1(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_UART1_UOP1,8,DATA) #define MCF5272_WR_UART1_UOP0(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_UART1_UOP0,8,DATA) /* Bit level definitions and macros */ #define MCF5272_UART_UMR1_RXRTS (0x80) #define MCF5272_UART_UMR1_RXIRQ (0x40) #define MCF5272_UART_UMR1_ERR (0x20) #define MCF5272_UART_UMR1_PM_MULTI_ADDR (0x1C) #define MCF5272_UART_UMR1_PM_MULTI_DATA (0x18) #define MCF5272_UART_UMR1_PM_NONE (0x10) #define MCF5272_UART_UMR1_PM_FORCE_HI (0x0C) #define MCF5272_UART_UMR1_PM_FORCE_LO (0x08) #define MCF5272_UART_UMR1_PM_ODD (0x04) #define MCF5272_UART_UMR1_PM_EVEN (0x00) #define MCF5272_UART_UMR1_BC_5 (0x00) #define MCF5272_UART_UMR1_BC_6 (0x01) #define MCF5272_UART_UMR1_BC_7 (0x02) #define MCF5272_UART_UMR1_BC_8 (0x03) #define MCF5272_UART_UMR2_CM_NORMAL (0x00) #define MCF5272_UART_UMR2_CM_ECHO (0x40) #define MCF5272_UART_UMR2_CM_LOCAL_LOOP (0x80) #define MCF5272_UART_UMR2_CM_REMOTE_LOOP (0xC0) #define MCF5272_UART_UMR2_TXRTS (0x20) #define MCF5272_UART_UMR2_TXCTS (0x10) #define MCF5272_UART_UMR2_STOP_BITS_1 (0x07) #define MCF5272_UART_UMR2_STOP_BITS_15 (0x08) #define MCF5272_UART_UMR2_STOP_BITS_2 (0x0F) #define MCF5272_UART_UMR2_STOP_BITS(a) ((a)&0x0f) /* Stop Bit Length */ #define MCF5272_UART_USR_RB (0x80) #define MCF5272_UART_USR_FE (0x40) #define MCF5272_UART_USR_PE (0x20) #define MCF5272_UART_USR_OE (0x10) #define MCF5272_UART_USR_TXEMP (0x08) #define MCF5272_UART_USR_TXRDY (0x04) #define MCF5272_UART_USR_FFULL (0x02) #define MCF5272_UART_USR_RXRDY (0x01) #define MCF5272_UART_UCSR_RCS(a) (((a)&0x0f)<<4) /* Rx Clk Select */ #define MCF5272_UART_UCSR_TCS(a) ((a)&0x0f) /* Tx Clk Select */ #define MCF5272_UART_UCR_NONE (0x00) #define MCF5272_UART_UCR_STOP_BREAK (0x70) #define MCF5272_UART_UCR_START_BREAK (0x60) #define MCF5272_UART_UCR_RESET_BKCHGINT (0x50) #define MCF5272_UART_UCR_RESET_ERROR (0x40) #define MCF5272_UART_UCR_RESET_TX (0x30) #define MCF5272_UART_UCR_RESET_RX (0x20) #define MCF5272_UART_UCR_RESET_MR (0x10) #define MCF5272_UART_UCR_TX_DISABLED (0x08) #define MCF5272_UART_UCR_TX_ENABLED (0x04) #define MCF5272_UART_UCR_RX_DISABLED (0x02) #define MCF5272_UART_UCR_RX_ENABLED (0x01) #define MCF5272_UART_UCCR_COS (0x10) #define MCF5272_UART_UCCR_CTS (0x01) #define MCF5272_UART_UACR_BRG (0x80) #define MCF5272_UART_UACR_CTMS_TIMER (0x60) #define MCF5272_UART_UACR_IEC (0x01) #define MCF5272_UART_UISR_COS (0x80) #define MCF5272_UART_UISR_DB (0x04) #define MCF5272_UART_UISR_RXRDY (0x02) #define MCF5272_UART_UISR_TXRDY (0x01) #define MCF5272_UART_UIMR_COS (0x80) #define MCF5272_UART_UIMR_DB (0x04) #define MCF5272_UART_UIMR_FFULL (0x02) #define MCF5272_UART_UIMR_TXRDY (0x01) /********************************************************************** * * SDRAM Controller Module Registers Description * ***********************************************************************/ /* Offsets of the registers from the MBAR */ #define MCF5272_SDRAMC_SDCCR (0x0180) #define MCF5272_SDRAMC_SDCTR (0x0184) /* Read access macros for general use */ #define MCF5272_RD_SDRAMC_SDCCR(IMMP) \ Mcf5272_iord(IMMP,MCF5272_SDRAMC_SDCCR,32) #define MCF5272_RD_SDRAMC_SDCTR(IMMP) \ Mcf5272_iord(IMMP,MCF5272_SDRAMC_SDCTR,32) /* Write access macros for general use */ #define MCF5272_WR_SDRAMC_SDCCR(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_SDRAMC_SDCCR,32,DATA) #define MCF5272_WR_SDRAMC_SDCTR(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_SDRAMC_SDCTR,32,DATA) /* Bit level definitions and macros */ #define MCF5272_SDRAMC_SDCCR_MCAS_A7 (0x0 << 13) #define MCF5272_SDRAMC_SDCCR_MCAS_A8 (0x1 << 13) #define MCF5272_SDRAMC_SDCCR_MCAS_A9 (0x2 << 13) #define MCF5272_SDRAMC_SDCCR_MCAS_A10 (0x3 << 13) #define MCF5272_SDRAMC_SDCCR_BALOC_A19 (0x0 << 8) #define MCF5272_SDRAMC_SDCCR_BALOC_A20 (0x1 << 8) #define MCF5272_SDRAMC_SDCCR_BALOC_A21 (0x2 << 8) #define MCF5272_SDRAMC_SDCCR_BALOC_A22 (0x3 << 8) #define MCF5272_SDRAMC_SDCCR_BALOC_A23 (0x4 << 8) #define MCF5272_SDRAMC_SDCCR_BALOC_A24 (0x5 << 8) #define MCF5272_SDRAMC_SDCCR_BALOC_A25 (0x6 << 8) #define MCF5272_SDRAMC_SDCCR_BALOC_A26 (0x7 << 8) #define MCF5272_SDRAMC_SDCCR_GSL (0x00000080) #define MCF5272_SDRAMC_SDCCR_REG (0x00000010) #define MCF5272_SDRAMC_SDCCR_INV (0x00000008) #define MCF5272_SDRAMC_SDCCR_SLEEP (0x00000004) #define MCF5272_SDRAMC_SDCCR_ACT (0x00000002) #define MCF5272_SDRAMC_SDCCR_INIT (0x00000001) #define MCF5272_SDRAMC_SDCTR_RTP_66MHz (0x3D << 10) #define MCF5272_SDRAMC_SDCTR_RTP_48MHz (0x2B << 10) #define MCF5272_SDRAMC_SDCTR_RTP_33MHz (0x1D << 10) #define MCF5272_SDRAMC_SDCTR_RTP_25MHz (0x16 << 10) #define MCF5272_SDRAMC_SDCTR_RC(x) ((x & 0x3) << 8) #define MCF5272_SDRAMC_SDCTR_RP(x) ((x & 0x3) << 4) #define MCF5272_SDRAMC_SDCTR_RCD(x) ((x & 0x3) << 2) #define MCF5272_SDRAMC_SDCTR_CLT_2 (0x00000001) #define MCF5272_SDRAMC_SDCTR_CLT_3 (0x00000002) #define MCF5272_SDRAMC_SDCTR_CLT_4 (0x00000003) /********************************************************************** * * Timer Module Registers Description * ***********************************************************************/ /* Offsets of the registers from the MBAR */ #define MCF5272_TIMER0_TMR (0x0200) #define MCF5272_TIMER0_TRR (0x0204) #define MCF5272_TIMER0_TCR (0x0208) #define MCF5272_TIMER0_TCN (0x020C) #define MCF5272_TIMER0_TER (0x0210) #define MCF5272_TIMER1_TMR (0x0220) #define MCF5272_TIMER1_TRR (0x0224) #define MCF5272_TIMER1_TCR (0x0228) #define MCF5272_TIMER1_TCN (0x022C) #define MCF5272_TIMER1_TER (0x0230) #define MCF5272_TIMER2_TMR (0x0240) #define MCF5272_TIMER2_TRR (0x0244) #define MCF5272_TIMER2_TCR (0x0248) #define MCF5272_TIMER2_TCN (0x024C) #define MCF5272_TIMER2_TER (0x0250) #define MCF5272_TIMER3_TMR (0x0260) #define MCF5272_TIMER3_TRR (0x0264) #define MCF5272_TIMER3_TCR (0x0268) #define MCF5272_TIMER3_TCN (0x026C) #define MCF5272_TIMER3_TER (0x0270) #define MCF5272_TIMER_WRRR (0x0280) #define MCF5272_TIMER_WIRR (0x0284) #define MCF5272_TIMER_WCR (0x0288) #define MCF5272_TIMER_WER (0x028C) /* Read access macros for general use */ #define MCF5272_RD_TIMER0_TMR(IMMP) Mcf5272_iord(IMMP,MCF5272_TIMER0_TMR,16) #define MCF5272_RD_TIMER0_TRR(IMMP) Mcf5272_iord(IMMP,MCF5272_TIMER0_TRR,16) #define MCF5272_RD_TIMER0_TCR(IMMP) Mcf5272_iord(IMMP,MCF5272_TIMER0_TCR,16) #define MCF5272_RD_TIMER0_TCN(IMMP) Mcf5272_iord(IMMP,MCF5272_TIMER0_TCN,16) #define MCF5272_RD_TIMER0_TER(IMMP) Mcf5272_iord(IMMP,MCF5272_TIMER0_TER,16) #define MCF5272_RD_TIMER1_TMR(IMMP) Mcf5272_iord(IMMP,MCF5272_TIMER1_TMR,16) #define MCF5272_RD_TIMER1_TRR(IMMP) Mcf5272_iord(IMMP,MCF5272_TIMER1_TRR,16) #define MCF5272_RD_TIMER1_TCR(IMMP) Mcf5272_iord(IMMP,MCF5272_TIMER1_TCR,16) #define MCF5272_RD_TIMER1_TCN(IMMP) Mcf5272_iord(IMMP,MCF5272_TIMER1_TCN,16) #define MCF5272_RD_TIMER1_TER(IMMP) Mcf5272_iord(IMMP,MCF5272_TIMER1_TER,16) #define MCF5272_RD_TIMER2_TMR(IMMP) Mcf5272_iord(IMMP,MCF5272_TIMER2_TMR,16) #define MCF5272_RD_TIMER2_TRR(IMMP) Mcf5272_iord(IMMP,MCF5272_TIMER2_TRR,16) #define MCF5272_RD_TIMER2_TCR(IMMP) Mcf5272_iord(IMMP,MCF5272_TIMER2_TCR,16) #define MCF5272_RD_TIMER2_TCN(IMMP) Mcf5272_iord(IMMP,MCF5272_TIMER2_TCN,16) #define MCF5272_RD_TIMER2_TER(IMMP) Mcf5272_iord(IMMP,MCF5272_TIMER2_TER,16) #define MCF5272_RD_TIMER3_TMR(IMMP) Mcf5272_iord(IMMP,MCF5272_TIMER3_TMR,16) #define MCF5272_RD_TIMER3_TRR(IMMP) Mcf5272_iord(IMMP,MCF5272_TIMER3_TRR,16) #define MCF5272_RD_TIMER3_TCR(IMMP) Mcf5272_iord(IMMP,MCF5272_TIMER3_TCR,16) #define MCF5272_RD_TIMER3_TCN(IMMP) Mcf5272_iord(IMMP,MCF5272_TIMER3_TCN,16) #define MCF5272_RD_TIMER3_TER(IMMP) Mcf5272_iord(IMMP,MCF5272_TIMER3_TER,16) #define MCF5272_RD_TIMER_TMR(IMMP,NUM) \ Mcf5272_iord(IMMP,MCF5272_TIMER0_TMR + (NUM * 0x20),16) #define MCF5272_RD_TIMER_TRR(IMMP,NUM) \ Mcf5272_iord(IMMP,MCF5272_TIMER0_TRR + (NUM * 0x20),16) #define MCF5272_RD_TIMER_TCR(IMMP,NUM) \ Mcf5272_iord(IMMP,MCF5272_TIMER0_TCR + (NUM * 0x20),16) #define MCF5272_RD_TIMER_TCN(IMMP,NUM) \ Mcf5272_iord(IMMP,MCF5272_TIMER0_TCN + (NUM * 0x20),16) #define MCF5272_RD_TIMER_TER(IMMP,NUM) \ Mcf5272_iord(IMMP,MCF5272_TIMER0_TER + (NUM * 0x20),16) #define MCF5272_RD_TIMER_WRRR(IMMP) Mcf5272_iord(IMMP,MCF5272_TIMER_WRRR,16) #define MCF5272_RD_TIMER_WIRR(IMMP) Mcf5272_iord(IMMP,MCF5272_TIMER_WIRR,16) #define MCF5272_RD_TIMER_WCR(IMMP) Mcf5272_iord(IMMP,MCF5272_TIMER_WCR,16) #define MCF5272_RD_TIMER_WER(IMMP) Mcf5272_iord(IMMP,MCF5272_TIMER_WER,16) /* Write access macros for general use */ #define MCF5272_WR_TIMER0_TMR(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_TIMER0_TMR,16,DATA) #define MCF5272_WR_TIMER0_TRR(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_TIMER0_TRR,16,DATA) #define MCF5272_WR_TIMER0_TCN(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_TIMER0_TCN,16,DATA) #define MCF5272_WR_TIMER0_TER(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_TIMER0_TER,16,DATA) #define MCF5272_WR_TIMER1_TMR(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_TIMER1_TMR,16,DATA) #define MCF5272_WR_TIMER1_TRR(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_TIMER1_TRR,16,DATA) #define MCF5272_WR_TIMER1_TCN(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_TIMER1_TCN,16,DATA) #define MCF5272_WR_TIMER1_TER(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_TIMER1_TER,16,DATA) #define MCF5272_WR_TIMER2_TMR(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_TIMER2_TMR,16,DATA) #define MCF5272_WR_TIMER2_TRR(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_TIMER2_TRR,16,DATA) #define MCF5272_WR_TIMER2_TCN(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_TIMER2_TCN,16,DATA) #define MCF5272_WR_TIMER2_TER(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_TIMER2_TER,16,DATA) #define MCF5272_WR_TIMER3_TMR(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_TIMER3_TMR,16,DATA) #define MCF5272_WR_TIMER3_TRR(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_TIMER3_TRR,16,DATA) #define MCF5272_WR_TIMER3_TCN(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_TIMER3_TCN,16,DATA) #define MCF5272_WR_TIMER3_TER(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_TIMER3_TER,16,DATA) #define MCF5272_WR_TIMER_WRRR(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_TIMER_WRRR,16,DATA) #define MCF5272_WR_TIMER_WIRR(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_TIMER_WIRR,16,DATA) #define MCF5272_WR_TIMER_WCR(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_TIMER_WCR,16,DATA) #define MCF5272_WR_TIMER_WER(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_TIMER_WER,16,DATA) #define MCF5272_WR_TIMER_TMR(IMMP,NUM,DATA) \ Mcf5272_iowr(IMMP,MCF5272_TIMER0_TMR + (NUM * 0x20),16,DATA) #define MCF5272_WR_TIMER_TRR(IMMP,NUM,DATA) \ Mcf5272_iowr(IMMP,MCF5272_TIMER0_TRR + (NUM * 0x20),16,DATA) #define MCF5272_WR_TIMER_TCN(IMMP,NUM,DATA) \ Mcf5272_iowr(IMMP,MCF5272_TIMER0_TCN + (NUM * 0x20),16,DATA) #define MCF5272_WR_TIMER_TER(IMMP,NUM,DATA) \ Mcf5272_iowr(IMMP,MCF5272_TIMER0_TER + (NUM * 0x20),16,DATA) /* Bit level definitions and macros */ #define MCF5272_TIMER_TMR_PS(a) (((a)&0x00FF)<<8) #define MCF5272_TIMER_TMR_CE_ANY (0x00C0) #define MCF5272_TIMER_TMR_CE_RISE (0x0080) #define MCF5272_TIMER_TMR_CE_FALL (0x0040) #define MCF5272_TIMER_TMR_CE_NONE (0x0000) #define MCF5272_TIMER_TMR_OM (0x0020) #define MCF5272_TIMER_TMR_ORI (0x0010) #define MCF5272_TIMER_TMR_FRR (0x0008) #define MCF5272_TIMER_TMR_CLK_TIN (0x0006) #define MCF5272_TIMER_TMR_CLK_DIV16 (0x0004) #define MCF5272_TIMER_TMR_CLK_MSCLK (0x0002) #define MCF5272_TIMER_TMR_CLK_STOP (0x0000) #define MCF5272_TIMER_TMR_RST (0x0001) #define MCF5272_TIMER_TER_REF (0x02) #define MCF5272_TIMER_TER_CAP (0x01) /********************************************************************** * * PLI Module Registers Description * ***********************************************************************/ /* Offsets of the registers from the MBAR */ #define MCF5272_PLI_P0B1RR (0x0300) #define MCF5272_PLI_P1B1RR (0x0304) #define MCF5272_PLI_P2B1RR (0x0308) #define MCF5272_PLI_P3B1RR (0x030C) #define MCF5272_PLI_P0B2RR (0x0310) #define MCF5272_PLI_P1B2RR (0x0314) #define MCF5272_PLI_P2B2RR (0x0318) #define MCF5272_PLI_P3B2RR (0x031C) #define MCF5272_PLI_P0DRR (0x0320) #define MCF5272_PLI_P1DRR (0x0321) #define MCF5272_PLI_P2DRR (0x0322) #define MCF5272_PLI_P3DRR (0x0323) #define MCF5272_PLI_P0B1TR (0x0328) #define MCF5272_PLI_P1B1TR (0x032C) #define MCF5272_PLI_P2B1TR (0x0330) #define MCF5272_PLI_P3B1TR (0x0334) #define MCF5272_PLI_P0B2TR (0x0338) #define MCF5272_PLI_P1B2TR (0x033C) #define MCF5272_PLI_P2B2TR (0x0340) #define MCF5272_PLI_P3B2TR (0x0344) #define MCF5272_PLI_P0DTR (0x0348) #define MCF5272_PLI_P1DTR (0x0349) #define MCF5272_PLI_P2DTR (0x034A) #define MCF5272_PLI_P3DTR (0x034B) #define MCF5272_PLI_P0CR (0x0350) #define MCF5272_PLI_P1CR (0x0352) #define MCF5272_PLI_P2CR (0x0354) #define MCF5272_PLI_P3CR (0x0356) #define MCF5272_PLI_P0ICR (0x0358) #define MCF5272_PLI_P1ICR (0x035A) #define MCF5272_PLI_P2ICR (0x035C) #define MCF5272_PLI_P3ICR (0x035E) #define MCF5272_PLI_P0GMR (0x0360) #define MCF5272_PLI_P1GMR (0x0362) #define MCF5272_PLI_P2GMR (0x0364) #define MCF5272_PLI_P3GMR (0x0366) #define MCF5272_PLI_P0GMT (0x0368) #define MCF5272_PLI_P1GMT (0x036A) #define MCF5272_PLI_P2GMT (0x036C) #define MCF5272_PLI_P3GMT (0x036E) #define MCF5272_PLI_PGMTS (0x0371) #define MCF5272_PLI_PGMTA (0x0372) #define MCF5272_PLI_P0GCIR (0x0374) #define MCF5272_PLI_P1GCIR (0x0375) #define MCF5272_PLI_P2GCIR (0x0376) #define MCF5272_PLI_P3GCIR (0x0377) #define MCF5272_PLI_P0GCIT (0x0378) #define MCF5272_PLI_P1GCIT (0x0379) #define MCF5272_PLI_P2GCIT (0x037A) #define MCF5272_PLI_P3GCIT (0x037E) #define MCF5272_PLI_PGCITSR (0x037F) #define MCF5272_PLI_PDSUSR (0x0382) #define MCF5272_PLI_PDCSR (0x0383) #define MCF5272_PLI_P0PSR (0x0384) #define MCF5272_PLI_P1PSR (0x0386) #define MCF5272_PLI_P2PSR (0x0388) #define MCF5272_PLI_P3PSR (0x038A) #define MCF5272_PLI_PASR (0x038C) #define MCF5272_PLI_PLCR (0x038F) #define MCF5272_PLI_PDRQR (0x0392) #define MCF5272_PLI_P0SDR (0x0394) #define MCF5272_PLI_P1SDR (0x0396) #define MCF5272_PLI_P2SDR (0x0398) #define MCF5272_PLI_P3SDR (0x039A) #define MCF5272_PLI_PCKSELR (0x039E) /* Read access macros for general use */ #define MCF5272_RD_PLI_P0B1RR(IMMP) Mcf5272_iord(IMMP,MCF5272_PLI_P0B1RR,32) #define MCF5272_RD_PLI_P1B1RR(IMMP) Mcf5272_iord(IMMP,MCF5272_PLI_P1B1RR,32) #define MCF5272_RD_PLI_P2B1RR(IMMP) Mcf5272_iord(IMMP,MCF5272_PLI_P2B1RR,32) #define MCF5272_RD_PLI_P3B1RR(IMMP) Mcf5272_iord(IMMP,MCF5272_PLI_P3B1RR,32) #define MCF5272_RD_PLI_P0B2RR(IMMP) Mcf5272_iord(IMMP,MCF5272_PLI_P0B2RR,32) #define MCF5272_RD_PLI_P1B2RR(IMMP) Mcf5272_iord(IMMP,MCF5272_PLI_P1B2RR,32) #define MCF5272_RD_PLI_P2B2RR(IMMP) Mcf5272_iord(IMMP,MCF5272_PLI_P2B2RR,32) #define MCF5272_RD_PLI_P3B2RR(IMMP) Mcf5272_iord(IMMP,MCF5272_PLI_P3B2RR,32) #define MCF5272_RD_PLI_P0DRR(IMMP) Mcf5272_iord(IMMP,MCF5272_PLI_P0DRR,8) #define MCF5272_RD_PLI_P1DRR(IMMP) Mcf5272_iord(IMMP,MCF5272_PLI_P1DRR,8) #define MCF5272_RD_PLI_P2DRR(IMMP) Mcf5272_iord(IMMP,MCF5272_PLI_P2DRR,8) #define MCF5272_RD_PLI_P3DRR(IMMP) Mcf5272_iord(IMMP,MCF5272_PLI_P3DRR,8) #define MCF5272_RD_PLI_P0B1TR(IMMP) Mcf5272_iord(IMMP,MCF5272_PLI_P0B1TR,32) #define MCF5272_RD_PLI_P1B1TR(IMMP) Mcf5272_iord(IMMP,MCF5272_PLI_P1B1TR,32) #define MCF5272_RD_PLI_P2B1TR(IMMP) Mcf5272_iord(IMMP,MCF5272_PLI_P2B1TR,32) #define MCF5272_RD_PLI_P3B1TR(IMMP) Mcf5272_iord(IMMP,MCF5272_PLI_P3B1TR,32) #define MCF5272_RD_PLI_P0B2TR(IMMP) Mcf5272_iord(IMMP,MCF5272_PLI_P0B2TR,32) #define MCF5272_RD_PLI_P1B2TR(IMMP) Mcf5272_iord(IMMP,MCF5272_PLI_P1B2TR,32) #define MCF5272_RD_PLI_P2B2TR(IMMP) Mcf5272_iord(IMMP,MCF5272_PLI_P2B2TR,32) #define MCF5272_RD_PLI_P3B2TR(IMMP) Mcf5272_iord(IMMP,MCF5272_PLI_P3B2TR,32) #define MCF5272_RD_PLI_P0DTR(IMMP) Mcf5272_iord(IMMP,MCF5272_PLI_P0DTR,8) #define MCF5272_RD_PLI_P1DTR(IMMP) Mcf5272_iord(IMMP,MCF5272_PLI_P1DTR,8) #define MCF5272_RD_PLI_P2DTR(IMMP) Mcf5272_iord(IMMP,MCF5272_PLI_P2DTR,8) #define MCF5272_RD_PLI_P3DTR(IMMP) Mcf5272_iord(IMMP,MCF5272_PLI_P3DTR,8) #define MCF5272_RD_PLI_P0CR(IMMP) Mcf5272_iord(IMMP,MCF5272_PLI_P0CR,16) #define MCF5272_RD_PLI_P1CR(IMMP) Mcf5272_iord(IMMP,MCF5272_PLI_P1CR,16) #define MCF5272_RD_PLI_P2CR(IMMP) Mcf5272_iord(IMMP,MCF5272_PLI_P2CR,16) #define MCF5272_RD_PLI_P3CR(IMMP) Mcf5272_iord(IMMP,MCF5272_PLI_P3CR,16) #define MCF5272_RD_PLI_P0ICR(IMMP) Mcf5272_iord(IMMP,MCF5272_PLI_P0ICR,16) #define MCF5272_RD_PLI_P1ICR(IMMP) Mcf5272_iord(IMMP,MCF5272_PLI_P1ICR,16) #define MCF5272_RD_PLI_P2ICR(IMMP) Mcf5272_iord(IMMP,MCF5272_PLI_P2ICR,16) #define MCF5272_RD_PLI_P3ICR(IMMP) Mcf5272_iord(IMMP,MCF5272_PLI_P3ICR,16) #define MCF5272_RD_PLI_P0GMR(IMMP) Mcf5272_iord(IMMP,MCF5272_PLI_P0GMR,16) #define MCF5272_RD_PLI_P1GMR(IMMP) Mcf5272_iord(IMMP,MCF5272_PLI_P1GMR,16) #define MCF5272_RD_PLI_P2GMR(IMMP) Mcf5272_iord(IMMP,MCF5272_PLI_P2GMR,16) #define MCF5272_RD_PLI_P3GMR(IMMP) Mcf5272_iord(IMMP,MCF5272_PLI_P3GMR,16) #define MCF5272_RD_PLI_P0GMT(IMMP) Mcf5272_iord(IMMP,MCF5272_PLI_P0GMT,16) #define MCF5272_RD_PLI_P1GMT(IMMP) Mcf5272_iord(IMMP,MCF5272_PLI_P1GMT,16) #define MCF5272_RD_PLI_P2GMT(IMMP) Mcf5272_iord(IMMP,MCF5272_PLI_P2GMT,16) #define MCF5272_RD_PLI_P3GMT(IMMP) Mcf5272_iord(IMMP,MCF5272_PLI_P3GMT,16) #define MCF5272_RD_PLI_PGMTS(IMMP) Mcf5272_iord(IMMP,MCF5272_PLI_PGMTS,8) #define MCF5272_RD_PLI_PGMTA(IMMP) Mcf5272_iord(IMMP,MCF5272_PLI_PGMTA,8) #define MCF5272_RD_PLI_P0GCIR(IMMP) Mcf5272_iord(IMMP,MCF5272_PLI_P0GCIR,8) #define MCF5272_RD_PLI_P1GCIR(IMMP) Mcf5272_iord(IMMP,MCF5272_PLI_P1GCIR,8) #define MCF5272_RD_PLI_P2GCIR(IMMP) Mcf5272_iord(IMMP,MCF5272_PLI_P2GCIR,8) #define MCF5272_RD_PLI_P3GCIR(IMMP) Mcf5272_iord(IMMP,MCF5272_PLI_P3GCIR,8) #define MCF5272_RD_PLI_P0GCIT(IMMP) Mcf5272_iord(IMMP,MCF5272_PLI_P0GCIT,8) #define MCF5272_RD_PLI_P1GCIT(IMMP) Mcf5272_iord(IMMP,MCF5272_PLI_P1GCIT,8) #define MCF5272_RD_PLI_P2GCIT(IMMP) Mcf5272_iord(IMMP,MCF5272_PLI_P2GCIT,8) #define MCF5272_RD_PLI_P3GCIT(IMMP) Mcf5272_iord(IMMP,MCF5272_PLI_P3GCIT,8) #define MCF5272_RD_PLI_PGCITSR(IMMP) Mcf5272_iord(IMMP,MCF5272_PLI_PGCITSR,8) #define MCF5272_RD_PLI_PDSUSR(IMMP) Mcf5272_iord(IMMP,MCF5272_PLI_PDSUSR,8) #define MCF5272_RD_PLI_PDCSR(IMMP) Mcf5272_iord(IMMP,MCF5272_PLI_PDCSR,8) #define MCF5272_RD_PLI_P0PSR(IMMP) Mcf5272_iord(IMMP,MCF5272_PLI_P0PSR,16) #define MCF5272_RD_PLI_P1PSR(IMMP) Mcf5272_iord(IMMP,MCF5272_PLI_P1PSR,16) #define MCF5272_RD_PLI_P2PSR(IMMP) Mcf5272_iord(IMMP,MCF5272_PLI_P2PSR,16) #define MCF5272_RD_PLI_P3PSR(IMMP) Mcf5272_iord(IMMP,MCF5272_PLI_P3PSR,16) #define MCF5272_RD_PLI_PASR(IMMP) Mcf5272_iord(IMMP,MCF5272_PLI_PASR,16) #define MCF5272_RD_PLI_PLCR(IMMP) Mcf5272_iord(IMMP,MCF5272_PLI_PLCR,8) #define MCF5272_RD_PLI_PDRQR(IMMP) Mcf5272_iord(IMMP,MCF5272_PLI_PDRQR,16) #define MCF5272_RD_PLI_P0SDR(IMMP) Mcf5272_iord(IMMP,MCF5272_PLI_P0SDR,16) #define MCF5272_RD_PLI_P1SDR(IMMP) Mcf5272_iord(IMMP,MCF5272_PLI_P1SDR,16) #define MCF5272_RD_PLI_P2SDR(IMMP) Mcf5272_iord(IMMP,MCF5272_PLI_P2SDR,16) #define MCF5272_RD_PLI_P3SDR(IMMP) Mcf5272_iord(IMMP,MCF5272_PLI_P3SDR,16) #define MCF5272_RD_PLI_PCKSELR(IMMP) Mcf5272_iord(IMMP,MCF5272_PLI_PCKSELR,16) /* Write access macros for general use */ #define MCF5272_WR_PLI_P0B1TR(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_PLI_P0B1TR,32,DATA) #define MCF5272_WR_PLI_P1B1TR(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_PLI_P1B1TR,32,DATA) #define MCF5272_WR_PLI_P2B1TR(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_PLI_P2B1TR,32,DATA) #define MCF5272_WR_PLI_P3B1TR(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_PLI_P3B1TR,32,DATA) #define MCF5272_WR_PLI_P0B2TR(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_PLI_P0B2TR,32,DATA) #define MCF5272_WR_PLI_P1B2TR(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_PLI_P1B2TR,32,DATA) #define MCF5272_WR_PLI_P2B2TR(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_PLI_P2B2TR,32,DATA) #define MCF5272_WR_PLI_P3B2TR(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_PLI_P3B2TR,32,DATA) #define MCF5272_WR_PLI_P0DTR(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_PLI_P0DTR,8,DATA) #define MCF5272_WR_PLI_P1DTR(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_PLI_P1DTR,8,DATA) #define MCF5272_WR_PLI_P2DTR(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_PLI_P2DTR,8,DATA) #define MCF5272_WR_PLI_P3DTR(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_PLI_P3DTR,8,DATA) #define MCF5272_WR_PLI_P0CR(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_PLI_P0CR,16,DATA) #define MCF5272_WR_PLI_P1CR(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_PLI_P1CR,16,DATA) #define MCF5272_WR_PLI_P2CR(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_PLI_P2CR,16,DATA) #define MCF5272_WR_PLI_P3CR(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_PLI_P3CR,16,DATA) #define MCF5272_WR_PLI_P0ICR(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_PLI_P0ICR,16,DATA) #define MCF5272_WR_PLI_P1ICR(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_PLI_P1ICR,16,DATA) #define MCF5272_WR_PLI_P2ICR(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_PLI_P2ICR,16,DATA) #define MCF5272_WR_PLI_P3ICR(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_PLI_P3ICR,16,DATA) #define MCF5272_WR_PLI_P0GMT(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_PLI_P0GMR,16,DATA) #define MCF5272_WR_PLI_P1GMT(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_PLI_P1GMT,16,DATA) #define MCF5272_WR_PLI_P2GMT(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_PLI_P2GMT,16,DATA) #define MCF5272_WR_PLI_P3GMT(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_PLI_P3GMT,16,DATA) #define MCF5272_WR_PLI_PGMTA(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_PLI_PGMTA,8,DATA) #define MCF5272_WR_PLI_P0GCIT(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_PLI_P0GCIT,8,DATA) #define MCF5272_WR_PLI_P1GCIT(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_PLI_P1GCIT,8,DATA) #define MCF5272_WR_PLI_P2GCIT(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_PLI_P2GCIT,8,DATA) #define MCF5272_WR_PLI_P3GCIT(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_PLI_P3GCIT,8,DATA) #define MCF5272_WR_PLI_PLCR(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_PLI_PLCR,8,DATA) #define MCF5272_WR_PLI_PDRQR(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_PLI_PDRQR,16,DATA) #define MCF5272_WR_PLI_P0SDR(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_PLI_P0SDR,16,DATA) #define MCF5272_WR_PLI_P1SDR(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_PLI_P1SDR,16,DATA) #define MCF5272_WR_PLI_P2SDR(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_PLI_P2SDR,16,DATA) #define MCF5272_WR_PLI_P3SDR(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_PLI_P3SDR,16,DATA) #define MCF5272_WR_PLI_PCKSELR(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_PLI_PCKSELR,16,DATA) /********************************************************************** * * Fast Ethernet Controller Module Register Descriptions * ***********************************************************************/ /* Offsets of the registers from the MBAR */ #define MCF5272_FEC_ECR (0x0840) #define MCF5272_FEC_EIR (0x0844) #define MCF5272_FEC_IMR (0x0848) #define MCF5272_FEC_IVSR (0x084C) #define MCF5272_FEC_RDAR (0x0850) #define MCF5272_FEC_TDAR (0x0854) #define MCF5272_FEC_MMFR (0x0880) #define MCF5272_FEC_MSCR (0x0884) #define MCF5272_FEC_FRBR (0x08CC) #define MCF5272_FEC_FRSR (0x08D0) #define MCF5272_FEC_TFWR (0x08E4) #define MCF5272_FEC_FTSR (0x08EC) #define MCF5272_FEC_RCR (0x0944) #define MCF5272_FEC_MFLR (0x0948) #define MCF5272_FEC_TCR (0x0984) #define MCF5272_FEC_MALR (0x0C00) #define MCF5272_FEC_MAUR (0x0C04) #define MCF5272_FEC_HTUR (0x0C08) #define MCF5272_FEC_HTLR (0x0C0C) #define MCF5272_FEC_ERDSR (0x0C10) #define MCF5272_FEC_ETDSR (0x0C14) #define MCF5272_FEC_EMRBR (0x0C18) #define MCF5272_FEC_EFIFO (0x0C40) /* 0x0C40 - 0x0DFF */ /* Read access macros for general use */ #define MCF5272_RD_FEC_ECR(IMMP) \ Mcf5272_iord(IMMP,MCF5272_FEC_ECR,32) #define MCF5272_RD_FEC_EIR(IMMP) \ Mcf5272_iord(IMMP,MCF5272_FEC_EIR,32) #define MCF5272_RD_FEC_IMR(IMMP) \ Mcf5272_iord(IMMP,MCF5272_FEC_IMR,32) #define MCF5272_RD_FEC_IVSR(IMMP) \ Mcf5272_iord(IMMP,MCF5272_FEC_IVSR,32) #define MCF5272_RD_FEC_RDAR(IMMP) \ Mcf5272_iord(IMMP,MCF5272_FEC_RDAR,32) #define MCF5272_RD_FEC_TDAR(IMMP) \ Mcf5272_iord(IMMP,MCF5272_FEC_TDAR,32) #define MCF5272_RD_FEC_MMFR(IMMP) \ Mcf5272_iord(IMMP,MCF5272_FEC_MMFR,32) #define MCF5272_RD_FEC_MSCR(IMMP) \ Mcf5272_iord(IMMP,MCF5272_FEC_MSCR,32) #define MCF5272_RD_FEC_FRBR(IMMP) \ Mcf5272_iord(IMMP,MCF5272_FEC_FRBR,32) #define MCF5272_RD_FEC_FRSR(IMMP) \ Mcf5272_iord(IMMP,MCF5272_FEC_FRSR,32) #define MCF5272_RD_FEC_TFWR(IMMP) \ Mcf5272_iord(IMMP,MCF5272_FEC_TFWR,32) #define MCF5272_RD_FEC_FTSR(IMMP) \ Mcf5272_iord(IMMP,MCF5272_FEC_FTSR,32) #define MCF5272_RD_FEC_RCR(IMMP) \ Mcf5272_iord(IMMP,MCF5272_FEC_RCR,32) #define MCF5272_RD_FEC_MFLR(IMMP) \ Mcf5272_iord(IMMP,MCF5272_FEC_MFLR,32) #define MCF5272_RD_FEC_TCR(IMMP) \ Mcf5272_iord(IMMP,MCF5272_FEC_TCR,32) #define MCF5272_RD_FEC_MALR(IMMP) \ Mcf5272_iord(IMMP,MCF5272_FEC_MALR,32) #define MCF5272_RD_FEC_MAUR(IMMP) \ Mcf5272_iord(IMMP,MCF5272_FEC_MAUR,32) #define MCF5272_RD_FEC_HTUR(IMMP) \ Mcf5272_iord(IMMP,MCF5272_FEC_HTUR,32) #define MCF5272_RD_FEC_HTLR(IMMP) \ Mcf5272_iord(IMMP,MCF5272_FEC_HTLR,32) #define MCF5272_RD_FEC_ERDSR(IMMP) \ Mcf5272_iord(IMMP,MCF5272_FEC_ERDSR,32) #define MCF5272_RD_FEC_ETDSR(IMMP) \ Mcf5272_iord(IMMP,MCF5272_FEC_ETDSR,32) #define MCF5272_RD_FEC_EMRBR(IMMP) \ Mcf5272_iord(IMMP,MCF5272_FEC_EMRBR,32) /* Write access macros for general use */ #define MCF5272_WR_FEC_ECR(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_FEC_ECR,32,DATA) #define MCF5272_WR_FEC_EIR(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_FEC_EIR,32,DATA) #define MCF5272_WR_FEC_IMR(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_FEC_IMR,32,DATA) #define MCF5272_WR_FEC_RDAR(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_FEC_RDAR,32,DATA) #define MCF5272_WR_FEC_TDAR(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_FEC_TDAR,32,DATA) #define MCF5272_WR_FEC_MMFR(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_FEC_MMFR,32,DATA) #define MCF5272_WR_FEC_MSCR(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_FEC_MSCR,32,DATA) #define MCF5272_WR_FEC_FRSR(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_FEC_FRSR,32,DATA) #define MCF5272_WR_FEC_TFWR(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_FEC_TFWR,32,DATA) #define MCF5272_WR_FEC_FTSR(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_FEC_FTSR,32,DATA) #define MCF5272_WR_FEC_RCR(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_FEC_RCR,32,DATA) #define MCF5272_WR_FEC_MFLR(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_FEC_MFLR,32,DATA) #define MCF5272_WR_FEC_TCR(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_FEC_TCR,32,DATA) #define MCF5272_WR_FEC_MALR(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_FEC_MALR,32,DATA) #define MCF5272_WR_FEC_MAUR(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_FEC_MAUR,32,DATA) #define MCF5272_WR_FEC_HTUR(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_FEC_HTUR,32,DATA) #define MCF5272_WR_FEC_HTLR(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_FEC_HTLR,32,DATA) #define MCF5272_WR_FEC_ERDSR(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_FEC_ERDSR,32,DATA) #define MCF5272_WR_FEC_ETDSR(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_FEC_ETDSR,32,DATA) #define MCF5272_WR_FEC_EMRBR(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_FEC_EMRBR,32,DATA) /* Bit level definitions and macros */ #define MCF5272_FEC_ECR_RESET (0x00000001) #define MCF5272_FEC_ECR_ETHER_EN (0x00000002) #define MCF5272_FEC_EIR_GRA (0x10000000) #define MCF5272_FEC_EIR_RXF (0x02000000) #define MCF5272_FEC_EIR_TXF (0x08000000) #define MCF5272_FEC_IMR_HBEEN (0x80000000) #define MCF5272_FEC_IMR_BREN (0x40000000) #define MCF5272_FEC_IMR_BTEN (0x20000000) #define MCF5272_FEC_IMR_GRAEN (0x10000000) #define MCF5272_FEC_IMR_TXFEN (0x08000000) #define MCF5272_FEC_IMR_TXBEN (0x04000000) #define MCF5272_FEC_IMR_RXFEN (0x02000000) #define MCF5272_FEC_IMR_RXBEN (0x01000000) #define MCF5272_FEC_IMR_MIIEN (0x00800000) #define MCF5272_FEC_IMR_EBERREN (0x00400000) #define MCF5272_FEC_RCR_PROM (0x00000008) #define MCF5272_FEC_RCR_MII_MODE (0x00000004) #define MCF5272_FEC_RCR_DRT (0x00000002) #define MCF5272_FEC_RCR_LOOP (0x00000001) #define MCF5272_FEC_TCR_GTS (0x00000001) #define MCF5272_FEC_TCR_HBC (0x00000002) #define MCF5272_FEC_TCR_FDEN (0x00000004) #define MCF5272_MMFR_MODE (0x00004000) #define MCF5272_MMFR_DUPLEX (0x00000200) #define MCF5272_MMFR_LOOP (0x00004000) #define MCF5272_MMFR_NEGOTIATE (0x00001000) #define MCF5272_MMFR_100 (0x00002000) /* * Bit level Buffer Descriptor definitions */ #define MCF5272_FEC_TX_BD_R 0x8000 #define MCF5272_FEC_TX_BD_INUSE 0x4000 #define MCF5272_FEC_TX_BD_TO1 0x4000 #define MCF5272_FEC_TX_BD_W 0x2000 #define MCF5272_FEC_TX_BD_TO2 0x1000 #define MCF5272_FEC_TX_BD_L 0x0800 #define MCF5272_FEC_TX_BD_TC 0x0400 #define MCF5272_FEC_TX_BD_DEF 0x0200 #define MCF5272_FEC_TX_BD_HB 0x0100 #define MCF5272_FEC_TX_BD_LC 0x0080 #define MCF5272_FEC_TX_BD_RL 0x0040 #define MCF5272_FEC_TX_BD_UN 0x0002 #define MCF5272_FEC_TX_BD_CSL 0x0001 #define MCF5272_FEC_RX_BD_E 0x8000 #define MCF5272_FEC_RX_BD_INUSE 0x4000 #define MCF5272_FEC_RX_BD_R01 0x4000 #define MCF5272_FEC_RX_BD_W 0x2000 #define MCF5272_FEC_RX_BD_R02 0x1000 #define MCF5272_FEC_RX_BD_L 0x0800 #define MCF5272_FEC_RX_BD_M 0x0100 #define MCF5272_FEC_RX_BD_BC 0x0080 #define MCF5272_FEC_RX_BD_MC 0x0040 #define MCF5272_FEC_RX_BD_LG 0x0020 #define MCF5272_FEC_RX_BD_NO 0x0010 #define MCF5272_FEC_RX_BD_SH 0x0008 #define MCF5272_FEC_RX_BD_CR 0x0004 #define MCF5272_FEC_RX_BD_OV 0x0002 #define MCF5272_FEC_RX_BD_TR 0x0001 /********************************************************************** * * USB_ Module Register Description * ***********************************************************************/ /* Offsets of the registers from the MBAR */ #define MCF5272_USB_FNR (0x1002) #define MCF5272_USB_FNMR (0x1006) #define MCF5272_USB_RFMR (0x100A) #define MCF5272_USB_RFMMR (0x100E) #define MCF5272_USB_FAR (0x1013) #define MCF5272_USB_ASR (0x1014) #define MCF5272_USB_DRR1 (0x1018) #define MCF5272_USB_DRR2 (0x101C) #define MCF5272_USB_SPECR (0x1022) #define MCF5272_USB_EP0SR (0x1026) #define MCF5272_USB_IEP0CFG (0x1028) #define MCF5272_USB_OEP0CFG (0x102C) #define MCF5272_USB_EP1CFG (0x1030) #define MCF5272_USB_EP2CFG (0x1034) #define MCF5272_USB_EP3CFG (0x1038) #define MCF5272_USB_EP4CFG (0x103C) #define MCF5272_USB_EP5CFG (0x1040) #define MCF5272_USB_EP6CFG (0x1044) #define MCF5272_USB_EP7CFG (0x1048) #define MCF5272_USB_EP0CTL (0x104C) #define MCF5272_USB_EP1CTL (0x1052) #define MCF5272_USB_EP2CTL (0x1056) #define MCF5272_USB_EP3CTL (0x105A) #define MCF5272_USB_EP4CTL (0x105E) #define MCF5272_USB_EP5CTL (0x1062) #define MCF5272_USB_EP6CTL (0x1066) #define MCF5272_USB_EP7CTL (0x106A) #define MCF5272_USB_EP0ISR (0x106C) #define MCF5272_USB_EP1ISR (0x1072) #define MCF5272_USB_EP2ISR (0x1076) #define MCF5272_USB_EP3ISR (0x107A) #define MCF5272_USB_EP4ISR (0x107E) #define MCF5272_USB_EP5ISR (0x1082) #define MCF5272_USB_EP6ISR (0x1086) #define MCF5272_USB_EP7ISR (0x108A) #define MCF5272_USB_EP0IMR (0x108C) #define MCF5272_USB_EP1IMR (0x1092) #define MCF5272_USB_EP2IMR (0x1096) #define MCF5272_USB_EP3IMR (0x109A) #define MCF5272_USB_EP4IMR (0x109E) #define MCF5272_USB_EP5IMR (0x10A2) #define MCF5272_USB_EP6IMR (0x10A6) #define MCF5272_USB_EP7IMR (0x10AA) #define MCF5272_USB_EP0DR (0x10AC) #define MCF5272_USB_EP1DR (0x10B0) #define MCF5272_USB_EP2DR (0x10B4) #define MCF5272_USB_EP3DR (0x10B8) #define MCF5272_USB_EP4DR (0x10BC) #define MCF5272_USB_EP5DR (0x10C0) #define MCF5272_USB_EP6DR (0x10C4) #define MCF5272_USB_EP7DR (0x10C8) #define MCF5272_USB_EP0DPR (0x10CE) #define MCF5272_USB_EP1DPR (0x10D2) #define MCF5272_USB_EP2DPR (0x10D6) #define MCF5272_USB_EP3DPR (0x10DA) #define MCF5272_USB_EP4DPR (0x10DE) #define MCF5272_USB_EP5DPR (0x10E2) #define MCF5272_USB_EP6DPR (0x10E6) #define MCF5272_USB_EP7DPR (0x10EA) #define MCF5272_USB_CFG_RAM (0x1400) /* 0x1400 - 0x17FF */ /* Read access macros for general use */ #define MCF5272_RD_USB_FNR(IMMP) \ Mcf5272_iord(IMMP,MCF5272_USB_FNR,16) #define MCF5272_RD_USB_FNMR(IMMP) \ Mcf5272_iord(IMMP,MCF5272_USB_FNMR,16) #define MCF5272_RD_USB_RFMR(IMMP) \ Mcf5272_iord(IMMP,MCF5272_USB_RFMR,16) #define MCF5272_RD_USB_RFMMR(IMMP) \ Mcf5272_iord(IMMP,MCF5272_USB_RFMMR,16) #define MCF5272_RD_USB_FAR(IMMP) \ Mcf5272_iord(IMMP,MCF5272_USB_FAR,8) #define MCF5272_RD_USB_ASR(IMMP) \ Mcf5272_iord(IMMP,MCF5272_USB_ASR,32) #define MCF5272_RD_USB_DRR1(IMMP) \ Mcf5272_iord(IMMP,MCF5272_USB_DRR1,32) #define MCF5272_RD_USB_DRR2(IMMP) \ Mcf5272_iord(IMMP,MCF5272_USB_DRR2,32) #define MCF5272_RD_USB_SPECR(IMMP) \ Mcf5272_iord(IMMP,MCF5272_USB_SPECR,16) #define MCF5272_RD_USB_EP0SR(IMMP) \ Mcf5272_iord(IMMP,MCF5272_USB_EP0SR,16) #define MCF5272_RD_USB_IEP0CFG(IMMP) \ Mcf5272_iord(IMMP,MCF5272_USB_IEP0CFG,32) #define MCF5272_RD_USB_OEP0CFG(IMMP) \ Mcf5272_iord(IMMP,MCF5272_USB_OEP0CFG,32) #define MCF5272_RD_USB_EPCFG(IMMP,EPN) \ Mcf5272_iord(IMMP,MCF5272_USB_EP1CFG + 4*(EPN-1),32) #define MCF5272_RD_USB_EP1CFG(IMMP) \ Mcf5272_iord(IMMP,MCF5272_USB_EP1CFG,32) #define MCF5272_RD_USB_EP2CFG(IMMP) \ Mcf5272_iord(IMMP,MCF5272_USB_EP2CFG,32) #define MCF5272_RD_USB_EP3CFG(IMMP) \ Mcf5272_iord(IMMP,MCF5272_USB_EP3CFG,32) #define MCF5272_RD_USB_EP4CFG(IMMP) \ Mcf5272_iord(IMMP,MCF5272_USB_EP4CFG,32) #define MCF5272_RD_USB_EP5CFG(IMMP) \ Mcf5272_iord(IMMP,MCF5272_USB_EP5CFG,32) #define MCF5272_RD_USB_EP6CFG(IMMP) \ Mcf5272_iord(IMMP,MCF5272_USB_EP6CFG,32) #define MCF5272_RD_USB_EP7CFG(IMMP) \ Mcf5272_iord(IMMP,MCF5272_USB_EP7CFG,32) #define MCF5272_RD_USB_EPCTL(IMMP,EPN) \ Mcf5272_iord(IMMP,MCF5272_USB_EP0CTL + 4*EPN,32) #define MCF5272_RD_USB_EP0CTL(IMMP) \ Mcf5272_iord(IMMP,MCF5272_USB_EP0CTL,32) #define MCF5272_RD_USB_EP1CTL(IMMP) \ Mcf5272_iord(IMMP,MCF5272_USB_EP1CTL,16) #define MCF5272_RD_USB_EP2CTL(IMMP) \ Mcf5272_iord(IMMP,MCF5272_USB_EP2CTL,16) #define MCF5272_RD_USB_EP3CTL(IMMP) \ Mcf5272_iord(IMMP,MCF5272_USB_EP3CTL,16) #define MCF5272_RD_USB_EP4CTL(IMMP) \ Mcf5272_iord(IMMP,MCF5272_USB_EP4CTL,16) #define MCF5272_RD_USB_EP5CTL(IMMP) \ Mcf5272_iord(IMMP,MCF5272_USB_EP5CTL,16) #define MCF5272_RD_USB_EP6CTL(IMMP) \ Mcf5272_iord(IMMP,MCF5272_USB_EP6CTL,16) #define MCF5272_RD_USB_EP7CTL(IMMP) \ Mcf5272_iord(IMMP,MCF5272_USB_EP7CTL,16) #define MCF5272_RD_USB_EPISR(IMMP,EPN) \ Mcf5272_iord(IMMP,MCF5272_USB_EP0ISR + 4*EPN,32) #define MCF5272_RD_USB_EP0ISR(IMMP) \ Mcf5272_iord(IMMP,MCF5272_USB_EP0ISR,32) #define MCF5272_RD_USB_EP1ISR(IMMP) \ Mcf5272_iord(IMMP,MCF5272_USB_EP1ISR,16) #define MCF5272_RD_USB_EP2ISR(IMMP) \ Mcf5272_iord(IMMP,MCF5272_USB_EP2ISR,16) #define MCF5272_RD_USB_EP3ISR(IMMP) \ Mcf5272_iord(IMMP,MCF5272_USB_EP3ISR,16) #define MCF5272_RD_USB_EP4ISR(IMMP) \ Mcf5272_iord(IMMP,MCF5272_USB_EP4ISR,16) #define MCF5272_RD_USB_EP5ISR(IMMP) \ Mcf5272_iord(IMMP,MCF5272_USB_EP5ISR,16) #define MCF5272_RD_USB_EP6ISR(IMMP) \ Mcf5272_iord(IMMP,MCF5272_USB_EP6ISR,16) #define MCF5272_RD_USB_EP7ISR(IMMP) \ Mcf5272_iord(IMMP,MCF5272_USB_EP7ISR,16) #define MCF5272_RD_USB_EPIMR(IMMP,EPN) \ Mcf5272_iord(IMMP,MCF5272_USB_EP0IMR + 4*EPN,32) #define MCF5272_RD_USB_EP0IMR(IMMP) \ Mcf5272_iord(IMMP,MCF5272_USB_EP0IMR,32) #define MCF5272_RD_USB_EP1IMR(IMMP) \ Mcf5272_iord(IMMP,MCF5272_USB_EP1IMR,16) #define MCF5272_RD_USB_EP2IMR(IMMP) \ Mcf5272_iord(IMMP,MCF5272_USB_EP2IMR,16) #define MCF5272_RD_USB_EP3IMR(IMMP) \ Mcf5272_iord(IMMP,MCF5272_USB_EP3IMR,16) #define MCF5272_RD_USB_EP4IMR(IMMP) \ Mcf5272_iord(IMMP,MCF5272_USB_EP4IMR,16) #define MCF5272_RD_USB_EP5IMR(IMMP) \ Mcf5272_iord(IMMP,MCF5272_USB_EP5IMR,16) #define MCF5272_RD_USB_EP6IMR(IMMP) \ Mcf5272_iord(IMMP,MCF5272_USB_EP6IMR,16) #define MCF5272_RD_USB_EP7IMR(IMMP) \ Mcf5272_iord(IMMP,MCF5272_USB_EP7IMR,16) #define MCF5272_RD_USB_EPDR(IMMP,EPN,SIZE) \ Mcf5272_iord(IMMP,MCF5272_USB_EP0DR + 4*EPN,SIZE) #define MCF5272_RD_USB_EP0DR(IMMP,SIZE) \ Mcf5272_iord(IMMP,MCF5272_USB_EP0DR,SIZE) #define MCF5272_RD_USB_EP1DR(IMMP,SIZE) \ Mcf5272_iord(IMMP,MCF5272_USB_EP1DR,SIZE) #define MCF5272_RD_USB_EP2DR(IMMP,SIZE) \ Mcf5272_iord(IMMP,MCF5272_USB_EP2DR,SIZE) #define MCF5272_RD_USB_EP3DR(IMMP,SIZE) \ Mcf5272_iord(IMMP,MCF5272_USB_EP3DR,SIZE) #define MCF5272_RD_USB_EP4DR(IMMP,SIZE) \ Mcf5272_iord(IMMP,MCF5272_USB_EP4DR,SIZE) #define MCF5272_RD_USB_EP5DR(IMMP,SIZE) \ Mcf5272_iord(IMMP,MCF5272_USB_EP5DR,SIZE) #define MCF5272_RD_USB_EP6DR(IMMP,SIZE) \ Mcf5272_iord(IMMP,MCF5272_USB_EP6DR,SIZE) #define MCF5272_RD_USB_EP7DR(IMMP,SIZE) \ Mcf5272_iord(IMMP,MCF5272_USB_EP7DR,SIZE) #define MCF5272_RD_USB_EPDPR(IMMP,EPN) \ Mcf5272_iord(IMMP,MCF5272_USB_EP0DPR + 4*EPN,16) #define MCF5272_RD_USB_EP0DPR(IMMP) \ Mcf5272_iord(IMMP,MCF5272_USB_EP0DPR,16) #define MCF5272_RD_USB_EP1DPR(IMMP) \ Mcf5272_iord(IMMP,MCF5272_USB_EP1DPR,16) #define MCF5272_RD_USB_EP2DPR(IMMP) \ Mcf5272_iord(IMMP,MCF5272_USB_EP2DPR,16) #define MCF5272_RD_USB_EP3DPR(IMMP) \ Mcf5272_iord(IMMP,MCF5272_USB_EP3DPR,16) #define MCF5272_RD_USB_EP4DPR(IMMP) \ Mcf5272_iord(IMMP,MCF5272_USB_EP4DPR,16) #define MCF5272_RD_USB_EP5DPR(IMMP) \ Mcf5272_iord(IMMP,MCF5272_USB_EP5DPR,16) #define MCF5272_RD_USB_EP6DPR(IMMP) \ Mcf5272_iord(IMMP,MCF5272_USB_EP6DPR,16) #define MCF5272_RD_USB_EP7DPR(IMMP) \ Mcf5272_iord(IMMP,MCF5272_USB_EP7DPR,16) /* Write access macros for general use */ #define MCF5272_WR_USB_FNR(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_USB_FNR,16,DATA) #define MCF5272_WR_USB_FNMR(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_USB_FNMR,16,DATA) #define MCF5272_WR_USB_RFMMR(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_USB_RFMMR,16,DATA) #define MCF5272_WR_USB_EP0SR(IMMP,DATA)\ Mcf5272_iowr(IMMP,MCF5272_USB_EP0SR,32,DATA) #define MCF5272_WR_USB_IEP0CFG(IMMP,DATA)\ Mcf5272_iowr(IMMP,MCF5272_USB_IEP0CFG,32,DATA) #define MCF5272_WR_USB_OEP0CFG(IMMP,DATA)\ Mcf5272_iowr(IMMP,MCF5272_USB_OEP0CFG,32,DATA) #define MCF5272_WR_USB_EPCFG(IMMP,EPN,DATA) \ Mcf5272_iowr(IMMP,MCF5272_USB_EP1CFG + 4*(EPN-1),32,DATA) #define MCF5272_WR_USB_EP1CFG(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_USB_EP1CFG,32,DATA) #define MCF5272_WR_USB_EP2CFG(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_USB_EP2CFG,32,DATA) #define MCF5272_WR_USB_EP3CFG(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_USB_EP3CFG,32,DATA) #define MCF5272_WR_USB_EP4CFG(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_USB_EP4CFG,32,DATA) #define MCF5272_WR_USB_EP5CFG(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_USB_EP5CFG,32,DATA) #define MCF5272_WR_USB_EP6CFG(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_USB_EP6CFG,32,DATA) #define MCF5272_WR_USB_EP7CFG(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_USB_EP7CFG,32,DATA) #define MCF5272_WR_USB_EPCTL(IMMP,EPN,DATA) \ Mcf5272_iowr(IMMP,MCF5272_USB_EP0CTL + 4*EPN,32,DATA) #define MCF5272_WR_USB_EP0CTL(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_USB_EP0CTL,32,DATA) #define MCF5272_WR_USB_EP1CTL(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_USB_EP1CTL,16,DATA) #define MCF5272_WR_USB_EP2CTL(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_USB_EP2CTL,16,DATA) #define MCF5272_WR_USB_EP3CTL(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_USB_EP3CTL,16,DATA) #define MCF5272_WR_USB_EP4CTL(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_USB_EP4CTL,16,DATA) #define MCF5272_WR_USB_EP5CTL(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_USB_EP5CTL,16,DATA) #define MCF5272_WR_USB_EP6CTL(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_USB_EP6CTL,16,DATA) #define MCF5272_WR_USB_EP7CTL(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_USB_EP7CTL,16,DATA) #define MCF5272_WR_USB_EPISR(IMMP,EPN,DATA) \ Mcf5272_iowr(IMMP,MCF5272_USB_EP0ISR + 4*EPN,32,DATA) #define MCF5272_WR_USB_EP0ISR(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_USB_EP0ISR,32,DATA) #define MCF5272_WR_USB_EP1ISR(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_USB_EP1ISR,16,DATA) #define MCF5272_WR_USB_EP2ISR(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_USB_EP2ISR,16,DATA) #define MCF5272_WR_USB_EP3ISR(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_USB_EP3ISR,16,DATA) #define MCF5272_WR_USB_EP4ISR(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_USB_EP4ISR,16,DATA) #define MCF5272_WR_USB_EP5ISR(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_USB_EP5ISR,16,DATA) #define MCF5272_WR_USB_EP6ISR(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_USB_EP6ISR,16,DATA) #define MCF5272_WR_USB_EP7ISR(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_USB_EP7ISR,16,DATA) #define MCF5272_WR_USB_EPIMR(IMMP,EPN,DATA) \ Mcf5272_iowr(IMMP,MCF5272_USB_EP0IMR + 4*EPN,32,DATA) #define MCF5272_WR_USB_EP0IMR(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_USB_EP0IMR,32,DATA) #define MCF5272_WR_USB_EP1IMR(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_USB_EP1IMR,16,DATA) #define MCF5272_WR_USB_EP2IMR(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_USB_EP2IMR,16,DATA) #define MCF5272_WR_USB_EP3IMR(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_USB_EP3IMR,16,DATA) #define MCF5272_WR_USB_EP4IMR(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_USB_EP4IMR,16,DATA) #define MCF5272_WR_USB_EP5IMR(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_USB_EP5IMR,16,DATA) #define MCF5272_WR_USB_EP6IMR(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_USB_EP6IMR,16,DATA) #define MCF5272_WR_USB_EP7IMR(IMMP,DATA) \ Mcf5272_iowr(IMMP,MCF5272_USB_EP7IMR,16,DATA) #define MCF5272_WR_USB_EPDR(IMMP,EPN,SIZE,DATA) \ Mcf5272_iowr(IMMP,MCF5272_USB_EP0DR + 4*EPN,SIZE,DATA) #define MCF5272_WR_USB_EP0DR(IMMP,SIZE,DATA) \ Mcf5272_iowr(IMMP,MCF5272_USB_EP0DR,SIZE,DATA) #define MCF5272_WR_USB_EP1DR(IMMP,SIZE,DATA) \ Mcf5272_iowr(IMMP,MCF5272_USB_EP1DR,SIZE,DATA) #define MCF5272_WR_USB_EP2DR(IMMP,SIZE,DATA) \ Mcf5272_iowr(IMMP,MCF5272_USB_EP2DR,SIZE,DATA) #define MCF5272_WR_USB_EP3DR(IMMP,SIZE,DATA) \ Mcf5272_iowr(IMMP,MCF5272_USB_EP3DR,SIZE,DATA) #define MCF5272_WR_USB_EP4DR(IMMP,SIZE,DATA) \ Mcf5272_iowr(IMMP,MCF5272_USB_EP4DR,SIZE,DATA) #define MCF5272_WR_USB_EP5DR(IMMP,SIZE,DATA) \ Mcf5272_iowr(IMMP,MCF5272_USB_EP5DR,SIZE,DATA) #define MCF5272_WR_USB_EP6DR(IMMP,SIZE,DATA) \ Mcf5272_iowr(IMMP,MCF5272_USB_EP6DR,SIZE,DATA) #define MCF5272_WR_USB_EP7DR(IMMP,SIZE,DATA) \ Mcf5272_iowr(IMMP,MCF5272_USB_EP7DR,SIZE,DATA) /* Macro to return current Alternate Setting for a given Interface */ #define AltSetting(imm, i) (int8)((MCF5272_RD_USB_ASR(imm) >> (i << 1)) & 3) /* Bit level definitions and macros */ #define MCF5272_USB_EP0SR_WAKE_ST 0x0800 #define MCF5272_USB_EP0SR_HALT_ST 0x0004 #define MCF5272_USB_EP0SR_DIR 0x0002 #define MCF5272_USB_EP0CTL_DEBUG 0x00040000 #define MCF5272_USB_EP0CTL_WOR_LVL 0x00020000 #define MCF5272_USB_EP0CTL_WOR_EN 0x00010000 #define MCF5272_USB_EP0CTL_CLK_SEL 0x00008000 #define MCF5272_USB_EP0CTL_RESUME 0x00004000 #define MCF5272_USB_EP0CTL_AFE_EN 0x00002000 #define MCF5272_USB_EP0CTL_BUS_PWR 0x00001000 #define MCF5272_USB_EP0CTL_USB_EN 0x00000800 #define MCF5272_USB_EP0CTL_CFG_RAM_VAL 0x00000400 #define MCF5272_USB_EP0CTL_CMD_ERR 0x00000200 #define MCF5272_USB_EP0CTL_CMD_OVER 0x00000100 #define MCF5272_USB_EP0CTL_CRC_ERR 0x00000080 #define MCF5272_USB_EP0CTL_OUT_LVL(x) ((x & 3) << 4) #define MCF5272_USB_EP0CTL_IN_LVL(x) ((x & 3) << 2) #define MCF5272_USB_EP0CTL_IN_BUSY 0x00000002 #define MCF5272_USB_EPNCTL_CRC_ERR 0x0080 #define MCF5272_USB_EPNCTL_ISO_MODE 0x0040 #define MCF5272_USB_EPNCTL_FIFO_LVL(x) ((x & 3) << 2) #define MCF5272_USB_EPNCTL_IN_BUSY 0x0002 #define MCF5272_USB_EPNCTL_STALL 0x0001 #define MCF5272_USB_EP0ISR_DEV_CFG 0x00010000 #define MCF5272_USB_EP0ISR_VEND_REQ 0x00008000 #define MCF5272_USB_EP0ISR_FRM_MAT 0x00004000 #define MCF5272_USB_EP0ISR_ASOF 0x00002000 #define MCF5272_USB_EP0ISR_SOF 0x00001000 #define MCF5272_USB_EP0ISR_WAKE_CHG 0x00000800 #define MCF5272_USB_EP0ISR_RESUME 0x00000400 #define MCF5272_USB_EP0ISR_SUSPEND 0x00000200 #define MCF5272_USB_EP0ISR_RESET 0x00000100 #define MCF5272_USB_EP0ISR_OUT_EOT 0x00000080 #define MCF5272_USB_EP0ISR_OUT_EOP 0x00000040 #define MCF5272_USB_EP0ISR_OUT_LVL 0x00000020 #define MCF5272_USB_EP0ISR_IN_EOT 0x00000010 #define MCF5272_USB_EP0ISR_IN_EOP 0x00000008 #define MCF5272_USB_EP0ISR_UNHALT 0x00000004 #define MCF5272_USB_EP0ISR_HALT 0x00000002 #define MCF5272_USB_EP0ISR_IN_LVL 0x00000001 #define MCF5272_USB_EPNISR_HALT_ST 0x8000 #define MCF5272_USB_EPNISR_DIR 0x4000 #define MCF5272_USB_EPNISR_PRES 0x2000 #define MCF5272_USB_EPNISR_EOT 0x0010 #define MCF5272_USB_EPNISR_EOP 0x0008 #define MCF5272_USB_EPNISR_UNHALT 0x0004 #define MCF5272_USB_EPNISR_HALT 0x0002 #define MCF5272_USB_EPNISR_FIFO_LVL 0x0001 #define MCF5272_USB_EP0IMR_DEV_CFG_EN 0x00010000 #define MCF5272_USB_EP0IMR_VEND_REQ_EN 0x00008000 #define MCF5272_USB_EP0IMR_FRM_MAT_EN 0x00004000 #define MCF5272_USB_EP0IMR_ASOF_EN 0x00002000 #define MCF5272_USB_EP0IMR_SOF_EN 0x00001000 #define MCF5272_USB_EP0IMR_WAKE_CHG_EN 0x00000800 #define MCF5272_USB_EP0IMR_RESUME_EN 0x00000400 #define MCF5272_USB_EP0IMR_SUSPEND_EN 0x00000200 #define MCF5272_USB_EP0IMR_RESET_EN 0x00000100 #define MCF5272_USB_EP0IMR_OUT_EOT_EN 0x00000080 #define MCF5272_USB_EP0IMR_OUT_EOP_EN 0x00000040 #define MCF5272_USB_EP0IMR_OUT_LVL_EN 0x00000020 #define MCF5272_USB_EP0IMR_IN_EOT_EN 0x00000010 #define MCF5272_USB_EP0IMR_IN_EOP_EN 0x00000008 #define MCF5272_USB_EP0IMR_UNHALT_EN 0x00000004 #define MCF5272_USB_EP0IMR_HALT_EN 0x00000002 #define MCF5272_USB_EP0IMR_IN_LVL_EN 0x00000001 #define MCF5272_USB_EPNIMR_EOT_EN 0x0010 #define MCF5272_USB_EPNIMR_EOP_EN 0x0008 #define MCF5272_USB_EPNIMR_UNHALT_EN 0x0004 #define MCF5272_USB_EPNIMR_HALT_EN 0x0002 #define MCF5272_USB_EPNIMR_FIFO_LVL_EN 0x0001 /***********************************************************************/ /* * Define a pointer to the MCF5272 Internal Memory Map */ typedef uint8 MCF5272_IMM; /***********************************************************************/ #endif /* _CPU_MCF5272_H */ ocproxy-1.60/contrib/ports/old/coldfire/include/arch/perf.h000066400000000000000000000033401303453231400237620ustar00rootroot00000000000000/* * Copyright (c) 2001-2003 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #ifndef __PERF_H__ #define __PERF_H__ #define PERF_START /* null definition */ #define PERF_STOP(x) /* null definition */ #endif /* __PERF_H__ */ ocproxy-1.60/contrib/ports/old/coldfire/include/arch/sys_arch.h000066400000000000000000000043571303453231400246520ustar00rootroot00000000000000/* @(#)sys_arch.h * Copyright (c) 2001-2003 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: David Haas * */ #ifndef _SYS_ARCH_H #define _SYS_ARCH_H 1 #include #include #include "netif/etharp.h" #define SYS_MBOX_NULL NULL #define SYS_SEM_NULL NULL /* sockets needs this definition. include time.h if this is a unix system */ struct timeval { long tv_sec; long tv_usec; }; typedef NU_SEMAPHORE * sys_sem_t; typedef NU_QUEUE * sys_mbox_t; typedef NU_TASK * sys_thread_t; typedef u32_t sys_prot_t; /* Functions specific to Coldfire/Nucleus */ void sys_setvect(u32_t vector, void (*isr_function)(void), void (*dis_funct)(void)); void sys_get_eth_addr(struct eth_addr *eth_addr); int * sys_arch_errno(void); #include "arch/errno.h" #endif /* _SYS_ARCH_H */ ocproxy-1.60/contrib/ports/old/coldfire/include/netif/000077500000000000000000000000001303453231400230455ustar00rootroot00000000000000ocproxy-1.60/contrib/ports/old/coldfire/include/netif/5272fec.h000066400000000000000000000033441303453231400242770ustar00rootroot00000000000000/* @(#)5272fec.h * Copyright (c) 2001-2003 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Purpose: MCF5272 fec ethernet driver * * Author: David Haas * */ #ifndef _5272FEC_H #define _5272FEC_H 1 err_t mcf5272fecif_init(struct netif *netif); #endif /* _5272FEC_H */ ocproxy-1.60/contrib/ports/old/coldfire/include/netif/tcpdump.h000066400000000000000000000033311303453231400246720ustar00rootroot00000000000000/* * Copyright (c) 2001-2003 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #ifndef __NETIF_TCPDUMP_H__ #define __NETIF_TCPDUMP_H__ #include "lwip/pbuf.h" void tcpdump(struct pbuf *p); #endif /* __NETIF_TCPDUMP_H__ */ ocproxy-1.60/contrib/ports/old/coldfire/netif/000077500000000000000000000000001303453231400214225ustar00rootroot00000000000000ocproxy-1.60/contrib/ports/old/coldfire/netif/5272fec.c000066400000000000000000000647371303453231400226640ustar00rootroot00000000000000/* * Copyright (c) 2001-2003, Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the Institute nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: David Haas dhaas@alum.rpi.edu * */ /* This is an ethernet driver for the internal fec in the Coldfire MCF5272. The driver has been written to use ISRs for Receive Frame and Transmit Frame Complete. */ #include "lwip/debug.h" #include "lwip/opt.h" #include "lwip/def.h" #include "lwip/mem.h" #include "lwip/pbuf.h" #include "lwip/stats.h" #include "lwip/sys.h" #include "netif/etharp.h" #include "arch/mcf5272.h" /* Sizing the descriptor rings will depend upon how many pbufs you have available * and how big they are. Also on how many frames you might want to input before dropping * frames. Generally it is a good idea to buffer one tcp window. This means that * you won't get a tcp retransmit and your tcp transmissions will be reasonably fast. */ #define NUM_RXBDS 64 // Number of receive descriptor rings #define NUM_TXBDS 32 // Number of transmit descriptor rings /* Define those to better describe your network interface. */ #define IFNAME0 'e' #define IFNAME1 't' /* Define interface MTU size. We set this to 1518, since this is the max Size of an ethernet frame without VLAN support. */ #define MTU_FEC 1518 PACK_STRUCT_BEGIN struct rxbd { u16_t flags; u16_t data_len; u8_t *p_buf; }; PACK_STRUCT_END typedef struct rxbd rxbd_t; PACK_STRUCT_BEGIN struct txbd { u16_t flags; u16_t data_len; u8_t *p_buf; }; PACK_STRUCT_END typedef struct txbd txbd_t; ALIGN_STRUCT_8_BEGIN struct mcf5272if { rxbd_t rxbd_a[NUM_RXBDS]; // Rx descriptor ring. Must be aligned to double-word txbd_t txbd_a[NUM_TXBDS]; // Tx descriptor ring. Must be aligned to double-word struct pbuf *rx_pbuf_a[NUM_RXBDS]; // Array of pbufs corresponding to payloads in rx desc ring. struct pbuf *tx_pbuf_a[NUM_TXBDS]; // Array of pbufs corresponding to payloads in tx desc ring. unsigned int rx_remove; // Index that driver will remove next rx frame from. unsigned int rx_insert; // Index that driver will insert next empty rx buffer. unsigned int tx_insert; // Index that driver will insert next tx frame to. unsigned int tx_remove; // Index that driver will clean up next tx buffer. unsigned int tx_free; // Number of free transmit descriptors. unsigned int rx_buf_len; // number of bytes in a rx buffer (that we can use). MCF5272_IMM *imm; // imm address. All register accesses use this as base. struct eth_addr *ethaddr; struct netif *netif; }; ALIGN_STRUCT_END typedef struct mcf5272if mcf5272if_t; #define INC_RX_BD_INDEX(idx) do { if (++idx >= NUM_RXBDS) idx = 0; } while (0) #define INC_TX_BD_INDEX(idx) do { if (++idx >= NUM_TXBDS) idx = 0; } while (0) #define DEC_TX_BD_INDEX(idx) do { if (idx-- == 0) idx = NUM_TXBDS-1; } while (0) static mcf5272if_t *mcf5272if; static sys_sem_t tx_sem; u32_t phy; typedef struct mcf5272if mcf5272if_t; /*-----------------------------------------------------------------------------------*/ static void fill_rx_ring(mcf5272if_t *mcf5272) { struct pbuf *p; struct rxbd *p_rxbd; int i = mcf5272->rx_insert; void *new_payload; u32_t u_p_pay; /* Try and fill as many receive buffers as we can */ while (mcf5272->rx_pbuf_a[i] == 0) { p = pbuf_alloc(PBUF_RAW, (u16_t) mcf5272->rx_buf_len, PBUF_POOL); if (p == 0) /* No pbufs, so can't refill ring */ return; /* Align payload start to be divisible by 16 as required by HW */ u_p_pay = (u32_t) p->payload; new_payload = p->payload = (void *) (((u_p_pay + 15) / 16) * 16); mcf5272->rx_pbuf_a[i] = p; p_rxbd = &mcf5272->rxbd_a[i]; p_rxbd->p_buf = (u8_t *) new_payload; p_rxbd->flags = (p_rxbd->flags & MCF5272_FEC_RX_BD_W) | MCF5272_FEC_RX_BD_E; INC_RX_BD_INDEX(mcf5272->rx_insert); i = mcf5272->rx_insert; } } /*-----------------------------------------------------------------------------------*/ static void enable_fec(mcf5272if_t *mcf5272) { MCF5272_IMM *imm = mcf5272->imm; int i; /* Initialize empty tx descriptor ring */ for(i = 0; i < NUM_TXBDS-1; i++) mcf5272->txbd_a[i].flags = 0; /* Set wrap bit for last descriptor */ mcf5272->txbd_a[i].flags = MCF5272_FEC_TX_BD_W; /* initialize tx indexes */ mcf5272->tx_remove = mcf5272->tx_insert = 0; mcf5272->tx_free = NUM_TXBDS; /* Initialize empty rx descriptor ring */ for (i = 0; i < NUM_RXBDS-1; i++) mcf5272->rxbd_a[i].flags = 0; /* Set wrap bit for last descriptor */ mcf5272->rxbd_a[i].flags = MCF5272_FEC_RX_BD_W; /* Initialize rx indexes */ mcf5272->rx_remove = mcf5272->rx_insert = 0; /* Fill receive descriptor ring */ fill_rx_ring(mcf5272); /* Enable FEC */ MCF5272_WR_FEC_ECR(imm, (MCF5272_FEC_ECR_ETHER_EN));// | 0x2000000)); /* Indicate that there have been empty receive buffers produced */ MCF5272_WR_FEC_RDAR(imm,1); } /*-----------------------------------------------------------------------------------*/ static void disable_fec(mcf5272if_t *mcf5272) { MCF5272_IMM *imm = mcf5272->imm; int i; u32_t value; u32_t old_level; /* We need to disable interrupts here, It is important when dealing with shared registers. */ old_level = sys_arch_protect(); /* First disable the FEC interrupts. Do it in the appropriate ICR register. */ value = MCF5272_RD_SIM_ICR3(imm); MCF5272_WR_SIM_ICR3(imm, (value & ~(MCF5272_SIM_ICR_ERX_IL(7) | MCF5272_SIM_ICR_ETX_IL(7) | MCF5272_SIM_ICR_ENTC_IL(7)))); /* Now we can restore interrupts. This is because we can assume that * we are single threaded here (only 1 thread will be calling disable_fec * for THIS interface). */ sys_arch_unprotect(old_level); /* Release all buffers attached to the descriptors. Since the driver * ALWAYS zeros the pbuf array locations and descriptors when buffers are * removed, we know we just have to free any non-zero descriptors */ for (i = 0; i < NUM_RXBDS; i++) if (mcf5272->rx_pbuf_a[i]) { pbuf_free(mcf5272->rx_pbuf_a[i]); mcf5272->rx_pbuf_a[i] = 0; mcf5272->rxbd_a->p_buf = 0; } for (i = 0; i < NUM_TXBDS; i++) if (mcf5272->tx_pbuf_a[i]) { pbuf_free(mcf5272->tx_pbuf_a[i]); mcf5272->tx_pbuf_a[i] = 0; mcf5272->txbd_a->p_buf = 0; } /* Reset the FEC - equivalent to a hard reset */ MCF5272_WR_FEC_ECR(imm,MCF5272_FEC_ECR_RESET); /* Wait for the reset sequence to complete, it should take about 16 clock cycles */ i = 0; while (MCF5272_RD_FEC_ECR(imm) & MCF5272_FEC_ECR_RESET) { if (++i > 100) abort(); } /* Disable all FEC interrupts by clearing the IMR register */ MCF5272_WR_FEC_IMR(imm,0); /* Clear any interrupts by setting all bits in the EIR register */ MCF5272_WR_FEC_EIR(imm,0xFFFFFFFF); } /*-----------------------------------------------------------------------------------* * Function called by receive LISR to disable fec tx interrupt *-----------------------------------------------------------------------------------*/ static void mcf5272_dis_tx_int(void) { mcf5272if_t *mcf5272 = mcf5272if; MCF5272_IMM *imm = mcf5272->imm; u32_t value; value = MCF5272_RD_FEC_IMR(imm); /* Clear rx interrupt bit */ MCF5272_WR_FEC_IMR(imm, (value & ~MCF5272_FEC_IMR_TXFEN)); return; } /*-----------------------------------------------------------------------------------* *-----------------------------------------------------------------------------------*/ static void mcf5272fec_tx_hisr(void) { /* Just signal task that it can run and cleanup */ sys_sem_signal(tx_sem); } /*-----------------------------------------------------------------------------------* This function must be run as a task, since it ends up calling free() through pbuf_free() *-----------------------------------------------------------------------------------*/ static void mcf5272fec_tx_cleanup(void) { struct pbuf *p; mcf5272if_t *mcf5272 = mcf5272if; MCF5272_IMM *imm = mcf5272->imm; u32_t value; u32_t old_level; unsigned int tx_remove_sof; unsigned int tx_remove_eof; unsigned int i; u16_t flags; tx_remove_sof = tx_remove_eof = mcf5272->tx_remove; /* We must protect reading the flags and then reading the buffer pointer. They must both be read together. */ old_level = sys_arch_protect(); /* Loop, looking for completed buffers at eof */ while ((((flags = mcf5272->txbd_a[tx_remove_eof].flags) & MCF5272_FEC_TX_BD_R) == 0) && (mcf5272->tx_pbuf_a[tx_remove_eof] != 0)) { /* See if this is last buffer in frame */ if ((flags & MCF5272_FEC_TX_BD_L) != 0) { i = tx_remove_eof; /* This frame is complete. Take the frame off backwards */ do { p = mcf5272->tx_pbuf_a[i]; mcf5272->tx_pbuf_a[i] = 0; mcf5272->txbd_a[i].p_buf = 0; mcf5272->tx_free++; if (i != tx_remove_sof) DEC_TX_BD_INDEX(i); else break; } while (1); sys_arch_unprotect(old_level); pbuf_free(p); // Will be head of chain old_level = sys_arch_protect(); /* Look at next descriptor */ INC_TX_BD_INDEX(tx_remove_eof); tx_remove_sof = tx_remove_eof; } else INC_TX_BD_INDEX(tx_remove_eof); } mcf5272->tx_remove = tx_remove_sof; /* clear interrupt status for tx interrupt */ MCF5272_WR_FEC_EIR(imm, MCF5272_FEC_EIR_TXF); value = MCF5272_RD_FEC_IMR(imm); /* Set tx interrupt bit again */ MCF5272_WR_FEC_IMR(imm, (value | MCF5272_FEC_IMR_TXFEN)); /* Now we can re-enable higher priority interrupts again */ sys_arch_unprotect(old_level); } /*-----------------------------------------------------------------------------------* void low_level_output(mcf5272if_t *mcf5272, struct pbuf *p) Output pbuf chain to hardware. It is assumed that there is a complete and correct ethernet frame in p. The only buffering we have in this system is in the hardware descriptor ring. If there is no room on the ring, then drop the frame. *-----------------------------------------------------------------------------------*/ static err_t low_level_output(struct netif *netif, struct pbuf *p) { struct pbuf *q; mcf5272if_t *mcf5272 = netif->state; MCF5272_IMM *imm = mcf5272->imm; int num_desc; int num_free; unsigned int tx_insert_sof, tx_insert_eof; unsigned int i; u32_t old_level; /* Make sure that there are no PBUF_REF buffers in the chain. These buffers have to be freed immediately and this ethernet driver puts the buffers on the dma chain, so they get freed later */ p = pbuf_take(p); /* Interrupts are disabled through this whole thing to support multi-threading * transmit calls. Also this function might be called from an ISR. */ old_level = sys_arch_protect(); /* Determine number of descriptors needed */ num_desc = pbuf_clen(p); if (num_desc > mcf5272->tx_free) { /* Drop the frame, we have no place to put it */ #ifdef LINK_STATS lwip_stats.link.memerr++; #endif sys_arch_unprotect(old_level); return ERR_MEM; } else { /* Increment use count on pbuf */ pbuf_ref(p); /* Put buffers on descriptor ring, but don't mark them as ready yet */ tx_insert_eof = tx_insert_sof = mcf5272->tx_insert; q = p; do { mcf5272->tx_free--; mcf5272->tx_pbuf_a[tx_insert_eof] = q; mcf5272->txbd_a[tx_insert_eof].p_buf = q->payload; mcf5272->txbd_a[tx_insert_eof].data_len = q->len; q = q->next; if (q) INC_TX_BD_INDEX(tx_insert_eof); } while (q); /* Go backwards through descriptor ring setting flags */ i = tx_insert_eof; do { mcf5272->txbd_a[i].flags = (u16_t) (MCF5272_FEC_TX_BD_R | (mcf5272->txbd_a[i].flags & MCF5272_FEC_TX_BD_W) | ((i == tx_insert_eof) ? (MCF5272_FEC_TX_BD_L | MCF5272_FEC_TX_BD_TC) : 0)); if (i != tx_insert_sof) DEC_TX_BD_INDEX(i); else break; } while (1); INC_TX_BD_INDEX(tx_insert_eof); mcf5272->tx_insert = tx_insert_eof; #ifdef LINK_STATS lwip_stats.link.xmit++; #endif /* Indicate that there has been a transmit buffer produced */ MCF5272_WR_FEC_TDAR(imm,1); sys_arch_unprotect(old_level); } return ERR_OK; } /*-----------------------------------------------------------------------------------*/ static void eth_input(struct pbuf *p, struct netif *netif) { /* Ethernet protocol layer */ struct eth_hdr *ethhdr; mcf5272if_t *mcf5272 = netif->state; ethhdr = p->payload; switch (htons(ethhdr->type)) { case ETHTYPE_IP: etharp_ip_input(netif, p); pbuf_header(p, -14); netif->input(p, netif); break; case ETHTYPE_ARP: etharp_arp_input(netif, mcf5272->ethaddr, p); break; default: pbuf_free(p); break; } } /*-----------------------------------------------------------------------------------*/ static void arp_timer(void *arg) { etharp_tmr(); sys_timeout(ARP_TMR_INTERVAL, (sys_timeout_handler)arp_timer, NULL); } /*-----------------------------------------------------------------------------------* * Function called by receive LISR to disable fec rx interrupt *-----------------------------------------------------------------------------------*/ static void mcf5272_dis_rx_int(void) { mcf5272if_t *mcf5272 = mcf5272if; MCF5272_IMM *imm = mcf5272->imm; u32_t value; value = MCF5272_RD_FEC_IMR(imm); /* Clear rx interrupt bit */ MCF5272_WR_FEC_IMR(imm, (value & ~MCF5272_FEC_IMR_RXFEN)); return; } /*-----------------------------------------------------------------------------------*/ static void mcf5272fec_rx(void) { /* This is the receive ISR. It is written to be a high-level ISR. */ u32_t old_level; mcf5272if_t *mcf5272 = mcf5272if; MCF5272_IMM *imm = mcf5272->imm; u32_t value; u16_t flags; unsigned int rx_remove_sof; unsigned int rx_remove_eof; struct pbuf *p; rx_remove_sof = rx_remove_eof = mcf5272->rx_remove; /* Loop, looking for filled buffers at eof */ while ((((flags = mcf5272->rxbd_a[rx_remove_eof].flags) & MCF5272_FEC_RX_BD_E) == 0) && (mcf5272->rx_pbuf_a[rx_remove_eof] != 0)) { /* See if this is last buffer in frame */ if ((flags & MCF5272_FEC_RX_BD_L) != 0) { /* This frame is ready to go. Start at first descriptor in frame. */ p = 0; do { /* Adjust pbuf length if this is last buffer in frame */ if (rx_remove_sof == rx_remove_eof) { mcf5272->rx_pbuf_a[rx_remove_sof]->tot_len = mcf5272->rx_pbuf_a[rx_remove_sof]->len = (u16_t) (mcf5272->rxbd_a[rx_remove_sof].data_len - (p ? p->tot_len : 0)); } else mcf5272->rx_pbuf_a[rx_remove_sof]->len = mcf5272->rx_pbuf_a[rx_remove_sof]->tot_len = mcf5272->rxbd_a[rx_remove_sof].data_len; /* Chain pbuf */ if (p == 0) { p = mcf5272->rx_pbuf_a[rx_remove_sof]; // First in chain p->tot_len = p->len; // Important since len might have changed } else { pbuf_chain(p, mcf5272->rx_pbuf_a[rx_remove_sof]); pbuf_free(mcf5272->rx_pbuf_a[rx_remove_sof]); } /* Clear pointer to mark descriptor as free */ mcf5272->rx_pbuf_a[rx_remove_sof] = 0; mcf5272->rxbd_a[rx_remove_sof].p_buf = 0; if (rx_remove_sof != rx_remove_eof) INC_RX_BD_INDEX(rx_remove_sof); else break; } while (1); INC_RX_BD_INDEX(rx_remove_sof); /* Check error status of frame */ if (flags & (MCF5272_FEC_RX_BD_LG | MCF5272_FEC_RX_BD_NO | MCF5272_FEC_RX_BD_CR | MCF5272_FEC_RX_BD_OV)) { #ifdef LINK_STATS lwip_stats.link.drop++; if (flags & MCF5272_FEC_RX_BD_LG) lwip_stats.link.lenerr++; //Jumbo gram else if (flags & (MCF5272_FEC_RX_BD_NO | MCF5272_FEC_RX_BD_OV)) lwip_stats.link.err++; else if (flags & MCF5272_FEC_RX_BD_CR) lwip_stats.link.chkerr++; // CRC errors #endif /* Drop errored frame */ pbuf_free(p); } else { /* Good frame. increment stat */ #ifdef LINK_STATS lwip_stats.link.recv++; #endif eth_input(p, mcf5272->netif); } } INC_RX_BD_INDEX(rx_remove_eof); } mcf5272->rx_remove = rx_remove_sof; /* clear interrupt status for rx interrupt */ old_level = sys_arch_protect(); MCF5272_WR_FEC_EIR(imm, MCF5272_FEC_EIR_RXF); value = MCF5272_RD_FEC_IMR(imm); /* Set rx interrupt bit again */ MCF5272_WR_FEC_IMR(imm, (value | MCF5272_FEC_IMR_RXFEN)); /* Now we can re-enable higher priority interrupts again */ sys_arch_unprotect(old_level); /* Fill up empty descriptor rings */ fill_rx_ring(mcf5272); /* Tell fec that we have filled up her ring */ MCF5272_WR_FEC_RDAR(imm, 1); return; } /*-----------------------------------------------------------------------------------*/ static void low_level_init(struct netif *netif) { mcf5272if_t *mcf5272; MCF5272_IMM *imm; VOID (*old_lisr)(INT); /* old LISR */ u32_t value; u32_t old_level; struct pbuf *p; int i; mcf5272 = netif->state; imm = mcf5272->imm; /* Initialize our ethernet address */ sys_get_eth_addr(mcf5272->ethaddr); /* First disable fec */ disable_fec(mcf5272); /* Plug appropriate low level interrupt vectors */ sys_setvect(MCF5272_VECTOR_ERx, mcf5272fec_rx, mcf5272_dis_rx_int); sys_setvect(MCF5272_VECTOR_ETx, mcf5272fec_tx_hisr, mcf5272_dis_tx_int); //sys_setvect(MCF5272_VECTOR_ENTC, mcf5272fec_ntc); /* Set the I_MASK register to enable only rx & tx frame interrupts */ MCF5272_WR_FEC_IMR(imm, MCF5272_FEC_IMR_TXFEN | MCF5272_FEC_IMR_RXFEN); /* Clear I_EVENT register */ MCF5272_WR_FEC_EIR(imm,0xFFFFFFFF); /* Set up the appropriate interrupt levels */ /* Disable interrupts, since this is a read/modify/write operation */ old_level = sys_arch_protect(); value = MCF5272_RD_SIM_ICR3(imm); MCF5272_WR_SIM_ICR3(imm, value | MCF5272_SIM_ICR_ERX_IL(FEC_LEVEL) | MCF5272_SIM_ICR_ETX_IL(FEC_LEVEL)); sys_arch_unprotect(old_level); /* Set the source address for the controller */ MCF5272_WR_FEC_MALR(imm,0 | (mcf5272->ethaddr->addr[0] <<24) | (mcf5272->ethaddr->addr[1] <<16) | (mcf5272->ethaddr->addr[2] <<8) | (mcf5272->ethaddr->addr[3] <<0)); MCF5272_WR_FEC_MAUR(imm,0 | (mcf5272->ethaddr->addr[4] <<24) | (mcf5272->ethaddr->addr[5] <<16)); /* Initialize the hash table registers */ /* We are not supporting multicast addresses */ MCF5272_WR_FEC_HTUR(imm,0); MCF5272_WR_FEC_HTLR(imm,0); /* Set Receive Buffer Size. We subtract 16 because the start of the receive * buffer MUST be divisible by 16, so depending on where the payload really * starts in the pbuf, we might be increasing the start point by up to 15 bytes. * See the alignment code in fill_rx_ring() */ /* There might be an offset to the payload address and we should subtract * that offset */ p = pbuf_alloc(PBUF_RAW, PBUF_POOL_BUFSIZE, PBUF_POOL); i = 0; if (p) { struct pbuf *q = p; while ((q = q->next) != 0) i += q->len; mcf5272->rx_buf_len = PBUF_POOL_BUFSIZE-16-i; pbuf_free(p); } MCF5272_WR_FEC_EMRBR(imm, (u16_t) mcf5272->rx_buf_len); /* Point to the start of the circular Rx buffer descriptor queue */ MCF5272_WR_FEC_ERDSR(imm, ((u32_t) &mcf5272->rxbd_a[0])); /* Point to the start of the circular Tx buffer descriptor queue */ MCF5272_WR_FEC_ETDSR(imm, ((u32_t) &mcf5272->txbd_a[0])); /* Set the tranceiver interface to MII mode */ MCF5272_WR_FEC_RCR(imm, 0 | MCF5272_FEC_RCR_MII_MODE | MCF5272_FEC_RCR_DRT); /* half duplex */ /* Only operate in half-duplex, no heart beat control */ MCF5272_WR_FEC_TCR(imm, 0); /* Set the maximum frame length (MTU) */ MCF5272_WR_FEC_MFLR(imm, MTU_FEC); /* Set MII bus speed */ MCF5272_WR_FEC_MSCR(imm, 0x0a); /* Enable fec i/o pins */ value = MCF5272_RD_GPIO_PBCNT(imm); MCF5272_WR_GPIO_PBCNT(imm, ((value & 0x0000ffff) | 0x55550000)); /* Clear MII interrupt status */ MCF5272_WR_FEC_EIR(imm, MCF5272_FEC_IMR_MIIEN); /* /\* Read phy ID *\/ */ /* MCF5272_WR_FEC_MMFR(imm, 0x600a0000); */ /* while (1) */ /* { */ /* value = MCF5272_RD_FEC_EIR(imm); */ /* if ((value & MCF5272_FEC_IMR_MIIEN) != 0) */ /* { */ /* MCF5272_WR_FEC_EIR(imm, MCF5272_FEC_IMR_MIIEN); */ /* break; */ /* } */ /* } */ /* phy = MCF5272_RD_FEC_MMFR(imm); */ /* Enable FEC */ enable_fec(mcf5272); /* THIS IS FOR LEVEL ONE/INTEL PHY ONLY!!! */ /* Program Phy LED 3 to tell us transmit status */ MCF5272_WR_FEC_MMFR(imm, 0x50520412); } /*-----------------------------------------------------------------------------------* * etharp timer thread * It's only job is to initialize the timer, create a semaphore and wait on it * forever. We need a special task to handle the arp timer. *-----------------------------------------------------------------------------------*/ static void etharp_timer_thread(void *arg) { sys_sem_t *psem = (sys_sem_t *) arg; /* Create timeout timer */ sys_timeout(ARP_TMR_INTERVAL, (sys_timeout_handler)arp_timer, NULL); /* Signal previous task that it can go */ sys_sem_signal(*psem); tx_sem = sys_sem_new(0); while (1) { sys_sem_wait(tx_sem); mcf5272fec_tx_cleanup(); } } /*-----------------------------------------------------------------------------------*/ static void etharp_timer_init(void *arg) { sys_thread_new(DEFAULT_THREAD_NAME, (void *)etharp_timer_thread, arg, DEFAULT_THREAD_STACKSIZE, DEFAULT_THREAD_PRIO); } /*-----------------------------------------------------------------------------------*/ /* * mcf5272fecif_init(struct netif *netif): * * Should be called at the beginning of the program to set up the * network interface. It calls the function low_level_init() to do the * actual setup of the hardware. * * Note that there is only one fec in a 5272! * */ err_t mcf5272fecif_init(struct netif *netif) { sys_sem_t sem; /* Allocate our interface control block */ /* IMPORTANT NOTE: This works for 5272, but if you are using a cpu with data cache * then you need to make sure you get this memory from non-cachable memory. */ mcf5272if = (mcf5272if_t *) calloc(1, sizeof(mcf5272if_t)); if (mcf5272if) { netif->state = mcf5272if; mcf5272if->netif = netif; netif->name[0] = IFNAME0; netif->name[1] = IFNAME1; netif->output = etharp_output; netif->linkoutput = low_level_output; netif->mtu = MTU_FEC - 18; // mtu without ethernet header and crc mcf5272if->ethaddr = (struct eth_addr *)&(netif->hwaddr[0]); netif->hwaddr_len = 6; /* Ethernet interface */ mcf5272if->imm = mcf5272_get_immp(); low_level_init(netif); etharp_init(); sem = sys_sem_new(0); etharp_timer_init(&sem); sys_sem_wait(sem); sys_sem_free(sem); return ERR_OK; } else return ERR_MEM; } /*-----------------------------------------------------------------------------------*/ ocproxy-1.60/contrib/ports/old/coldfire/netif/tcpdump.c000066400000000000000000000036501303453231400232460ustar00rootroot00000000000000/* * Copyright (c) 2001-2003 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #include #include "netif/tcpdump.h" #include "lwip/ip.h" #include "lwip/tcp.h" #include "lwip/udp.h" #include "lwip/inet.h" /*-----------------------------------------------------------------------------------*/ void tcpdump(struct pbuf *p) { } /*-----------------------------------------------------------------------------------*/ ocproxy-1.60/contrib/ports/old/coldfire/perf.c000066400000000000000000000032011303453231400214110ustar00rootroot00000000000000/* * Copyright (c) 2001-2003 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #include "arch/perf.h" void perf_init(char *fname) { } ocproxy-1.60/contrib/ports/old/coldfire/proj/000077500000000000000000000000001303453231400212675ustar00rootroot00000000000000ocproxy-1.60/contrib/ports/old/coldfire/proj/lwipopts.h000066400000000000000000000166151303453231400233320ustar00rootroot00000000000000/* * Copyright (c) 2001-2003 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #ifndef __LWIPOPTS_H__ #define __LWIPOPTS_H__ #define NO_SYS 0 /*#define LWIP_EVENT_API 0*/ /* ---------- Memory options ---------- */ /* MEM_ALIGNMENT: should be set to the alignment of the CPU for which lwIP is compiled. 4 byte alignment -> define MEM_ALIGNMENT to 4, 2 byte alignment -> define MEM_ALIGNMENT to 2. */ #define MEM_ALIGNMENT 4 /* MEM_SIZE: the size of the heap memory. If the application will send a lot of data that needs to be copied, this should be set high. */ #define MEM_SIZE 65000 /* MEMP_NUM_PBUF: the number of memp struct pbufs. If the application sends a lot of data out of ROM (or other static memory), this should be set high. */ #define MEMP_NUM_PBUF 16 /* MEMP_NUM_UDP_PCB: the number of UDP protocol control blocks. One per active UDP "connection". */ #define MEMP_NUM_UDP_PCB 4 /* MEMP_NUM_TCP_PCB: the number of simulatenously active TCP connections. */ #define MEMP_NUM_TCP_PCB 5 /* MEMP_NUM_TCP_PCB_LISTEN: the number of listening TCP connections. */ #define MEMP_NUM_TCP_PCB_LISTEN 8 /* MEMP_NUM_TCP_SEG: the number of simultaneously queued TCP segments. */ #define MEMP_NUM_TCP_SEG 16 /* The following four are used only with the sequential API and can be set to 0 if the application only will use the raw API. */ /* MEMP_NUM_NETBUF: the number of struct netbufs. */ #define MEMP_NUM_NETBUF 6 /* MEMP_NUM_NETCONN: the number of struct netconns. */ #define MEMP_NUM_NETCONN 10 /* MEMP_NUM_TCPIP_MSG: the number of struct tcpip_msg, which is used for sequential API communication and incoming packets. Used in src/api/tcpip.c. */ #define MEMP_NUM_TCPIP_MSG_API 16 #define MEMP_NUM_TCPIP_MSG_INPKT 16 /* MEMP_NUM_SYS_TIMEOUT: the number of simulateously active timeouts. */ #define MEMP_NUM_SYS_TIMEOUT 3 /* These two control is reclaimer functions should be compiled in. Should always be turned on (1). */ #define MEM_RECLAIM 1 #define MEMP_RECLAIM 1 /* ---------- Pbuf options ---------- */ /* PBUF_POOL_SIZE: the number of buffers in the pbuf pool. */ #define PBUF_POOL_SIZE 128 /* PBUF_POOL_BUFSIZE: the size of each pbuf in the pbuf pool. */ #define PBUF_POOL_BUFSIZE 1024 /* PBUF_LINK_HLEN: the number of bytes that should be allocated for a link level header. */ #define PBUF_LINK_HLEN 16 /** SYS_LIGHTWEIGHT_PROT * define SYS_LIGHTWEIGHT_PROT in lwipopts.h if you want inter-task protection * for certain critical regions during buffer allocation, deallocation and memory * allocation and deallocation. */ #define SYS_LIGHTWEIGHT_PROT 1 /* ---------- TCP options ---------- */ #define LWIP_TCP 1 #define TCP_TTL 255 /* Controls if TCP should queue segments that arrive out of order. Define to 0 if your device is low on memory. */ #define TCP_QUEUE_OOSEQ 1 /* TCP Maximum segment size. */ #define TCP_MSS 128 /* TCP sender buffer space (bytes). */ #define TCP_SND_BUF 256 /* TCP sender buffer space (pbufs). This must be at least = 2 * TCP_SND_BUF/TCP_MSS for things to work. */ #define TCP_SND_QUEUELEN 4 * TCP_SND_BUF/TCP_MSS /* TCP receive window. */ #define TCP_WND 1024 /* Maximum number of retransmissions of data segments. */ #define TCP_MAXRTX 12 /* Maximum number of retransmissions of SYN segments. */ #define TCP_SYNMAXRTX 4 /* TCP writable space (bytes). This must be less than or equal to TCP_SND_BUF. It is the amount of space which must be available in the tcp snd_buf for select to return writable */ #define TCP_SNDLOWAT TCP_SND_BUF/2 /* ---------- ARP options ---------- */ #define ARP_TABLE_SIZE 10 #define ARP_QUEUEING 1 /* ---------- IP options ---------- */ /* Define IP_FORWARD to 1 if you wish to have the ability to forward IP packets across network interfaces. If you are going to run lwIP on a device with only one network interface, define this to 0. */ #define IP_FORWARD 0 /* If defined to 1, IP options are allowed (but not parsed). If defined to 0, all packets with IP options are dropped. */ #define IP_OPTIONS 1 /* IP reassembly and segmentation.These are orthogonal even * if they both deal with IP fragments */ #define IP_REASSEMBLY 1 #define IP_FRAG 1 /* ---------- ICMP options ---------- */ #define ICMP_TTL 255 /* ---------- DHCP options ---------- */ /* Define LWIP_DHCP to 1 if you want DHCP configuration of interfaces. DHCP is not implemented in lwIP 0.5.1, however, so turning this on does currently not work. */ #define LWIP_DHCP 0 /* 1 if you want to do an ARP check on the offered address (recommended). */ #define DHCP_DOES_ARP_CHECK 1 /* ---------- UDP options ---------- */ #define LWIP_UDP 1 #define UDP_TTL 255 /* ---------- Statistics options ---------- */ #define LWIP_STATS 1 #ifdef LWIP_STATS #define LINK_STATS #define IP_STATS #define ICMP_STATS #define UDP_STATS #define TCP_STATS #define MEM_STATS #define MEMP_STATS #define PBUF_STATS #define SYS_STATS #endif /* STATS */ #define LWIP_COMPAT_SOCKETS 1 #define LWIP_PROVIDE_ERRNO 1 /* People often make a mistake on the priority of their communications task. The TCP/IP stack should be at a relatively low priority if it is an endpoint (not a router) on a somewhat underpowered CPU. You are'nt going to keep up with network traffic during a denial of service attack or misconfigured network and you don't want an overburdened network task to cause other important tasks (including your UI) to stop working. Drop packets! It forces flow control and lets the rest of your system run. */ #define TCPIP_THREAD_PRIO 220 // Relatively low priority #define DEFAULT_THREAD_PRIO 240 #endif /* __LWIPOPTS_H__ */ ocproxy-1.60/contrib/ports/old/coldfire/sys_arch.c000066400000000000000000000462501303453231400223030ustar00rootroot00000000000000/* @(#)sys_arch.c * Copyright (c) 2001-2003 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: David Haas * */ #include "lwip/debug.h" #include "lwip/sys.h" #include "lwip/opt.h" #include "lwip/stats.h" #include "nucleus.h" #include "config.h" #include #include struct sys_thread { struct sys_thread *next; struct sys_timeouts timeouts; int errno_i; NU_TASK *pthread; void (*function)(void *arg); void *arg; }; struct sys_hisr { struct sys_hisr *next; NU_HISR *hisr; void (*disablefun) (void); u32_t vector; }; static int num_sem = 0; // Number of semaphores created static int num_mbox = 0; // Number of mailboxes created static int num_thread = 0; // Number of threads created static int num_hisr = 0; // Number of hisrs created static struct sys_thread *threads = NULL; static struct sys_hisr *hisrs = NULL; #define TICKS_PER_SECOND 10000 #define MS_TO_TICKS(MS) (MS * (TICKS_PER_SECOND / 1000)) #define TICKS_TO_MS(TICKS) ((unsigned long)((1000ULL * TICKS) / TICKS_PER_SECOND)) #define TICKS_TO_HUNDMICROSEC(TICKS) TICKS #define SYS_MBOX_SIZE 128 // Number of elements in mbox queue #define SYS_STACK_SIZE 2048 // A minimum Nucleus stack for coldfire #define SYS_HISR_STACK_SIZE 2048 // A minimum Nucleus stack for coldfire /*---------------------------------------------------------------------------------*/ void sys_init(void) { return; } /*---------------------------------------------------------------------------------*/ static void sys_thread_entry(UNSIGNED argc, VOID *argv) { /* argv is passed as a pointer to our thread structure */ struct sys_thread *p_thread = (struct sys_thread *)argv; p_thread->function(p_thread->arg); } /*---------------------------------------------------------------------------------*/ static struct sys_thread * introduce_thread(NU_TASK *id, void (*function)(void *arg), void *arg) { struct sys_thread *thread; sys_prot_t old_level; thread = (struct sys_thread *) calloc(1,sizeof(struct sys_thread)); if (thread) { old_level = sys_arch_protect(); thread->next = threads; thread->timeouts.next = NULL; thread->pthread = id; thread->function = function; thread->arg = arg; threads = thread; sys_arch_unprotect(old_level); } return thread; } /*---------------------------------------------------------------------------------*/ /* We use Nucleus task as thread. Create one with a standard size stack at a standard * priority. */ sys_thread_t sys_thread_new(char *name, void (* function)(void *arg), void *arg, int stacksize, int prio) { NU_TASK *p_thread; u8_t *p_stack; STATUS status; char thread_name[8] = " "; struct sys_thread *st; /** @todo Replace SYS_STACK_SIZE by "stacksize" parameter, perhaps use "name" if it is prefered */ p_stack = (u8_t *) malloc(SYS_STACK_SIZE); if (p_stack) { p_thread = (NU_TASK *) calloc(1,sizeof(NU_TASK)); if (p_thread) { /* get a new thread structure */ st = introduce_thread(p_thread, function, arg); if (st) { num_thread = (num_thread +1) % 100; // Only count to 99 sprintf(thread_name, "lwip%02d", num_thread); thread_name[strlen(thread_name)] = ' '; status = NU_Create_Task(p_thread, thread_name, sys_thread_entry, 0, st, p_stack, SYS_STACK_SIZE, prio, 0, //Disable timeslicing NU_PREEMPT, NU_START); if (status == NU_SUCCESS) return p_thread; } } } abort(); } /*-----------------------------------------------------------------------------------*/ static struct sys_thread * current_thread(void) { struct sys_thread *st; sys_prot_t old_level; NU_TASK *pt; pt = NU_Current_Task_Pointer(); old_level = sys_arch_protect(); for(st = threads; st != NULL; st = st->next) { if (st->pthread == pt) { sys_arch_unprotect(old_level); return st; } } sys_arch_unprotect(old_level); st = introduce_thread(pt, 0, 0); if (!st) { abort(); } return st; } /*---------------------------------------------------------------------------------*/ struct sys_timeouts * sys_arch_timeouts(void) { struct sys_thread *thread; thread = current_thread(); return &thread->timeouts; } /*---------------------------------------------------------------------------------*/ int * sys_arch_errno(void) { struct sys_thread *thread; thread = current_thread(); return &thread->errno_i; } /*---------------------------------------------------------------------------------*/ sys_sem_t sys_sem_new(u8_t count) { STATUS status; NU_SEMAPHORE *sem; char sem_name[8] = " "; #ifdef SYS_STATS lwip_stats.sys.sem.used++; if (lwip_stats.sys.sem.used > lwip_stats.sys.sem.max) { lwip_stats.sys.sem.max = lwip_stats.sys.sem.used; } #endif /* SYS_STATS */ /* Get memory for new semaphore */ sem = (NU_SEMAPHORE *) calloc(1,sizeof(NU_SEMAPHORE)); if (sem) { /* Create a unique name for semaphore based on number created */ num_sem = (num_sem + 1) % 100; // Only count to 99 sprintf(sem_name, "lwip%02d", num_sem); sem_name[strlen(sem_name)] = ' '; /* Ask nucleus to create semaphore */ NU_Create_Semaphore(sem, sem_name, count, NU_FIFO); } return sem; } /*---------------------------------------------------------------------------------*/ void sys_sem_free(sys_sem_t sem) { if (sem != SYS_SEM_NULL) { #ifdef SYS_STATS lwip_stats.sys.sem.used--; #endif /* SYS_STATS */ NU_Delete_Semaphore(sem); free(sem); } } /*---------------------------------------------------------------------------------*/ void sys_sem_signal(sys_sem_t sem) { NU_Release_Semaphore(sem); } /*---------------------------------------------------------------------------------*/ u32_t sys_arch_sem_wait(sys_sem_t sem, u32_t timeout) { UNSIGNED timestart, timespent; STATUS status; /* Get the current time */ timestart = NU_Retrieve_Clock(); /* Wait for the semaphore */ status = NU_Obtain_Semaphore(sem, timeout ? MS_TO_TICKS(timeout) : NU_SUSPEND); /* This next statement takes wraparound into account. It works. Really! */ timespent = TICKS_TO_HUNDMICROSEC(((s32_t) ((s32_t) NU_Retrieve_Clock() - (s32_t) timestart))); if (status == NU_TIMEOUT) return SYS_ARCH_TIMEOUT; else /* Round off to milliseconds */ return (timespent+5)/10; } /*---------------------------------------------------------------------------------*/ sys_mbox_t sys_mbox_new(void) { u32_t *p_queue_mem; NU_QUEUE *p_queue; char queue_name[8] = " "; /* Allocate memory for queue */ p_queue_mem = (u32_t *) calloc(1,(SYS_MBOX_SIZE * sizeof(u32_t))); if (p_queue_mem) { /* Allocate memory for queue control block */ p_queue = (NU_QUEUE *) calloc(1,sizeof(NU_QUEUE)); if (p_queue) { /* Create a unique name for mbox based on number created */ num_mbox = (num_mbox + 1) % 100; sprintf(queue_name, "lwip%02d", num_mbox); queue_name[strlen(queue_name)] = ' '; NU_Create_Queue(p_queue, queue_name, p_queue_mem, SYS_MBOX_SIZE, NU_FIXED_SIZE, 1, NU_FIFO); #ifdef SYS_STATS lwip_stats.sys.mbox.used++; if (lwip_stats.sys.mbox.used > lwip_stats.sys.mbox.max) { lwip_stats.sys.mbox.max = lwip_stats.sys.mbox.used; } #endif /* SYS_STATS */ return p_queue; } else free(p_queue_mem); } return SYS_MBOX_NULL; } /*---------------------------------------------------------------------------------*/ void sys_mbox_free(sys_mbox_t mbox) { VOID *p_queue_mem; CHAR name[8]; UNSIGNED queue_size; UNSIGNED available; UNSIGNED messages; OPTION message_type; UNSIGNED message_size; OPTION suspend_type; UNSIGNED tasks_waiting; NU_TASK *first_task; STATUS status; if (mbox != SYS_MBOX_NULL) { /* First we need to get address of queue memory. Ask Nucleus for information about the queue */ status = NU_Queue_Information(mbox, name, &p_queue_mem, &queue_size, &available, &messages, &message_type, &message_size, &suspend_type, &tasks_waiting, &first_task); if (status == NU_SUCCESS) free(p_queue_mem); NU_Delete_Queue(mbox); free(mbox); #ifdef SYS_STATS lwip_stats.sys.mbox.used--; #endif /* SYS_STATS */ } } /*--------------------------------------------------------------------------------- This function sends a message to a mailbox. It is unusual in that no error return is made. This is because the caller is responsible for ensuring that the mailbox queue will not fail. The caller does this by limiting the number of msg structures which exist for a given mailbox. ---------------------------------------------------------------------------------*/ void sys_mbox_post(sys_mbox_t mbox, void *msg) { UNSIGNED status; LWIP_DEBUGF(SYS_DEBUG, ("sys_mbox_post: mbox %p msg %p\n", mbox, msg)); status = NU_Send_To_Queue(mbox, &msg, 1, NU_NO_SUSPEND); LWIP_ASSERT("sys_mbox_post: mbx post failed", status == NU_SUCCESS); } /*---------------------------------------------------------------------------------*/ u32_t sys_arch_mbox_fetch(sys_mbox_t mbox, void **msg, u32_t timeout) { UNSIGNED timestart, timespent; STATUS status; void *ret_msg; UNSIGNED actual_size; /* Get the current time */ timestart = NU_Retrieve_Clock(); /* Wait for message */ status = NU_Receive_From_Queue(mbox, &ret_msg, 1, &actual_size, timeout ? MS_TO_TICKS(timeout) : NU_SUSPEND); if (status == NU_SUCCESS) { if (msg) *msg = ret_msg; LWIP_DEBUGF(SYS_DEBUG, ("sys_mbox_fetch: mbox %p msg %p\n", mbox, ret_msg)); } else { if (msg) *msg = 0; if (status == NU_TIMEOUT) LWIP_DEBUGF(SYS_DEBUG, ("sys_mbox_fetch: timeout on mbox %p\n", mbox)); else LWIP_DEBUGF(SYS_DEBUG, ("sys_mbox_fetch: Queue Error %i on mbox %p\n", status, mbox)); } /* This next statement takes wraparound into account. It works. Really! */ timespent = TICKS_TO_HUNDMICROSEC(((s32_t) ((s32_t) NU_Retrieve_Clock() - (s32_t) timestart))); if (status == NU_TIMEOUT) return SYS_ARCH_TIMEOUT; else /* Round off to milliseconds */ return (timespent+5)/10; } /*---------------------------------------------------------------------------------*/ static void sys_arch_lisr(INT vector_number) { struct sys_hisr *p_hisr = hisrs; /* Determine which HISR to activate */ while (p_hisr != NULL) { if (vector_number == p_hisr->vector) { if (p_hisr->disablefun) (*p_hisr->disablefun)(); NU_Activate_HISR(p_hisr->hisr); break; } p_hisr = p_hisr->next; } return; } /*---------------------------------------------------------------------------------*/ void sys_setvect(u32_t vector, void (*isr_function)(void), void (*dis_funct)(void)) { /* The passed function is called as a high level ISR on the selected vector. It is assumed that all the functions in this module can be called by the isr_function. */ struct sys_hisr *p_hisr = hisrs; INT old_level; NU_HISR *nucleus_hisr; u8_t *p_stack; STATUS status; char hisr_name[8] = " "; void (*old_lisr)(INT); /* In this case a Nucleus HISR is created for the isr_function. This * requires it's own stack. Also get memory for Nucleus HISR. */ nucleus_hisr = (NU_HISR *) calloc(1,sizeof(NU_HISR)); if (nucleus_hisr) { p_stack = (u8_t *) malloc(SYS_HISR_STACK_SIZE); if (p_stack) { /* It is most efficient to disable interrupts for Nucleus for a short time. Chances are we are doing this while interrupts are disabled already during system initialization. */ old_level = NU_Control_Interrupts(NU_DISABLE_INTERRUPTS); /* It is a simplification here that once an HISR is set up for a particular * vector it will never be set up again. This way if the init code is called * more than once it is harmless (no memory leaks) */ while (p_hisr != NULL) { if (vector == p_hisr->vector) { NU_Control_Interrupts(old_level); free(p_stack); free(nucleus_hisr); return; } p_hisr = p_hisr->next; } /* Get a sys_hisr structure */ p_hisr = (struct sys_hisr *) calloc(1,sizeof(struct sys_hisr)); if (p_hisr) { p_hisr->next = hisrs; p_hisr->vector = vector; p_hisr->hisr = nucleus_hisr; p_hisr->disablefun = dis_funct; hisrs = p_hisr; NU_Control_Interrupts(old_level); num_hisr = (num_hisr + 1) % 100; sprintf(hisr_name, "lwip%02d", num_hisr); hisr_name[strlen(hisr_name)] = ' '; /* Ask Nucleus to create the HISR */ status = NU_Create_HISR(p_hisr->hisr, hisr_name, isr_function, 1, //Priority 0-2 p_stack, SYS_HISR_STACK_SIZE); if (status == NU_SUCCESS) { /* Plug vector with system lisr now */ NU_Register_LISR(vector, sys_arch_lisr, &old_lisr); return; //Success } } NU_Control_Interrupts(old_level); } } /* Errors should be logged here */ abort(); } /*---------------------------------------------------------------------------------*/ /** sys_prot_t sys_arch_protect(void) This optional function does a "fast" critical region protection and returns the previous protection level. This function is only called during very short critical regions. An embedded system which supports ISR-based drivers might want to implement this function by disabling interrupts. Task-based systems might want to implement this by using a mutex or disabling tasking. This function should support recursive calls from the same task or interrupt. In other words, sys_arch_protect() could be called while already protected. In that case the return value indicates that it is already protected. sys_arch_protect() is only required if your port is supporting an operating system. */ sys_prot_t sys_arch_protect(void) { return NU_Control_Interrupts(NU_DISABLE_INTERRUPTS); } /*---------------------------------------------------------------------------------*/ /** void sys_arch_unprotect(sys_prot_t pval) This optional function does a "fast" set of critical region protection to the value specified by pval. See the documentation for sys_arch_protect() for more information. This function is only required if your port is supporting an operating system. */ void sys_arch_unprotect(sys_prot_t pval) { NU_Control_Interrupts(pval); } /********************************************************************* * void sys_get_eth_addr(struct eth_addr *eth_addr) * * Get configured ethernet address from nvram and return it * in a eth_addr structure. *********************************************************************/ void sys_get_eth_addr(struct eth_addr *eth_addr) { Cfg_lan *p_lan = config_get_lan_setup(); eth_addr->addr[0] = (u8_t) ((p_lan->etheraddrhi >> 16) & 0xff); eth_addr->addr[1] = (u8_t) ((p_lan->etheraddrhi >> 8) & 0xff); eth_addr->addr[2] = (u8_t) ((p_lan->etheraddrhi) & 0xff); eth_addr->addr[3] = (u8_t) ((p_lan->etheraddrlo >> 16) & 0xff); eth_addr->addr[4] = (u8_t) ((p_lan->etheraddrlo >> 8) & 0xff); eth_addr->addr[5] = (u8_t) ((p_lan->etheraddrlo) & 0xff); } ocproxy-1.60/contrib/ports/old/ecos/000077500000000000000000000000001303453231400174575ustar00rootroot00000000000000ocproxy-1.60/contrib/ports/old/ecos/README000066400000000000000000000027341303453231400203450ustar00rootroot00000000000000This part of the lwip-contrib section is the ecos glue Check out latest ecos from CVS (>= 19 Jan 2004) so it has the latest io/eth glue for lwip. You must have the current lwip sources checked out and the scripts here will hopefully generate a correct EPK suitable for use with ecos. To make an ecos package: Run the mkepk script something like this # EPK=/dir/of/epk LWIP_CVS=/dir/of/checked/out/lwip ./mkepk This will put the generated EPK in the dir you specify then add that EPK to your package repository and use it Build example: #ecosconfig new edb7xxx kernel #ecosconfig add lwip this will default to SLIP connection.If you also #ecosconfig add net_drivers you'll be able to configure for ethernet In both cases set LWIP_MY_ADDR and LWIP_SERV_ADDR (means host/gateway for eth or host/peer for slip) #ecosconfig tree #make tests and you can try any of the five tests included Tests: udpecho - echo service port 7 on UDP tcpecho - ditto on TCP sockets - as tcpecho but written with the socket API not the lwip specific API https - http server on port 80 written with the raw API nc_test_slave - a port of the test with the same name in net/common to lwip. Used to compare lwIP throughput to that of the FreeBSD stack.In this matchup lwIP gets a well deserved silver medal.Not bad for a newcomer ;) Bugreports (or even better patches) at jani@iv.ro not the lwip or ecos mailing lists!! Only if you peek into the lwip sources and think you found a bug post to lwip-users. ocproxy-1.60/contrib/ports/old/ecos/copy000077500000000000000000000007371303453231400203660ustar00rootroot00000000000000#!/bin/sh #make an ecos epk from CVS lwIP CURRENT=$EPK/net/lwip_tcpip/current mkdir -p `dirname $CURRENT/$2` #prepend eCos license text to all files but the ones #in the ppp directory: those have the advertising clause #type of BSD license which is not compatible with GPL #or that's what I'be been told and IANAL if [ "`dirname $1`" != "src/netif/ppp" ]; then #cat header $LWIP_CVS/$1 > $CURRENT/$2 cp -f $LWIP_CVS/$1 $CURRENT/$2 else cp -f $LWIP_CVS/$1 $CURRENT/$2 fi ocproxy-1.60/contrib/ports/old/ecos/ecos/000077500000000000000000000000001303453231400204105ustar00rootroot00000000000000ocproxy-1.60/contrib/ports/old/ecos/ecos/net/000077500000000000000000000000001303453231400211765ustar00rootroot00000000000000ocproxy-1.60/contrib/ports/old/ecos/ecos/net/lwip_tcpip/000077500000000000000000000000001303453231400233505ustar00rootroot00000000000000ocproxy-1.60/contrib/ports/old/ecos/ecos/net/lwip_tcpip/current/000077500000000000000000000000001303453231400250325ustar00rootroot00000000000000ocproxy-1.60/contrib/ports/old/ecos/ecos/net/lwip_tcpip/current/cdl/000077500000000000000000000000001303453231400255745ustar00rootroot00000000000000ocproxy-1.60/contrib/ports/old/ecos/ecos/net/lwip_tcpip/current/cdl/lwip_net.cdl000066400000000000000000000412431303453231400301050ustar00rootroot00000000000000#==================================================================== # # lwip_net.cdl # # lwIP network stack configuration data # # ==================================================================== #####ECOSGPLCOPYRIGHTBEGIN#### ## ------------------------------------------- ## This file is part of eCos, the Embedded Configurable Operating System. ## Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. ## Copyright (C) 2004 eCosCentric ## ## eCos is free software; you can redistribute it and/or modify it under ## the terms of the GNU General Public License as published by the Free ## Software Foundation; either version 2 or (at your option) any later version. ## ## eCos is distributed in the hope that it will be useful, but WITHOUT ANY ## WARRANTY; without even the implied warranty of MERCHANTABILITY or ## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ## for more details. ## ## You should have received a copy of the GNU General Public License along ## with eCos; if not, write to the Free Software Foundation, Inc., ## 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ## ## As a special exception, if other files instantiate templates or use macros ## or inline functions from this file, or you compile this file and link it ## with other works to produce a work based on this file, this file does not ## by itself cause the resulting work to be covered by the GNU General Public ## License. However the source code for this file must still be made available ## in accordance with section (3) of the GNU General Public License. ## ## This exception does not invalidate any other reasons why a work based on ## this file might be covered by the GNU General Public License. ## ## ------------------------------------------- #####ECOSGPLCOPYRIGHTEND#### # ==================================================================== ######DESCRIPTIONBEGIN#### # # Author(s): cris@iv.ro, jani@iv.ro # Original data: jani@iv.ro # Contributors: # Date: 2002-06-21 # #####DESCRIPTIONEND#### # # ==================================================================== cdl_package CYGPKG_NET_LWIP { display "lwIP" description "Lightweight TCP/IP stack" requires {(CYGPKG_LWIP_ETH == 1) || (CYGPKG_LWIP_SLIP == 1) || (CYGPKG_LWIP_PPP == 1)} compile core/mem.c \ core/memp.c \ core/netif.c \ core/pbuf.c \ core/stats.c \ core/sys.c \ core/tcp.c \ core/tcp_in.c \ core/tcp_out.c \ core/inet.c \ core/ipv4/icmp.c \ core/ipv4/ip.c \ core/ipv4/ip_addr.c \ core/ipv4/ip_frag.c \ api/api_lib.c \ api/api_msg.c \ api/tcpip.c \ api/err.c \ api/sockets.c \ ecos/sys_arch.c \ ecos/init.c cdl_component CYGPKG_LWIP_STATS { display "Turn ON/OFF statistics" flavor bool default_value 0 description " Check this box to turn ON statistics options for lwIP." } cdl_component CYGPKG_LWIP_DEBUG { display "Turn ON/OFF debug options" flavor bool default_value 0 description " Check this box to turn ON debug options for lwIP." cdl_option CYGPKG_LWIP_DEBUG_TCP { display "Control TCP debug" flavor bool default_value 0 description " Generic TCP debug switch." } } cdl_component CYGPKG_LWIP_ASSERTS { display "Turn ON/OFF assertions" flavor bool default_value 0 description " Check this box to turn ON assertions for lwIP." } cdl_component CYGPKG_LWIP_IPV4_CONF { display "IPV4 netconf" flavor none no_define description " See suboptions to define gateway IP, local IP and netmask." cdl_option CYGPKG_LWIP_SERV_ADDR { display "Gateway IP" flavor data default_value {"192,168,1,1"} description " Gateway's IP address." } cdl_option CYGPKG_LWIP_MY_ADDR { display "My IP" flavor data default_value {"192,168,1,222"} description " The IP address for this device." } cdl_option CYGPKG_LWIP_NETMASK { display "Netmask" flavor data default_value {"255,255,255,0"} description " Netmask of the local network." } } cdl_component CYGPKG_LWIP_MEM_OPTIONS { display "Memory options" flavor none no_define description " Tunables for various aspects of memory usage throughout the stack." cdl_option CYGPKG_LWIP_MEM_ALIGNMENT { display "Memory alignment" flavor data default_value 4 description " MEM_ALIGNMENT: should be set to the alignment of the CPU for which lwIP is compiled. 4 byte alignment -> define MEM_ALIGNMENT to 4, 2 byte alignment -> define MEM_ALIGNMENT to 2." } cdl_option CYGPKG_LWIP_MEM_SIZE { display "Memory size" flavor data default_value 4000 description " MEM_SIZE: the size of the heap memory. If the application will send a lot of data that needs to be copied, this should be set high." } cdl_option CYGPKG_LWIP_MEMP_NUM_PBUF { display "Number of memp struct pbufs" flavor data default_value 8 description " MEMP_NUM_PBUF: the number of memp struct pbufs. If the application sends a lot of data out of ROM (or other static memory), this should be set high." } cdl_option CYGPKG_LWIP_MEMP_NUM_UDP_PCB { display "Simultaneous UDP control blocks " flavor data default_value 4 description " MEMP_NUM_UDP_PCB: the number of UDP protocol control blocks. One per active UDP 'connection'." } cdl_option CYGPKG_LWIP_MEMP_NUM_TCP_PCB { display "Simultaneous active TCP connections " flavor data default_value 5 description " MEMP_NUM_TCP_PCB: the number of simulatenously active TCP connections." } cdl_option CYGPKG_LWIP_MEMP_NUM_TCP_PCB_LISTEN { display "Listening TCP connections" flavor data default_value 8 description " MEMP_NUM_TCP_PCB_LISTEN: the number of listening TCP connections." } cdl_option CYGPKG_LWIP_MEMP_NUM_TCP_SEG { display "Simultaneous TCP segments queued" flavor data default_value 8 description " MEMP_NUM_TCP_SEG: the number of simultaneously queued TCP segments." } cdl_option CYGPKG_LWIP_MEMP_NUM_SYS_TIMEOUT { display "Simultaneous active timeouts" flavor data default_value 3 description " MEMP_NUM_SYS_TIMEOUT: the number of simulateously active timeouts." } cdl_component CYGPKG_LWIP_CYGPKG_LWIP_MEM_SEQ_API { display "Sequential API settings" flavor none no_define description " The following four are used only with the sequential API and can be set to 0 if the application only will use the raw API." cdl_option CYGPKG_LWIP_MEMP_NUM_NETBUF { display "Struct netbufs" flavor data default_value 2 description " MEMP_NUM_NETBUF: the number of struct netbufs." } cdl_option CYGPKG_LWIP_MEMP_NUM_NETCONN { display "Struct netconns" flavor data default_value 4 description " MEMP_NUM_NETCONN: the number of struct netconns." } cdl_option CYGPKG_LWIP_MEMP_NUM_APIMSG { display "Struct api_msgs" flavor data default_value 8 description " MEMP_NUM_APIMSG: the number of struct api_msg, used for communication between the TCP/IP stack and the sequential programs." } cdl_option CYGPKG_LWIP_MEMP_NUM_TCPIP_MSG { display "Struct tcpip_msgs" flavor data default_value 8 description " MEMP_NUM_TCPIPMSG: the number of struct tcpip_msg, which is used for sequential API communication and incoming packets. Used in src/api/tcpip.c." } } } cdl_component CYGPKG_LWIP_PBUF_OPTIONS { display "PBUF" flavor none no_define description " Packet buffer related tunings." cdl_option CYGPKG_LWIP_PBUF_POOL_SIZE { display "PBUF pool size" flavor data default_value 60 description " PBUF_POOL_SIZE: the number of buffers in the pbuf pool." } cdl_option CYGPKG_LWIP_PBUF_POOL_BUFSIZE { display "PBUF buffer size" flavor data default_value 1024 description " PBUF_POOL_BUFSIZE: the size of each pbuf in the pbuf pool." } cdl_option CYGPKG_LWIP_PBUF_LINK_HLEN { display "Allocation for a link level header" flavor data calculated {CYGPKG_LWIP_SLIP || CYGPKG_LWIP_PPP ? 0 : 16} description " PBUF_LINK_HLEN: the number of bytes that should be allocated for a link level header." } } cdl_component CYGPKG_LWIP_TCP_OPTIONS { display "TCP" flavor none no_define description " Tune the TCP protocol details" cdl_option CYGPKG_LWIP_TCP { display "Activate TCP" flavor bool default_value 1 description "" } cdl_option CYGPKG_LWIP_TCPIP_THREAD_PRIORITY { display "tcpip thread priority" flavor data default_value 7 description "Pririty of the lwIP network thread.This thread handles all API messages and network packets." } cdl_option CYGPKG_LWIP_TCP_TTL { display "Time To Live" flavor data default_value 255 description "" } cdl_option CYGPKG_LWIP_TCP_QUEUE_OOSEQ { display "Queue segments" flavor bool default_value 1 description " Controls if TCP should queue segments that arrive out of order. Define to 0 if your device is low on memory." } cdl_option CYGPKG_LWIP_TCP_MSS { display "Maximum segment size" flavor data default_value 2048 description " TCP Maximum segment size." } cdl_option CYGPKG_LWIP_TCP_SND_BUF { display "Sender buffer space" flavor data default_value 2048 description " TCP sender buffer space (bytes)." } cdl_option CYGPKG_LWIP_TCP_SND_QUEUELEN { display "Sender pbufs" flavor data calculated "4 * CYGPKG_LWIP_TCP_SND_BUF/CYGPKG_LWIP_TCP_MSS" description " TCP sender buffer space (pbufs). This must be at least = 2 * TCP_SND_BUF/TCP_MSS for things to work." } cdl_option CYGPKG_LWIP_TCP_WND { display "Receive window" flavor data default_value 4096 description " TCP receive window." } cdl_option CYGPKG_LWIP_TCP_MAXRTX { display "Segment retransmissions" flavor data default_value 12 description " Maximum number of retransmissions of data segments." } cdl_option CYGPKG_LWIP_TCP_SYNMAXRTX { display "Syn retransmissions" flavor data default_value 4 description " Maximum number of retransmissions of SYN segments." } } cdl_component CYGPKG_LWIP_ARP_OPTIONS { display "ARP" flavor none no_define cdl_option CYGPKG_LWIP_ARP_TABLE_SIZE { display "ARP table size" flavor data default_value 10 description "" } } cdl_component CYGPKG_LWIP_IP { display "IP" flavor none no_define cdl_option CYGPKG_LWIP_IP_FORWARD { display "IP forwarding" flavor bool default_value 1 description " Define IP_FORWARD to 1 if you wish to have the ability to forward IP packets across network interfaces. If you are going to run lwIP on a device with only one network interface, define this to 0." } cdl_option CYGPKG_LWIP_IP_OPTIONS { display "Allow IP options" flavor bool default_value 1 description " If defined to 1, IP options are allowed (but not parsed). If defined to 0, all packets with IP options are dropped." } cdl_option CYGPKG_LWIP_IP_FRAG { display "Support IP fragmentation" flavor bool default_value 1 description " " } cdl_option CYGPKG_LWIP_IP_REASS { display "Support IP reassembly" flavor bool default_value 1 description " " } } cdl_component CYGPKG_LWIP_ICMP_OPTIONS { display "ICMP" flavor none no_define cdl_option CYGPKG_LWIP_ICMP_TTL { display "ICMP Time To Live" flavor data default_value 255 description "" } } cdl_component CYGPKG_LWIP_DHCP_OPTIONS { display "DHCP" flavor none no_define cdl_option CYGPKG_LWIP_DHCP { display "Activate DHCP" flavor bool default_value 0 description " Define LWIP_DHCP to 1 if you want DHCP configuration of interfaces." compile core/dhcp.c } cdl_option CYGPKG_LWIP_DHCP_DOES_ARP_CHECK { display "Check offered address" flavor bool default_value 0 description " 1 if you want to do an ARP check on the offered address (recommended)." } } cdl_component CYGPKG_LWIP_LOOPIF { display "Support loop interface (127.0.0.1)" flavor bool default_value 1 compile netif/loopif.c } cdl_component CYGPKG_LWIP_ETH { display "Ethernet support" flavor bool requires CYGPKG_IO_ETH_DRIVERS default_value 1 description "Ethernet support" compile netif/etharp.c cdl_option CYGPKG_LWIP_ETH_THREAD_PRIORITY { display "ethernet input thread priority" flavor data default_value 6 description "Priority of the ethernet input thread" } } cdl_component CYGPKG_LWIP_SLIP { display "SLIP" flavor bool requires CYGPKG_IO_SERIAL_DEVICES default_value 0 description "IP over Serial Line" compile netif/slipif.c ecos/sio.c cdl_option CYGPKG_LWIP_SLIPIF_THREAD_PRIORITY { display "SLIP thread priority" flavor data default_value 8 description "Priority of the SLIP input thread" } cdl_option CYGPKG_LWIP_SLIP_DEV { display "Serial device" flavor data default_value {"\"/dev/ser0\""} description " Which serial port to use SLIP on." } } cdl_component CYGPKG_LWIP_PPP { display "PPP" flavor bool requires CYGPKG_IO_SERIAL_DEVICES default_value 0 description "The Point-to-Point Protocol" compile netif/ppp/ppp.c \ netif/ppp/auth.c \ netif/ppp/chpms.c \ netif/ppp/fsm.c \ netif/ppp/ipcp.c \ netif/ppp/lcp.c \ netif/ppp/magic.c \ netif/ppp/md5.c \ netif/ppp/randm.c \ netif/ppp/vj.c \ ecos/sio.c cdl_option CYGPKG_LWIP_PPP_PAP_AUTH { display "Support PAP authentication" flavor bool default_value 1 compile netif/ppp/pap.c } cdl_option CYGPKG_LWIP_PPP_CHAP_AUTH { display "Support CHAP authentication" flavor bool default_value 1 compile netif/ppp/chap.c } cdl_option CYGPKG_LWIP_PPP_DEV { display "Serial device for PPP" flavor data default_value {"\"/dev/ser0\""} description " Which serial port to use PPP on." } cdl_option CYGPKG_LWIP_PPP_THREAD_PRIORITY { display "PPP main thread priority" flavor data default_value 8 description "Priority of the PPP input thread" } } cdl_component CYGPKG_LWIP_UDP_OPTIONS { display "UDP" flavor none no_define cdl_option CYGPKG_LWIP_UDP { display "Activate UDP" flavor bool default_value 1 description "" compile core/udp.c } cdl_option CYGPKG_LWIP_UDP_TTL { display "Time To Live" flavor data default_value 255 description "" } } cdl_option CYGPKG_LWIP_RAW { display "Enable RAW socket support" flavor bool default_value 1 description "" compile core/raw.c } cdl_component CYGPKG_LWIP_APP_MEM_OPTIONS { display "Memory options for apps" flavor none no_define description "Memory options for applications." cdl_option CYGNUM_LWIP_VARMEMPOOL_SIZE { display "Size of variable memory pool" flavor data default_value 2048 description " Memory required to hold semaphore, mbox and thread structures are allocated from this memory pool. " } cdl_option CYGNUM_LWIP_APP_THREADS { display "Number of network threads in application" flavor data default_value 1 description " At startup at least two lwIP threads are created:the polling(input) thread and the TCP/IP (output) thread.Additionally your application creates one or more threads. Set this option to the maximum number of threads you will create through sys_thread_new().Threads which you create through cyg_thread_create() are not lwIP threads and don't count.This number is needed so that enough static memory is reserved for stack space. " } cdl_option CYGNUM_LWIP_THREAD_STACK_SIZE { display "Size of per thread stack in lwIP" flavor data default_value 4096 description " Since stack space for threads needs to be statically allocated you can specify the amount of memory to use for each network thread. " } } cdl_option CYGPKG_NET_LWIP_TESTS { display "Some lwIP tests" flavor data no_define calculated { "tests/tcpecho tests/udpecho tests/httpd tests/socket tests/nc_test_slave tests/sys_timeout" } description " This option specifies the set of tests for lwIP.They show the usage of the raw, the sequential and the BSD socket compatible APIs" } } ocproxy-1.60/contrib/ports/old/ecos/ecos/net/lwip_tcpip/current/include/000077500000000000000000000000001303453231400264555ustar00rootroot00000000000000ocproxy-1.60/contrib/ports/old/ecos/ecos/net/lwip_tcpip/current/include/arch/000077500000000000000000000000001303453231400273725ustar00rootroot00000000000000ocproxy-1.60/contrib/ports/old/ecos/ecos/net/lwip_tcpip/current/include/arch/cc.h000066400000000000000000000111331303453231400301270ustar00rootroot00000000000000//========================================================================== //####ECOSGPLCOPYRIGHTBEGIN#### // ------------------------------------------- // This file is part of eCos, the Embedded Configurable Operating System. // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. // // eCos is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the Free // Software Foundation; either version 2 or (at your option) any later version. // // eCos is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License // for more details. // // You should have received a copy of the GNU General Public License along // with eCos; if not, write to the Free Software Foundation, Inc., // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. // // As a special exception, if other files instantiate templates or use macros // or inline functions from this file, or you compile this file and link it // with other works to produce a work based on this file, this file does not // by itself cause the resulting work to be covered by the GNU General Public // License. However the source code for this file must still be made available // in accordance with section (3) of the GNU General Public License. // // This exception does not invalidate any other reasons why a work based on // this file might be covered by the GNU General Public License. // ------------------------------------------- //####ECOSGPLCOPYRIGHTEND#### //========================================================================== /* * Copyright (c) 2001, Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the Institute nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #ifndef __ARCH_CC_H__ #define __ARCH_CC_H__ #include #include //while EFAULT should have no meaning in eCos since there are no address spaces //it is defined here because set/getsockopt in lwIP use it. #define EFAULT 14 //found no better place for this prototype int lwip_init(void); //#define LWIP_PROVIDE_ERRNO #include #if (CYG_BYTEORDER == CYG_LSBFIRST) #define BYTE_ORDER LITTLE_ENDIAN #else #define BYTE_ORDER BIG_ENDIAN #endif typedef unsigned char u8_t; typedef signed char s8_t; typedef unsigned short u16_t; typedef signed short s16_t; typedef unsigned long u32_t; typedef signed long s32_t; typedef unsigned long mem_ptr_t; #define U16_F "hu" #define S16_F "hd" #define X16_F "hx" #define U32_F "lu" #define S32_F "ld" #define X32_F "lx" #define PACK_STRUCT_FIELD(x) x __attribute__((packed)) #define PACK_STRUCT_STRUCT __attribute__((packed)) #define PACK_STRUCT_BEGIN #define PACK_STRUCT_END #include #include #define LWIP_PLATFORM_DIAG(x) {diag_printf x;} #define LWIP_PLATFORM_ASSERT(x) {CYG_FAIL(x);} #define SYS_ARCH_DECL_PROTECT(x) #define SYS_ARCH_PROTECT(x) #define SYS_ARCH_UNPROTECT(x) #endif /* __ARCH_CC_H__ */ ocproxy-1.60/contrib/ports/old/ecos/ecos/net/lwip_tcpip/current/include/arch/perf.h000066400000000000000000000067711303453231400305120ustar00rootroot00000000000000//========================================================================== //####ECOSGPLCOPYRIGHTBEGIN#### // ------------------------------------------- // This file is part of eCos, the Embedded Configurable Operating System. // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. // // eCos is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the Free // Software Foundation; either version 2 or (at your option) any later version. // // eCos is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License // for more details. // // You should have received a copy of the GNU General Public License along // with eCos; if not, write to the Free Software Foundation, Inc., // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. // // As a special exception, if other files instantiate templates or use macros // or inline functions from this file, or you compile this file and link it // with other works to produce a work based on this file, this file does not // by itself cause the resulting work to be covered by the GNU General Public // License. However the source code for this file must still be made available // in accordance with section (3) of the GNU General Public License. // // This exception does not invalidate any other reasons why a work based on // this file might be covered by the GNU General Public License. // ------------------------------------------- //####ECOSGPLCOPYRIGHTEND#### //========================================================================== /* * Copyright (c) 2001, Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the Institute nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #ifndef __PERF_H__ #define __PERF_H__ #define PERF_START /* null definition */ #define PERF_STOP(x) /* null definition */ #endif /* __PERF_H__ */ ocproxy-1.60/contrib/ports/old/ecos/ecos/net/lwip_tcpip/current/include/arch/sys_arch.h000066400000000000000000000037251303453231400313650ustar00rootroot00000000000000//========================================================================== //####ECOSGPLCOPYRIGHTBEGIN#### // ------------------------------------------- // This file is part of eCos, the Embedded Configurable Operating System. // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. // // eCos is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the Free // Software Foundation; either version 2 or (at your option) any later version. // // eCos is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License // for more details. // // You should have received a copy of the GNU General Public License along // with eCos; if not, write to the Free Software Foundation, Inc., // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. // // As a special exception, if other files instantiate templates or use macros // or inline functions from this file, or you compile this file and link it // with other works to produce a work based on this file, this file does not // by itself cause the resulting work to be covered by the GNU General Public // License. However the source code for this file must still be made available // in accordance with section (3) of the GNU General Public License. // // This exception does not invalidate any other reasons why a work based on // this file might be covered by the GNU General Public License. // ------------------------------------------- //####ECOSGPLCOPYRIGHTEND#### //========================================================================== #ifndef __SYS_ECOS_H__ #define __SYS_ECOS_H__ #include #define SYS_MBOX_NULL (sys_mbox_t)NULL #define SYS_SEM_NULL (sys_sem_t)NULL typedef cyg_sem_t * sys_sem_t; typedef cyg_handle_t sys_mbox_t; typedef cyg_thread * sys_thread_t; #endif /* __SYS_ECOS_H__ */ ocproxy-1.60/contrib/ports/old/ecos/ecos/net/lwip_tcpip/current/include/lwipopts.h000066400000000000000000000245031303453231400305130ustar00rootroot00000000000000//========================================================================== //####ECOSGPLCOPYRIGHTBEGIN#### // ------------------------------------------- // This file is part of eCos, the Embedded Configurable Operating System. // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. // // eCos is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the Free // Software Foundation; either version 2 or (at your option) any later version. // // eCos is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License // for more details. // // You should have received a copy of the GNU General Public License along // with eCos; if not, write to the Free Software Foundation, Inc., // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. // // As a special exception, if other files instantiate templates or use macros // or inline functions from this file, or you compile this file and link it // with other works to produce a work based on this file, this file does not // by itself cause the resulting work to be covered by the GNU General Public // License. However the source code for this file must still be made available // in accordance with section (3) of the GNU General Public License. // // This exception does not invalidate any other reasons why a work based on // this file might be covered by the GNU General Public License. // ------------------------------------------- //####ECOSGPLCOPYRIGHTEND#### //========================================================================== /* * Copyright (c) 2001, Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the Institute nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #ifndef __LWIPOPTS_H__ #define __LWIPOPTS_H__ /*include the configuration made with configtool*/ #include /* ---------- Memory options ---------- */ /* MEM_ALIGNMENT: should be set to the alignment of the CPU for which lwIP is compiled. 4 byte alignment -> define MEM_ALIGNMENT to 4, 2 byte alignment -> define MEM_ALIGNMENT to 2. */ #define MEM_ALIGNMENT CYGPKG_LWIP_MEM_ALIGNMENT /* MEM_SIZE: the size of the heap memory. If the application will send a lot of data that needs to be copied, this should be set high. */ #define MEM_SIZE CYGPKG_LWIP_MEM_SIZE /* MEMP_NUM_PBUF: the number of memp struct pbufs. If the application sends a lot of data out of ROM (or other static memory), this should be set high. */ #define MEMP_NUM_PBUF CYGPKG_LWIP_MEMP_NUM_PBUF /* MEMP_NUM_UDP_PCB: the number of UDP protocol control blocks. One per active UDP "connection". */ #define MEMP_NUM_UDP_PCB CYGPKG_LWIP_MEMP_NUM_UDP_PCB /* MEMP_NUM_TCP_PCB: the number of simulatenously active TCP connections. */ #define MEMP_NUM_TCP_PCB CYGPKG_LWIP_MEMP_NUM_TCP_PCB /* MEMP_NUM_TCP_PCB_LISTEN: the number of listening TCP connections. */ #define MEMP_NUM_TCP_PCB_LISTEN CYGPKG_LWIP_MEMP_NUM_TCP_PCB_LISTEN /* MEMP_NUM_TCP_SEG: the number of simultaneously queued TCP segments. */ #define MEMP_NUM_TCP_SEG CYGPKG_LWIP_MEMP_NUM_TCP_SEG /* MEMP_NUM_SYS_TIMEOUT: the number of simulateously active timeouts. */ #define MEMP_NUM_SYS_TIMEOUT CYGPKG_LWIP_MEMP_NUM_SYS_TIMEOUT /* The following four are used only with the sequential API and can be set to 0 if the application only will use the raw API. */ /* MEMP_NUM_NETBUF: the number of struct netbufs. */ #define MEMP_NUM_NETBUF CYGPKG_LWIP_MEMP_NUM_NETBUF /* MEMP_NUM_NETCONN: the number of struct netconns. */ #define MEMP_NUM_NETCONN CYGPKG_LWIP_MEMP_NUM_NETCONN /* MEMP_NUM_TCPIP_MSG: the number of struct tcpip_msg, which is used for sequential API communication and incoming packets. Used in src/api/tcpip.c. */ #define MEMP_NUM_TCPIP_MSG_API CYGPKG_LWIP_MEMP_NUM_TCPIP_MSG #define MEMP_NUM_TCPIP_MSG_INPKT CYGPKG_LWIP_MEMP_NUM_TCPIP_MSG /* ---------- Pbuf options ---------- */ /* PBUF_POOL_SIZE: the number of buffers in the pbuf pool. */ #define PBUF_POOL_SIZE CYGPKG_LWIP_PBUF_POOL_SIZE /* PBUF_POOL_BUFSIZE: the size of each pbuf in the pbuf pool. */ #define PBUF_POOL_BUFSIZE CYGPKG_LWIP_PBUF_POOL_BUFSIZE /* PBUF_LINK_HLEN: the number of bytes that should be allocated for a link level header. */ #define PBUF_LINK_HLEN CYGPKG_LWIP_PBUF_LINK_HLEN /* ---------- TCP options ---------- */ #define LWIP_TCP defined (CYGPKG_LWIP_TCP) #define TCP_TTL CYGPKG_LWIP_TCP_TTL /* Controls if TCP should queue segments that arrive out of order. Define to 0 if your device is low on memory. */ #define TCP_QUEUE_OOSEQ CYGPKG_LWIP_TCP_QUEUE_OOSEQ /* TCP Maximum segment size. */ #define TCP_MSS CYGPKG_LWIP_TCP_MSS /* TCP sender buffer space (bytes). */ #define TCP_SND_BUF CYGPKG_LWIP_TCP_SND_BUF #define TCP_SNDLOWAT TCP_SND_BUF/2 /* TCP sender buffer space (pbufs). This must be at least = 2 * TCP_SND_BUF/TCP_MSS for things to work. */ #define TCP_SND_QUEUELEN CYGPKG_LWIP_TCP_SND_QUEUELEN /* TCP receive window. */ #define TCP_WND CYGPKG_LWIP_TCP_WND /* Maximum number of retransmissions of data segments. */ #define TCP_MAXRTX CYGPKG_LWIP_TCP_MAXRTX /* Maximum number of retransmissions of SYN segments. */ #define TCP_SYNMAXRTX CYGPKG_LWIP_TCP_SYNMAXRTX /* ---------- ARP options ---------- */ #define ARP_TABLE_SIZE CYGPKG_LWIP_ARP_TABLE_SIZE /* ---------- IP options ---------- */ /* Define IP_FORWARD to 1 if you wish to have the ability to forward IP packets across network interfaces. If you are going to run lwIP on a device with only one network interface, define this to 0. */ #define IP_FORWARD CYGPKG_LWIP_IP_FORWARD /* If defined to 1, IP options are allowed (but not parsed). If defined to 0, all packets with IP options are dropped. */ #define IP_OPTIONS CYGPKG_LWIP_IP_OPTIONS /* ---------- ICMP options ---------- */ #define ICMP_TTL CYGPKG_LWIP_ICMP_TTL /* ---------- DHCP options ---------- */ /* Define LWIP_DHCP to 1 if you want DHCP configuration of interfaces.*/ #ifdef CYGPKG_LWIP_DHCP #define LWIP_DHCP CYGPKG_LWIP_DHCP /* 1 if you want to do an ARP check on the offered address (recommended). */ #define DHCP_DOES_ARP_CHECK CYGPKG_LWIP_DHCP_DOES_ARP_CHECK #endif /* ---------- UDP options ---------- */ #define LWIP_UDP CYGPKG_LWIP_UDP #define UDP_TTL CYGPKG_LWIP_UDP_TTL /* ---------- RAW socket support ---------- */ #define LWIP_RAW CYGPKG_LWIP_RAW /* ---------- SLIP options --------- */ #define LWIP_SLIP defined(CYGPKG_LWIP_SLIP) #define SLIP_DEV CYGPKG_LWIP_SLIP_DEV #define LWIP_HAVE_LOOPIF defined (CYGPKG_LWIP_LOOPIF) /* ---------- PPP options --------- */ #define PPP_SUPPORT defined(CYGPKG_LWIP_PPP) #define PPP_DEV CYGPKG_LWIP_PPP_DEV #define MD5_SUPPORT 1 #if defined(CYGPKG_LWIP_PPP_PAP_AUTH) #define PAP_SUPPORT 1 #else #define PAP_SUPPORT 0 #endif #if defined(CYGPKG_LWIP_PPP_CHAP_AUTH) #define CHAP_SUPPORT 1 #else #define CHAP_SUPPORT 0 #endif /* ------- Thread priorities ---------------*/ #define TCPIP_THREAD_PRIO CYGPKG_LWIP_TCPIP_THREAD_PRIORITY #define SLIPIF_THREAD_PRIO CYGPKG_LWIP_SLIPIF_THREAD_PRIORITY #define PPP_THREAD_PRIO CYGPKG_LWIP_PPP_THREAD_PRIORITY /* ---------- Statistics options ---------- */ #define LWIP_STATS defined(CYGPKG_LWIP_STATS) /* ---------- Debug options ---------- */ #if !defined(CYGPKG_LWIP_ASSERTS) #define LWIP_NOASSERT #endif #if defined(CYGPKG_LWIP_DEBUG) #define LWIP_DEBUG #define MEM_DEBUG LWIP_DBG_ON #define MEMP_DEBUG LWIP_DBG_ON #define PBUF_DEBUG LWIP_DBG_ON #define API_LIB_DEBUG LWIP_DBG_ON #define API_MSG_DEBUG LWIP_DBG_ON #define TCPIP_DEBUG LWIP_DBG_ON #define NETIF_DEBUG LWIP_DBG_ON #define SOCKETS_DEBUG LWIP_DBG_ON #define DEMO_DEBUG LWIP_DBG_ON #define IP_DEBUG LWIP_DBG_ON #define IP_REASS_DEBUG LWIP_DBG_ON #define RAW_DEBUG LWIP_DBG_ON #define ICMP_DEBUG LWIP_DBG_ON #define UDP_DEBUG LWIP_DBG_ON #define TCP_DEBUG LWIP_DBG_ON #define TCP_INPUT_DEBUG LWIP_DBG_ON #define TCP_OUTPUT_DEBUG LWIP_DBG_ON #define TCP_RTO_DEBUG LWIP_DBG_ON #define TCP_CWND_DEBUG LWIP_DBG_ON #define TCP_WND_DEBUG LWIP_DBG_ON #define TCP_FR_DEBUG LWIP_DBG_ON #define TCP_QLEN_DEBUG LWIP_DBG_ON #define TCP_RST_DEBUG LWIP_DBG_ON #define PPP_DEBUG LWIP_DBG_ON #define LWIP_DBG_TYPES_ON (LWIP_DBG_ON|LWIP_DBG_TRACE|LWIP_DBG_STATE|LWIP_DBG_FRESH|LWIP_DBG_HALT) #endif #endif /* __LWIPOPTS_H__ */ ocproxy-1.60/contrib/ports/old/ecos/ecos/net/lwip_tcpip/current/include/network.h000066400000000000000000000003171303453231400303200ustar00rootroot00000000000000/* network.h for compatibility with the other eCos network stacks */ #include /* lwIP stack includes */ #define LWIP_COMPAT_SOCKETS 1 #include #include ocproxy-1.60/contrib/ports/old/ecos/ecos/net/lwip_tcpip/current/src/000077500000000000000000000000001303453231400256215ustar00rootroot00000000000000ocproxy-1.60/contrib/ports/old/ecos/ecos/net/lwip_tcpip/current/src/ecos/000077500000000000000000000000001303453231400265525ustar00rootroot00000000000000ocproxy-1.60/contrib/ports/old/ecos/ecos/net/lwip_tcpip/current/src/ecos/init.c000066400000000000000000000142601303453231400276640ustar00rootroot00000000000000//========================================================================== //####ECOSGPLCOPYRIGHTBEGIN#### // ------------------------------------------- // This file is part of eCos, the Embedded Configurable Operating System. // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. // // eCos is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the Free // Software Foundation; either version 2 or (at your option) any later version. // // eCos is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License // for more details. // // You should have received a copy of the GNU General Public License along // with eCos; if not, write to the Free Software Foundation, Inc., // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. // // As a special exception, if other files instantiate templates or use macros // or inline functions from this file, or you compile this file and link it // with other works to produce a work based on this file, this file does not // by itself cause the resulting work to be covered by the GNU General Public // License. However the source code for this file must still be made available // in accordance with section (3) of the GNU General Public License. // // This exception does not invalidate any other reasons why a work based on // this file might be covered by the GNU General Public License. // ------------------------------------------- //####ECOSGPLCOPYRIGHTEND#### //========================================================================== /* * init.c - misc lwip ecos glue functions */ #include #include "lwip/opt.h" #include "lwip/sys.h" #include "lwip/memp.h" #include "lwip/tcpip.h" #include "lwip/ip_addr.h" #if LWIP_DHCP #include "lwip/dhcp.h" #endif #if LWIP_SLIP #include "netif/slipif.h" #endif #if PPP_SUPPORT #include "netif/ppp/ppp.h" #endif #include "netif/loopif.h" #include #include #ifdef CYGPKG_LWIP_ETH #include "netif/etharp.h" #include #include // Define table boundaries CYG_HAL_TABLE_BEGIN(__NETDEVTAB__, netdev); CYG_HAL_TABLE_END(__NETDEVTAB_END__, netdev); static void ecosglue_init(void); #endif void inline IP_ADDR(struct ip_addr *ipaddr, char a, char b, char c, char d) { IP4_ADDR(ipaddr,a,b,c,d); } void tcpip_init_done(void * arg) { sys_sem_t *sem = arg; sys_sem_signal(*sem); } struct netif mynetif, loopif; void lwip_set_addr(struct netif *netif); #if PPP_SUPPORT #define PPP_USER "pppuser" #define PPP_PASS "ppppass" void pppMyCallback(void *a , int e, void * arg) { diag_printf("callback %d \n",e); } /* These temporarily here */ unsigned long sys_jiffies(void) { return cyg_current_time(); } void ppp_trace(int level, const char *format,...) { va_list args; (void)level; va_start(args, format); diag_vprintf(format, args); va_end(args); } #endif #if LWIP_HAVE_LOOPIF struct netif ecos_loopif; #endif /* * Called by the eCos application at startup * wraps various init calls */ int lwip_init(void) { struct ip_addr ipaddr, netmask, gw; static int inited = 0; sys_sem_t sem; if (inited) return 1; inited++; sys_init(); /* eCos specific initialization */ mem_init(); /* heap based memory allocator */ memp_init(); /* pool based memory allocator */ pbuf_init(); /* packet buffer allocator */ netif_init(); /* netif layer */ /* Start the stack.It will spawn a new dedicated thread */ sem = sys_sem_new(0); tcpip_init(tcpip_init_done,&sem); sys_sem_wait(sem); sys_sem_free(sem); #if LWIP_HAVE_LOOPIF IP4_ADDR(&gw, 127,0,0,1); IP4_ADDR(&ipaddr, 127,0,0,1); IP4_ADDR(&netmask, 255,0,0,0); netif_add(&ecos_loopif, &ipaddr, &netmask, &gw, NULL, loopif_init, tcpip_input); #endif #if LWIP_SLIP lwip_set_addr(&mynetif); slipif_init(&mynetif); netif_set_default(&mynetif); #elif PPP_SUPPORT pppInit(); #if PAP_SUPPORT || CHAP_SUPPORT pppSetAuth(PPPAUTHTYPE_PAP, PPP_USER, PPP_PASS); #endif pppOpen(sio_open(2), pppMyCallback, NULL); #else ecosglue_init(); #endif return 0; } void lwip_set_addr(struct netif *netif) { struct ip_addr ipaddr, netmask, gw; IP_ADDR(&gw, CYGPKG_LWIP_SERV_ADDR); IP_ADDR(&ipaddr, CYGPKG_LWIP_MY_ADDR); IP_ADDR(&netmask, CYGPKG_LWIP_NETMASK); netif_set_addr(netif, &ipaddr, &netmask, &gw); netif->next = netif_list; netif_list = netif; netif->input = tcpip_input; //netif->input = ip_input; } #ifdef CYGPKG_LWIP_ETH //io eth stuff cyg_sem_t delivery; void lwip_dsr_stuff(void) { cyg_semaphore_post(&delivery); } //Input thread signalled by DSR calls deliver() on low level drivers static void input_thread(void *arg) { cyg_netdevtab_entry_t *t; for (;;) { cyg_semaphore_wait(&delivery); for (t = &__NETDEVTAB__[0]; t != &__NETDEVTAB_END__; t++) { struct eth_drv_sc *sc = (struct eth_drv_sc *)t->device_instance; if (sc->state & ETH_DRV_NEEDS_DELIVERY) { #if defined(CYGDBG_HAL_DEBUG_GDB_CTRLC_SUPPORT) cyg_bool was_ctrlc_int; #endif sc->state &= ~ETH_DRV_NEEDS_DELIVERY; #if defined(CYGDBG_HAL_DEBUG_GDB_CTRLC_SUPPORT) was_ctrlc_int = HAL_CTRLC_CHECK((*sc->funs->int_vector)(sc), (int)sc); if (!was_ctrlc_int) // Fall through and run normal code #endif (sc->funs->deliver) (sc); } } } } // Initialize all network devices static void init_hw_drivers(void) { cyg_netdevtab_entry_t *t; for (t = &__NETDEVTAB__[0]; t != &__NETDEVTAB_END__; t++) { if (t->init(t)) { t->status = CYG_NETDEVTAB_STATUS_AVAIL; } else { // What to do if device init fails? t->status = 0; // Device not [currently] available } } } static void arp_timer(void *arg) { etharp_tmr(); sys_timeout(ARP_TMR_INTERVAL, (sys_timeout_handler) arp_timer, NULL); } static void ecosglue_init(void) { cyg_semaphore_init(&delivery, 0); init_hw_drivers(); sys_thread_new("input_thread", input_thread, (void*)0, DEFAULT_THREAD_STACKSIZE, CYGPKG_LWIP_ETH_THREAD_PRIORITY); etharp_init(); sys_timeout(ARP_TMR_INTERVAL, (sys_timeout_handler) arp_timer, NULL); } #endif //CYGPKG_LWIP_ETH ocproxy-1.60/contrib/ports/old/ecos/ecos/net/lwip_tcpip/current/src/ecos/sio.c000066400000000000000000000054621303453231400275170ustar00rootroot00000000000000//========================================================================== //####ECOSGPLCOPYRIGHTBEGIN#### // ------------------------------------------- // This file is part of eCos, the Embedded Configurable Operating System. // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. // // eCos is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the Free // Software Foundation; either version 2 or (at your option) any later version. // // eCos is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License // for more details. // // You should have received a copy of the GNU General Public License along // with eCos; if not, write to the Free Software Foundation, Inc., // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. // // As a special exception, if other files instantiate templates or use macros // or inline functions from this file, or you compile this file and link it // with other works to produce a work based on this file, this file does not // by itself cause the resulting work to be covered by the GNU General Public // License. However the source code for this file must still be made available // in accordance with section (3) of the GNU General Public License. // // This exception does not invalidate any other reasons why a work based on // this file might be covered by the GNU General Public License. // ------------------------------------------- //####ECOSGPLCOPYRIGHTEND#### //========================================================================== /* Serial operations for SLIP */ #include "lwip/opt.h" #include "lwip/def.h" #include "lwip/sys.h" #include "lwip/netif.h" #include #include #include static cyg_io_handle_t ser; static int len; void sio_send(char c,void * dev) { len = 1; cyg_io_write(*(cyg_io_handle_t*)dev, &c, &len); } char sio_recv(void * dev) { char c; len = 1; cyg_io_read(*(cyg_io_handle_t *)dev, &c, &len); return c; } int sio_write(void *dev, char *b, int size) { int len = size; cyg_io_write(*(cyg_io_handle_t*)dev, b, &len); return len; } int sio_read(void *dev, char *b, int size) { int len = size; cyg_io_read(*(cyg_io_handle_t*)dev, b, &len); return len; } void * sio_open(int devnum) { int res; cyg_uint32 nb = 0, len = 4; #if LWIP_SLIP #define SIODEV SLIP_DEV #elif PPP_SUPPORT #define SIODEV PPP_DEV #endif res = cyg_io_lookup(SIODEV, &ser); if (res != ENOERR) diag_printf("Cannot open %s\n", SIODEV); res = cyg_io_set_config(ser, CYG_IO_SET_CONFIG_READ_BLOCKING, &nb, &len); return &ser; } void sio_read_abort(void * dev) { diag_printf("Abort called\n"); } ocproxy-1.60/contrib/ports/old/ecos/ecos/net/lwip_tcpip/current/src/ecos/sys_arch.c000066400000000000000000000157341303453231400305430ustar00rootroot00000000000000//========================================================================== //####ECOSGPLCOPYRIGHTBEGIN#### // ------------------------------------------- // This file is part of eCos, the Embedded Configurable Operating System. // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. // // eCos is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the Free // Software Foundation; either version 2 or (at your option) any later version. // // eCos is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License // for more details. // // You should have received a copy of the GNU General Public License along // with eCos; if not, write to the Free Software Foundation, Inc., // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. // // As a special exception, if other files instantiate templates or use macros // or inline functions from this file, or you compile this file and link it // with other works to produce a work based on this file, this file does not // by itself cause the resulting work to be covered by the GNU General Public // License. However the source code for this file must still be made available // in accordance with section (3) of the GNU General Public License. // // This exception does not invalidate any other reasons why a work based on // this file might be covered by the GNU General Public License. // ------------------------------------------- //####ECOSGPLCOPYRIGHTEND#### //========================================================================== // Author: Jani Monoses // Contributors: Claudio Leonel Salvadori // /* * This file implements the eCos specific sys_arch functions used by lwIP */ #include "lwip/opt.h" #include "arch/sys_arch.h" #include "lwip/sys.h" #include "lwip/def.h" //FIXME use CYG_HWR_whatever for RTC /* lwIp timeouts are milliseconds, eCos time unit is clock tick */ //1s = 1000ms = 100ticks (eCos default is 100 tick per second for most(all?) platforms) #define tick_to_msec(tick) ((u16_t)((tick)*10+1)) #define msec_to_tick(msec) ((cyg_tick_count_t)(msec+9)/10) /* We use a common var mempool for allocating semaphores, mboxes and threads... */ static char memvar[CYGNUM_LWIP_VARMEMPOOL_SIZE]; static cyg_mempool_var var_mempool; static cyg_handle_t var_mempool_h; #define SYS_THREADS 2 /* polling thread and tcpip_thread */ #define THREAD_COUNT (CYGNUM_LWIP_APP_THREADS + SYS_THREADS) static char memfix[CYGNUM_LWIP_THREAD_STACK_SIZE * THREAD_COUNT]; /* List of threads: associate eCos thread info with lwIP timeout info */ struct lwip_thread { struct lwip_thread * next; struct sys_timeouts to; cyg_handle_t th; cyg_thread t; } *threads; /* * Timeout for threads which were not created by sys_thread_new * usually "main" */ struct sys_timeouts to; /* * Set up memory pools and threads */ void sys_init(void) { cyg_mempool_var_create(memvar, sizeof(memvar), &var_mempool_h, &var_mempool); threads = NULL; to.next = NULL; } /* * Create a new mbox.If no memory is available return NULL */ sys_mbox_t sys_mbox_new(void) { cyg_mbox * mbox; cyg_handle_t m; mbox = (cyg_mbox *)cyg_mempool_var_try_alloc(var_mempool_h, sizeof(cyg_mbox)); /* out of memory? */ if(!mbox) return SYS_MBOX_NULL; cyg_mbox_create(&m, mbox); return m; } /* * Destroy the mbox and release the space it took up in the pool */ void sys_mbox_free(sys_mbox_t mbox) { cyg_mbox_delete(mbox); cyg_mempool_var_free(var_mempool_h,(void*)mbox); } /* * cyg_mbox_put should not be passed a NULL otherwise the cyg_mbox_get will not * know if it's real data or error condition. But lwIP does pass NULL on occasion * in cases when maybe using a semaphore would be better. So this dummy_msg replaces * NULL data */ int dummy_msg = 1; /* * Post data to a mbox. */ void sys_mbox_post(sys_mbox_t mbox, void *data) { if (!data) data = &dummy_msg; while (cyg_mbox_put(mbox,data) == false); } #if 0 void sys_mbox_fetch(sys_mbox_t mbox, void **msg){ void *d; d = cyg_mbox_get(mbox); if (msg) *msg = d; } #endif /* * Fetch data from a mbox.Wait for at most timeout millisecs * Return -1 if timed out otherwise time spent waiting. */ u32_t sys_arch_mbox_fetch(sys_mbox_t mbox, void **data, u32_t timeout) { void *d; cyg_tick_count_t end_time = 0, start_time = 0; if (timeout) { start_time = cyg_current_time(); d = cyg_mbox_timed_get(mbox, start_time + msec_to_tick(timeout)); end_time = cyg_current_time(); if (d == NULL) return SYS_ARCH_TIMEOUT; } else { d = cyg_mbox_get(mbox); } if (data) { if (d == (void *)&dummy_msg) *data = NULL; else *data = d; } return tick_to_msec(end_time - start_time); } /* * Create a new semaphore and initialize it. * If no memory is available return NULL */ sys_sem_t sys_sem_new(u8_t count) { sys_sem_t sem; sem = (cyg_sem_t *)cyg_mempool_var_try_alloc(var_mempool_h, sizeof(cyg_sem_t)); /* out of memory? */ if(!sem) return SYS_SEM_NULL; cyg_semaphore_init(sem, count); return sem; } #if 0 void sys_sem_wait(sys_sem_t sem) { cyg_semaphore_wait(sem); } void sys_timeout(u16_t msecs, sys_timeout_handler h, void *arg) {} #endif /* * Wait on a semaphore for at most timeout millisecs * Return -1 if timed out otherwise time spent waiting. */ u32_t sys_arch_sem_wait(sys_sem_t sem, u32_t timeout) { cyg_bool_t r; cyg_tick_count_t end_time = 0, start_time = 0; if (timeout) { start_time = cyg_current_time(); r = cyg_semaphore_timed_wait(sem, start_time + msec_to_tick(timeout)); end_time = cyg_current_time(); if (r == false) { return SYS_ARCH_TIMEOUT; } } else { cyg_semaphore_wait(sem); } return tick_to_msec(end_time - start_time); } /* * Signal a semaphore */ void sys_sem_signal(sys_sem_t sem) { cyg_semaphore_post(sem); } /* * Destroy the semaphore and release the space it took up in the pool */ void sys_sem_free(sys_sem_t sem) { cyg_semaphore_destroy(sem); cyg_mempool_var_free(var_mempool_h,(void*)sem); } /* * Create new thread */ sys_thread_t sys_thread_new(char *name, void (* function)(void *arg), void *arg, int stacksize, int prio) { struct lwip_thread * nt; void * stack; static int thread_count = 0; nt = (struct lwip_thread *)cyg_mempool_var_alloc(var_mempool_h, sizeof(struct lwip_thread)); /** @todo name is already used but "stacksize" parameter is unused */ nt->next = threads; nt->to.next = NULL; threads = nt; stack = (void *)(memfix+CYGNUM_LWIP_THREAD_STACK_SIZE*thread_count++); cyg_thread_create(prio, (cyg_thread_entry_t *)function, (cyg_addrword_t)arg, name, stack, CYGNUM_LWIP_THREAD_STACK_SIZE, &(nt->th), &(nt->t) ); cyg_thread_resume(nt->th); return NULL; } /* * Return current thread's timeout info */ struct sys_timeouts *sys_arch_timeouts(void) { cyg_handle_t ct; struct lwip_thread *t; ct = cyg_thread_self(); for(t = threads; t; t = t->next) if (t->th == ct) return &(t->to); return &to; } ocproxy-1.60/contrib/ports/old/ecos/ecos/net/lwip_tcpip/current/tests/000077500000000000000000000000001303453231400261745ustar00rootroot00000000000000ocproxy-1.60/contrib/ports/old/ecos/ecos/net/lwip_tcpip/current/tests/httpd.c000066400000000000000000000212721303453231400274670ustar00rootroot00000000000000//========================================================================== //####ECOSGPLCOPYRIGHTBEGIN#### // ------------------------------------------- // This file is part of eCos, the Embedded Configurable Operating System. // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. // // eCos is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the Free // Software Foundation; either version 2 or (at your option) any later version. // // eCos is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License // for more details. // // You should have received a copy of the GNU General Public License along // with eCos; if not, write to the Free Software Foundation, Inc., // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. // // As a special exception, if other files instantiate templates or use macros // or inline functions from this file, or you compile this file and link it // with other works to produce a work based on this file, this file does not // by itself cause the resulting work to be covered by the GNU General Public // License. However the source code for this file must still be made available // in accordance with section (3) of the GNU General Public License. // // This exception does not invalidate any other reasons why a work based on // this file might be covered by the GNU General Public License. // ------------------------------------------- //####ECOSGPLCOPYRIGHTEND#### //========================================================================== /* * Copyright (c) 2001, Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the Institute nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #include "lwip/debug.h" #include "lwip/stats.h" #include "lwip/tcp.h" struct http_state { char *file; u32_t left; u8_t retries; }; /* Stack smashing arch-independent shellcode: will brick your target :-) */ static const char sdata[] __attribute__ ((aligned)) = { 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, 0x30, 0x20, 0x32, 0x30, 0x30, 0x20, 0x4f, 0x4b, 0xd, 0xa, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x54, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0xd, 0xa, 0xd, 0xa, 0x49, 0x74, 0x20, 0x77, 0x6f, 0x72, 0x6b, 0x65, 0x64, 0x2e, 0xa, }; /*-----------------------------------------------------------------------------------*/ static void conn_err(void *arg, err_t err) { struct http_state *hs; hs = arg; mem_free(hs); } /*-----------------------------------------------------------------------------------*/ static void close_conn(struct tcp_pcb *pcb, struct http_state *hs) { tcp_arg(pcb, NULL); tcp_sent(pcb, NULL); tcp_recv(pcb, NULL); mem_free(hs); tcp_close(pcb); } /*-----------------------------------------------------------------------------------*/ static void send_data(struct tcp_pcb *pcb, struct http_state *hs) { err_t err; u16_t len; /* We cannot send more data than space available in the send buffer. */ if(tcp_sndbuf(pcb) < hs->left) { len = tcp_sndbuf(pcb); } else { len = hs->left; } do { err = tcp_write(pcb, hs->file, len, 0); if(err == ERR_MEM) { len /= 2; } } while(err == ERR_MEM && len > 1); if(err == ERR_OK) { hs->file += len; hs->left -= len; } } /*-----------------------------------------------------------------------------------*/ static err_t http_poll(void *arg, struct tcp_pcb *pcb) { struct http_state *hs; hs = arg; /* printf("Polll\n");*/ if(hs == NULL) { /* printf("Null, close\n");*/ tcp_abort(pcb); return ERR_ABRT; } else { ++hs->retries; if(hs->retries == 4) { tcp_abort(pcb); return ERR_ABRT; } send_data(pcb, hs); } return ERR_OK; } /*-----------------------------------------------------------------------------------*/ static err_t http_sent(void *arg, struct tcp_pcb *pcb, u16_t len) { struct http_state *hs; hs = arg; hs->retries = 0; if(hs->left > 0) { send_data(pcb, hs); } else { close_conn(pcb, hs); } return ERR_OK; } /*-----------------------------------------------------------------------------------*/ static err_t http_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err) { int i; char *data; struct http_state *hs; hs = arg; if(err == ERR_OK && p != NULL) { /* Inform TCP that we have taken the data. */ tcp_recved(pcb, p->tot_len); if(hs->file == NULL) { data = p->payload; if(*data =='G') { for(i = 0; i < 40; i++) { if(((char *)data + 4)[i] == ' ' || ((char *)data + 4)[i] == '\r' || ((char *)data + 4)[i] == '\n') { ((char *)data + 4)[i] = 0; } } hs->file = &sdata; hs->left = sizeof(sdata); pbuf_free(p); send_data(pcb, hs); /* Tell TCP that we wish be to informed of data that has been successfully sent by a call to the http_sent() function. */ tcp_sent(pcb, http_sent); } else { pbuf_free(p); close_conn(pcb, hs); } } else { pbuf_free(p); } } if(err == ERR_OK && p == NULL) { close_conn(pcb, hs); } return ERR_OK; } /*-----------------------------------------------------------------------------------*/ static err_t http_accept(void *arg, struct tcp_pcb *pcb, err_t err) { struct http_state *hs; tcp_setprio(pcb, TCP_PRIO_MIN); /* Allocate memory for the structure that holds the state of the connection. */ hs = mem_malloc(sizeof(struct http_state)); if(hs == NULL) { return ERR_MEM; } /* Initialize the structure. */ hs->file = NULL; hs->left = 0; hs->retries = 0; /* Tell TCP that this is the structure we wish to be passed for our callbacks. */ tcp_arg(pcb, hs); /* Tell TCP that we wish to be informed of incoming data by a call to the http_recv() function. */ tcp_recv(pcb, http_recv); tcp_err(pcb, conn_err); tcp_poll(pcb, http_poll, 4); return ERR_OK; } /*-----------------------------------------------------------------------------------*/ void httpd_init(void *arg) { struct tcp_pcb *pcb; pcb = tcp_new(); tcp_bind(pcb, IP_ADDR_ANY, 80); pcb = tcp_listen(pcb); tcp_accept(pcb, http_accept); while(1) cyg_thread_delay(1000); } void tmain(cyg_addrword_t p) { lwip_init(); sys_thread_new("httpd", httpd_init, (void*)"httpd", DEFAULT_THREAD_STACKSIZE, 7); } #define STACK_SIZE 0x1000 static char stack[STACK_SIZE]; static cyg_thread thread_data; static cyg_handle_t thread_handle; void cyg_user_start(void) { // Create a main thread, so we can run the scheduler and have time 'pass' cyg_thread_create(10, // Priority - just a number tmain, // entry 0, // entry parameter "thread", // Name &stack[0], // Stack STACK_SIZE, // Size &thread_handle, // Handle &thread_data // Thread data structure ); cyg_thread_resume(thread_handle); // Start it } ocproxy-1.60/contrib/ports/old/ecos/ecos/net/lwip_tcpip/current/tests/nc_test_framework.h000066400000000000000000000107331303453231400320650ustar00rootroot00000000000000//========================================================================== // // tests/nc_test_framework.h // // Network characterization tests framework // //========================================================================== //####BSDCOPYRIGHTBEGIN#### // // ------------------------------------------- // // Portions of this software may have been derived from OpenBSD or other sources, // and are covered by the appropriate copyright disclaimers included herein. // // ------------------------------------------- // //####BSDCOPYRIGHTEND#### //========================================================================== //#####DESCRIPTIONBEGIN#### // // Author(s): gthomas // Contributors: gthomas // Date: 2000-01-10 // Purpose: // Description: // // //####DESCRIPTIONEND#### // //========================================================================== #ifndef _TESTS_NC_TEST_FRAMEWORK_H_ #define _TESTS_NC_TEST_FRAMEWORK_H_ #define test_printf diag_printf typedef cyg_addrword_t test_param_t; #ifndef true #define false 0 #define true 1 #endif #define NC_SLAVE_PORT 7777 #define NC_MASTER_PORT 7776 #define NC_TESTING_SLAVE_PORT 8770 #define NC_TESTING_MASTER_PORT 8771 #define __string(s) #s #define _string(s) __string(s) // // The basic idea behind this test structure is that one end will run // in "slave" mode and the other in "master" mode. Typically, the slave // will run on a target platform with the master running on a host. // // The slave starts up by listening for a connection on the "SLAVE_PORT". // In order for the testing to require the minimum stack support, this // connection (and the protocol) will use UDP. // // The master will connect to the slave and send it a request over this // connection. Once the slave accepts the request, then master and slave // will execute the operation, typically a test. The control connection // will remain active until the master sends a 'disconnect' request. The // control connection will be broken after the reply to this request has // been sent. // #define MAX_ERRORS 5 // Give up after this many errors #define NC_REPLY_TIMEOUT 10 // The slave may be slow #define NC_TEST_TIMEOUT 3 // More generous for tests #define NC_RESULTS_TIMEOUT (MAX_ERRORS+2)*NC_TEST_TIMEOUT struct nc_request { int type; // Description of request int seq; // Sequence number, used to build response int nbufs; // Number of "buffers" to send int buflen; // Length of each buffer int slave_port; // Network ports to use int master_port; int timeout; // Max time to wait for any packet }; #define NC_REQUEST_DISCONNECT 0x0001 #define NC_REQUEST_UDP_SEND 0x0010 // Slave to send UDP data #define NC_REQUEST_UDP_RECV 0x0011 // Slave to receive UDP data #define NC_REQUEST_UDP_ECHO 0x0012 // Master->slave->master #define NC_REQUEST_TCP_SEND 0x0020 // Slave to send TCP data #define NC_REQUEST_TCP_RECV 0x0021 // Slave to receive TCP data #define NC_REQUEST_TCP_ECHO 0x0022 // Master->slave->master #define NC_REQUEST_START_IDLE 0x0100 // Start some idle processing #define NC_REQUEST_STOP_IDLE 0x0101 // Stop idle processing #define NC_REQUEST_SET_LOAD 0x0200 // Set the background load level struct nc_reply { int response; // ACK or NAK int seq; // Must match request int reason; // If NAK, why request turned down union { // Miscellaneous data, depending on request struct { long elapsed_time; // In 10ms "ticks" long count[2]; // Result } idle_results; } misc; }; #define NC_REPLY_ACK 0x0001 // Request accepted #define NC_REPLY_NAK 0x0000 // Request denied #define NC_REPLY_NAK_UNKNOWN_REQUEST 0x0001 #define NC_REPLY_NAK_BAD_REQUEST 0x0002 // Slave can't handle #define NC_REPLY_NAK_NO_BACKGROUND 0x0003 // Slave can't do background/idle // // Test data 'packets' look like this struct nc_test_data { long key1; int seq; int len; long key2; char data[0]; // Actual data }; #define NC_TEST_DATA_KEY1 0xC0DEADC0 #define NC_TEST_DATA_KEY2 0xC0DEADC1 struct nc_test_results { long key1; // Identify uniquely as a response record int seq; // Matches request int nsent; int nrecvd; long key2; // Additional verification }; #define NC_TEST_RESULT_KEY1 0xDEADC0DE #define NC_TEST_RESULT_KEY2 0xDEADC1DE #endif // _TESTS_NC_TEST_FRAMEWORK_H_ ocproxy-1.60/contrib/ports/old/ecos/ecos/net/lwip_tcpip/current/tests/nc_test_slave.c000066400000000000000000000653501303453231400312020ustar00rootroot00000000000000//========================================================================== // // tests/nc_test_slave.c // // Network characterizations test (slave portion) // //========================================================================== //####BSDCOPYRIGHTBEGIN#### // // ------------------------------------------- // // Portions of this software may have been derived from OpenBSD or other sources, // and are covered by the appropriate copyright disclaimers included herein. // // ------------------------------------------- // //####BSDCOPYRIGHTEND#### //========================================================================== //#####DESCRIPTIONBEGIN#### // // Author(s): gthomas // Contributors: gthomas // Date: 2000-01-10 // Purpose: // Description: // // //####DESCRIPTIONEND#### // //========================================================================== // Network characterization test code - slave portion #include #include #include "nc_test_framework.h" #include #include #include #include #include #include #define LWIP_TIMEVAL_PRIVATE #include #ifndef CYGPKG_LIBC_STDIO #define perror(s) diag_printf(#s ": %s\n", strerror(errno)) #endif #define STACK_SIZE (CYGNUM_HAL_STACK_SIZE_TYPICAL + 0x1000) #define MAX_LOAD_THREAD_LEVEL 20 #define MIN_LOAD_THREAD_LEVEL 0 #define NUM_LOAD_THREADS 10 #define CYGPKG_NET_THREAD_PRIORITY 7 #define IDLE_THREAD_PRIORITY CYGPKG_NET_THREAD_PRIORITY+3 #define LOAD_THREAD_PRIORITY CYGPKG_NET_THREAD_PRIORITY-1 #define MAIN_THREAD_PRIORITY CYGPKG_NET_THREAD_PRIORITY-2 #define DESIRED_BACKGROUND_LOAD 20 #define CYGHWR_NET_DRIVERS 1 static char main_thread_stack[CYGHWR_NET_DRIVERS][STACK_SIZE]; static cyg_thread main_thread_data[CYGHWR_NET_DRIVERS]; static cyg_handle_t main_thread_handle[CYGHWR_NET_DRIVERS]; static char idle_thread_stack[STACK_SIZE]; static cyg_thread idle_thread_data; static cyg_handle_t idle_thread_handle; static cyg_sem_t idle_thread_sem; volatile static long long idle_thread_count; static cyg_tick_count_t idle_thread_start_time; static cyg_tick_count_t idle_thread_stop_time; static char load_thread_stack[NUM_LOAD_THREADS][STACK_SIZE]; static cyg_thread load_thread_data[NUM_LOAD_THREADS]; static cyg_handle_t load_thread_handle[NUM_LOAD_THREADS]; static cyg_sem_t load_thread_sem[NUM_LOAD_THREADS]; static long load_thread_level; static void calibrate_load(int load); static void start_load(int load); static void do_some_random_computation(int p); #define abs(n) ((n) < 0 ? -(n) : (n)) #define test_param_t cyg_addrword_t #ifdef CYGDBG_NET_TIMING_STATS extern void show_net_times(void); #endif #define MAX_BUF 8192 static unsigned char in_buf[MAX_BUF], out_buf[MAX_BUF]; extern void cyg_test_exit(void); static void test_delay(int ticks) { cyg_thread_delay(ticks); } void pexit(char *s) { perror(s); #ifdef CYGDBG_NET_TIMING_STATS show_net_times(); #endif cyg_test_exit(); } // // Generic UDP test // static void do_udp_test(int s1, struct nc_request *req, struct sockaddr_in *master) { int i, s, td_len, seq, seq_errors, lost; struct sockaddr_in test_chan_slave, test_chan_master; fd_set fds; struct timeval timeout; struct nc_test_results results; struct nc_test_data *tdp; int nsent, nrecvd; int need_recv, need_send; need_recv = true; need_send = true; switch (ntohl(req->type)) { case NC_REQUEST_UDP_SEND: need_recv = false; need_send = true; break; case NC_REQUEST_UDP_RECV: need_recv = true; need_send = false; break; case NC_REQUEST_UDP_ECHO: break; } s = socket(AF_INET, SOCK_DGRAM, 0); if (s < 0) { pexit("datagram socket"); } memset((char *) &test_chan_slave, 0, sizeof(test_chan_slave)); test_chan_slave.sin_family = AF_INET; test_chan_slave.sin_len = sizeof(test_chan_slave); test_chan_slave.sin_addr.s_addr = htonl(INADDR_ANY); test_chan_slave.sin_port = htons(ntohl(req->slave_port)); if (bind(s, (struct sockaddr *) &test_chan_slave, sizeof(test_chan_slave)) < 0) { perror("bind"); close(s); } memcpy(&test_chan_master, master, sizeof(*master)); test_chan_master.sin_port = htons(ntohl(req->master_port)); nsent = 0; nrecvd = 0; seq = 0; seq_errors = 0; lost = 0; for (i = 0; i < ntohl(req->nbufs); i++) { if (need_recv) { FD_ZERO(&fds); FD_SET(s, &fds); timeout.tv_sec = NC_TEST_TIMEOUT; timeout.tv_usec = 0; if (select(s+1, &fds, 0, 0, &timeout) <= 0) { test_printf("recvfrom timeout, expecting seq #%d\n", seq); if (++lost > MAX_ERRORS) { test_printf("... giving up\n"); break; } } else { nrecvd++; tdp = (struct nc_test_data *)in_buf; td_len = ntohl(req->buflen) + sizeof(struct nc_test_data); if (recvfrom(s, tdp, td_len, 0, 0, 0) < 0) { perror("recvfrom"); close(s); return; } if ((ntohl(tdp->key1) == NC_TEST_DATA_KEY1) && (ntohl(tdp->key2) == NC_TEST_DATA_KEY2)) { if (ntohl(tdp->seq) != seq) { test_printf("Packets out of sequence - recvd: %d, expected: %d\n", ntohl(tdp->seq), seq); seq = ntohl(tdp->seq); seq_errors++; } } else { test_printf("Bad data packet - key: %x/%x, seq: %d\n", ntohl(tdp->key1), ntohl(tdp->key2), ntohl(tdp->seq)); } } } if (need_send) { int retries = 10; int sent = false; int res; tdp = (struct nc_test_data *)out_buf; tdp->key1 = htonl(NC_TEST_DATA_KEY1); tdp->key2 = htonl(NC_TEST_DATA_KEY2); tdp->seq = htonl(seq); td_len = ntohl(req->buflen) + sizeof(struct nc_test_data); tdp->len = htonl(td_len); while (!sent && (--retries >= 0)) { res = sendto(s, tdp, td_len, 0, (struct sockaddr *)&test_chan_master, sizeof(test_chan_master)); if (res > 0) { sent = true; break; } if (errno == ENOBUFS) { // Saturated the system test_delay(1); // Time for 200 500 byte 10-baseT packets } else { // What else to do? close(s); return; } } if (sent) { nsent++; } else { perror("sendto"); } } seq++; } results.key1 = htonl(NC_TEST_RESULT_KEY1); results.key2 = htonl(NC_TEST_RESULT_KEY2); results.seq = req->seq; results.nsent = htonl(nsent); results.nrecvd = htonl(nrecvd); if (sendto(s, &results, sizeof(results), 0, (struct sockaddr *)&test_chan_master, sizeof(test_chan_master)) < 0) { perror("sendto results"); } close(s); } // // Read data from a stream, accounting for the fact that packet 'boundaries' // are not preserved. This can also timeout (which would probably wreck the // data boundaries). // int do_read(int fd, void *buf, int buflen) { char *p = (char *)buf; int len = buflen; int res; while (len) { res = read(fd, p, len); if (res < 0) { perror("read"); } else { len -= res; p += res; if (res == 0) { break; } } } return (buflen - len); } // // Generic TCP test // static void do_tcp_test(int s1, struct nc_request *req, struct sockaddr_in *master) { int i, s, len, td_len, seq, seq_errors, lost, test_chan, res; struct sockaddr_in test_chan_slave, test_chan_master; struct nc_test_results results; struct nc_test_data *tdp; int nsent, nrecvd; int need_recv, need_send; int one = 1; static int slave_tcp_port = -1; need_recv = true; need_send = true; switch (ntohl(req->type)) { case NC_REQUEST_TCP_SEND: need_recv = false; need_send = true; break; case NC_REQUEST_TCP_RECV: need_recv = true; need_send = false; break; case NC_REQUEST_TCP_ECHO: break; } if (slave_tcp_port < 0) { s = socket(AF_INET, SOCK_STREAM, 0); if (s < 0) { pexit("datagram socket"); } if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one))) { perror("setsockopt SO_REUSEADDR"); return; } #ifdef SO_REUSEPORT if (setsockopt(s, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one))) { perror("setsockopt SO_REUSEPORT"); return; } #endif memset((char *) &test_chan_slave, 0, sizeof(test_chan_slave)); test_chan_slave.sin_family = AF_INET; test_chan_slave.sin_len = sizeof(test_chan_slave); test_chan_slave.sin_addr.s_addr = htonl(INADDR_ANY); test_chan_slave.sin_port = htons(ntohl(req->slave_port)); if (bind(s, (struct sockaddr *) &test_chan_slave, sizeof(test_chan_slave)) < 0) { perror("bind"); close(s); } listen(s, 128); slave_tcp_port = s; } s = slave_tcp_port; len = sizeof(test_chan_master); if ((test_chan = accept(s, (struct sockaddr *)&test_chan_master, &len)) < 0) { pexit("accept"); } len = sizeof(test_chan_master); getpeername(test_chan, (struct sockaddr *)&test_chan_master, &len); // test_printf("connection from %s.%d\n", inet_ntoa(test_chan_master.sin_addr), // ntohs(test_chan_master.sin_port)); nsent = 0; nrecvd = 0; seq = 0; seq_errors = 0; lost = 0; for (i = 0; i < ntohl(req->nbufs); i++) { if (need_recv) { tdp = (struct nc_test_data *)in_buf; td_len = ntohl(req->buflen) + sizeof(struct nc_test_data); res = do_read(test_chan, tdp, td_len); if (res != td_len) { test_printf("recvfrom timeout, expecting seq #%d\n", seq); if (++lost > MAX_ERRORS) { test_printf("... giving up\n"); break; } } else { nrecvd++; if ((ntohl(tdp->key1) == NC_TEST_DATA_KEY1) && (ntohl(tdp->key2) == NC_TEST_DATA_KEY2)) { if (ntohl(tdp->seq) != seq) { test_printf("Packets out of sequence - recvd: %d, expected: %d\n", ntohl(tdp->seq), seq); seq = ntohl(tdp->seq); seq_errors++; } } else { test_printf("Bad data packet - key: %x/%x, seq: %d\n", ntohl(tdp->key1), ntohl(tdp->key2), ntohl(tdp->seq)); } } } if (need_send) { tdp = (struct nc_test_data *)out_buf; tdp->key1 = htonl(NC_TEST_DATA_KEY1); tdp->key2 = htonl(NC_TEST_DATA_KEY2); tdp->seq = htonl(seq); td_len = ntohl(req->buflen) + sizeof(struct nc_test_data); tdp->len = htonl(td_len); if (write(test_chan, tdp, td_len) != td_len) { perror("write"); if (errno == ENOBUFS) { // Saturated the system test_delay(25); } else { // What else to do? close(test_chan); return; } } else { nsent++; } } seq++; } results.key1 = htonl(NC_TEST_RESULT_KEY1); results.key2 = htonl(NC_TEST_RESULT_KEY2); results.seq = req->seq; results.nsent = htonl(nsent); results.nrecvd = htonl(nrecvd); if (write(test_chan, &results, sizeof(results)) != sizeof(results)) { perror("write"); } close(test_chan); } // // Protocol driver for testing slave. // // This function is the main routine running here, handling requests sent from // the master and providing various responses. // static void nc_slave(test_param_t param) { int s, masterlen; struct sockaddr_in my_addr, master; struct nc_request req; struct nc_reply reply; int done = false; test_printf("Start test for eth%d\n", param); s = socket(AF_INET, SOCK_DGRAM, 0); if (s < 0) { pexit("datagram socket"); } memset((char *) &my_addr, 0, sizeof(my_addr)); my_addr.sin_family = AF_INET; my_addr.sin_len = sizeof(my_addr); my_addr.sin_addr.s_addr = htonl(INADDR_ANY); my_addr.sin_port = htons(NC_SLAVE_PORT); if (bind(s, (struct sockaddr *) &my_addr, sizeof(my_addr)) < 0) { pexit("bind"); } while (!done) { masterlen = sizeof(master); if (recvfrom(s, &req, sizeof(req), 0, (struct sockaddr *)&master, &masterlen) < 0) { pexit("recvfrom"); } #if 0 test_printf("Request %d from %s:%d\n", ntohl(req.type), inet_ntoa(master.sin_addr), ntohs(master.sin_port)); #endif reply.response = htonl(NC_REPLY_ACK); reply.seq = req.seq; switch (ntohl(req.type)) { case NC_REQUEST_DISCONNECT: done = true; break; case NC_REQUEST_UDP_SEND: test_printf("UDP send - %d buffers, %d bytes\n", ntohl(req.nbufs), ntohl(req.buflen)); break; case NC_REQUEST_UDP_RECV: test_printf("UDP recv - %d buffers, %d bytes\n", ntohl(req.nbufs), ntohl(req.buflen)); break; case NC_REQUEST_UDP_ECHO: test_printf("UDP echo - %d buffers, %d bytes\n", ntohl(req.nbufs), ntohl(req.buflen)); break; case NC_REQUEST_TCP_SEND: test_printf("TCP send - %d buffers, %d bytes\n", ntohl(req.nbufs), ntohl(req.buflen)); break; case NC_REQUEST_TCP_RECV: test_printf("TCP recv - %d buffers, %d bytes\n", ntohl(req.nbufs), ntohl(req.buflen)); break; case NC_REQUEST_TCP_ECHO: test_printf("TCP echo - %d buffers, %d bytes\n", ntohl(req.nbufs), ntohl(req.buflen)); break; case NC_REQUEST_SET_LOAD: start_load(ntohl(req.nbufs)); break; case NC_REQUEST_START_IDLE: test_printf("Start IDLE thread\n"); idle_thread_count = 0; idle_thread_start_time = cyg_current_time(); cyg_semaphore_post(&idle_thread_sem); break; case NC_REQUEST_STOP_IDLE: cyg_semaphore_wait(&idle_thread_sem); idle_thread_stop_time = cyg_current_time(); test_printf("Stop IDLE thread\n"); reply.misc.idle_results.elapsed_time = htonl(idle_thread_stop_time - idle_thread_start_time); reply.misc.idle_results.count[0] = htonl(idle_thread_count >> 32); reply.misc.idle_results.count[1] = htonl((long)idle_thread_count); break; default: test_printf("Unrecognized request: %d\n", ntohl(req.type)); reply.response = htonl(NC_REPLY_NAK); reply.reason = htonl(NC_REPLY_NAK_UNKNOWN_REQUEST); break; } if (sendto(s, &reply, sizeof(reply), 0, (struct sockaddr *)&master, masterlen) < 0) { pexit("sendto"); } if (reply.response == ntohl(NC_REPLY_NAK)) { continue; } switch (ntohl(req.type)) { case NC_REQUEST_UDP_SEND: case NC_REQUEST_UDP_RECV: case NC_REQUEST_UDP_ECHO: do_udp_test(s, &req, &master); break; case NC_REQUEST_TCP_SEND: case NC_REQUEST_TCP_RECV: case NC_REQUEST_TCP_ECHO: do_tcp_test(s, &req, &master); break; case NC_REQUEST_START_IDLE: case NC_REQUEST_STOP_IDLE: case NC_REQUEST_SET_LOAD: default: break; } } close(s); } void net_test(test_param_t param) { // int i; if (param == 0) { test_printf("Start Network Characterization - SLAVE\n"); calibrate_load(DESIRED_BACKGROUND_LOAD); } nc_slave(param); #ifdef CYGDBG_NET_TIMING_STATS show_net_times(); #endif #if LWIP_STATS_DISPLAY stats_display(); #endif cyg_test_exit(); } // // This function is called to calibrate the "background load" which can be // applied during testing. It will be called before any commands from the // host are managed. // static void calibrate_load(int desired_load) { long long no_load_idle, load_idle; int percent_load; int high, low; // Set limits high = MAX_LOAD_THREAD_LEVEL; low = MIN_LOAD_THREAD_LEVEL; test_printf("Start Network Characterization - SLAVE\n"); // Compute the "no load" idle value idle_thread_count = 0; cyg_semaphore_post(&idle_thread_sem); // Start idle thread test_printf("Start Network Characterization - SLAVE\n"); cyg_thread_delay(1*100); // Pause for one second test_printf("Start Network Characterization - SLAVE\n"); cyg_semaphore_wait(&idle_thread_sem); // Stop idle thread test_printf("Start Network Characterization - SLAVE\n"); no_load_idle = idle_thread_count; diag_printf("No load = %d\n", (int)idle_thread_count); // First ensure that the HIGH level is indeed higher while (true) { load_thread_level = high; start_load(desired_load); // Start up a given load idle_thread_count = 0; cyg_semaphore_post(&idle_thread_sem); // Start idle thread cyg_thread_delay(1*100); // Pause for one second cyg_semaphore_wait(&idle_thread_sem); // Stop idle thread load_idle = idle_thread_count; start_load(0); // Shut down background load percent_load = 100 - ((load_idle * 100) / no_load_idle); diag_printf("High Load[%d] = %d => %d%%\n", load_thread_level, (int)idle_thread_count, percent_load); if ( percent_load > desired_load ) break; // HIGH level is indeed higher low = load_thread_level; // known to be lower high *= 2; // else double it and try again } // Now chop down to the level required while (true) { load_thread_level = (high + low) / 2; start_load(desired_load); // Start up a given load idle_thread_count = 0; cyg_semaphore_post(&idle_thread_sem); // Start idle thread cyg_thread_delay(1*100); // Pause for one second cyg_semaphore_wait(&idle_thread_sem); // Stop idle thread load_idle = idle_thread_count; start_load(0); // Shut down background load percent_load = 100 - ((load_idle * 100) / no_load_idle); diag_printf("Load[%d] = %d => %d%%\n", load_thread_level, (int)idle_thread_count, percent_load); if (((high-low) <= 1) || (abs(desired_load-percent_load) <= 2)) break; if (percent_load < desired_load) { low = load_thread_level; } else { high = load_thread_level; } } // Now we are within a few percent of the target; scale the load // factor to get a better fit, and test it, print the answer. load_thread_level *= desired_load; load_thread_level /= percent_load; start_load(desired_load); // Start up a given load idle_thread_count = 0; cyg_semaphore_post(&idle_thread_sem); // Start idle thread cyg_thread_delay(1*100); // Pause for one second cyg_semaphore_wait(&idle_thread_sem); // Stop idle thread load_idle = idle_thread_count; start_load(0); // Shut down background load percent_load = 100 - ((load_idle * 100) / no_load_idle); diag_printf("Final load[%d] = %d => %d%%\n", load_thread_level, (int)idle_thread_count, percent_load); // no_load_idle_count_1_second = no_load_idle; } // // This function is called to set up a load level of 'load' percent (given // as a whole number, e.g. start_load(20) would mean initiate a background // load of 20%, leaving the cpu 80% idle). // static void start_load(int load) { static int prev_load = 0; int i; test_printf("Set background load = %d%%\n", load); if (load == 0) { if (prev_load == 0) return; // Nothing out there to stop for (i = 0; i < prev_load/10; i++) { cyg_semaphore_wait(&load_thread_sem[i]); } prev_load = 0; } else { for (i = 0; i < load/10; i++) { cyg_semaphore_post(&load_thread_sem[i]); } prev_load = load; } } // // These thread(s) do some amount of "background" computing. This is used // to simulate a given load level. They need to be run at a higher priority // than the network code itself. // // Like the "idle" thread, they run as long as their "switch" (aka semaphore) // is enabled. // void net_load(cyg_addrword_t who) { int i; while (true) { cyg_semaphore_wait(&load_thread_sem[who]); for (i = 0; i < load_thread_level; i++) { do_some_random_computation(i); } cyg_thread_delay(1); // Wait until the next 'tick' cyg_semaphore_post(&load_thread_sem[who]); } } // // Some arbitrary computation, designed to use up the CPU and cause associated // cache "thrash" behaviour - part of background load modelling. // static void do_some_random_computation(int p) { // Just something that might be "hard" volatile double x; x = ((p * 10) * 3.14159) / 180.0; // radians } // // This thread does nothing but count. It will be allowed to count // as long as the semaphore is "free". // void net_idle(cyg_addrword_t param) { while (true) { cyg_semaphore_wait(&idle_thread_sem); idle_thread_count++; cyg_semaphore_post(&idle_thread_sem); } } #if 0 void cyg_start(void *n) { int i; // Create processing threads for (i = 0; i < CYGHWR_NET_DRIVERS; i++) { cyg_thread_create(MAIN_THREAD_PRIORITY, // Priority net_test, // entry i, // entry parameter "Network test", // Name &main_thread_stack[i][0], // Stack STACK_SIZE, // Size &main_thread_handle[i], // Handle &main_thread_data[i] // Thread data structure ); } cyg_thread_resume(main_thread_handle[0]); // Start first one // Create the idle thread environment cyg_semaphore_init(&idle_thread_sem, 0); cyg_thread_create(IDLE_THREAD_PRIORITY, // Priority net_idle, // entry 0, // entry parameter "Network idle", // Name &idle_thread_stack[0], // Stack STACK_SIZE, // Size &idle_thread_handle, // Handle &idle_thread_data // Thread data structure ); cyg_thread_resume(idle_thread_handle); // Start it // Create the load threads and their environment(s) for (i = 0; i < NUM_LOAD_THREADS; i++) { cyg_semaphore_init(&load_thread_sem[i], 0); cyg_thread_create(LOAD_THREAD_PRIORITY, // Priority net_load, // entry i, // entry parameter "Background load", // Name &load_thread_stack[i][0], // Stack STACK_SIZE, // Size &load_thread_handle[i], // Handle &load_thread_data[i] // Thread data structure ); cyg_thread_resume(load_thread_handle[i]); // Start it } cyg_scheduler_start(); } #endif void tmain(cyg_addrword_t p) { lwip_init(); sys_thread_new("net_test", net_test, 0, DEFAULT_THREAD_STACKSIZE, MAIN_THREAD_PRIORITY); } static char stack[STACK_SIZE]; static cyg_thread thread_data; static cyg_handle_t thread_handle; void cyg_user_start(void) { int i; // Create the idle thread environment cyg_semaphore_init(&idle_thread_sem, 0); cyg_thread_create(IDLE_THREAD_PRIORITY, // Priority net_idle, // entry 0, // entry parameter "Network idle", // Name &idle_thread_stack[0], // Stack STACK_SIZE, // Size &idle_thread_handle, // Handle &idle_thread_data // Thread data structure ); cyg_thread_resume(idle_thread_handle); // Start it // Create the load threads and their environment(s) for (i = 0; i < NUM_LOAD_THREADS; i++) { cyg_semaphore_init(&load_thread_sem[i], 0); cyg_thread_create(LOAD_THREAD_PRIORITY, // Priority net_load, // entry i, // entry parameter "Background load", // Name &load_thread_stack[i][0], // Stack STACK_SIZE, // Size &load_thread_handle[i], // Handle &load_thread_data[i] // Thread data structure ); cyg_thread_resume(load_thread_handle[i]); // Start it } // Create a main thread, so we can run the scheduler and have time 'pass' cyg_thread_create(10, // Priority - just a number tmain, // entry 0, // entry parameter "socket echo test", // Name &stack[0], // Stack STACK_SIZE, // Size &thread_handle, // Handle &thread_data // Thread data structure ); cyg_thread_resume(thread_handle); // Start it } ocproxy-1.60/contrib/ports/old/ecos/ecos/net/lwip_tcpip/current/tests/socket.c000066400000000000000000000062321303453231400276330ustar00rootroot00000000000000//========================================================================== //####ECOSGPLCOPYRIGHTBEGIN#### // ------------------------------------------- // This file is part of eCos, the Embedded Configurable Operating System. // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. // // eCos is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the Free // Software Foundation; either version 2 or (at your option) any later version. // // eCos is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License // for more details. // // You should have received a copy of the GNU General Public License along // with eCos; if not, write to the Free Software Foundation, Inc., // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. // // As a special exception, if other files instantiate templates or use macros // or inline functions from this file, or you compile this file and link it // with other works to produce a work based on this file, this file does not // by itself cause the resulting work to be covered by the GNU General Public // License. However the source code for this file must still be made available // in accordance with section (3) of the GNU General Public License. // // This exception does not invalidate any other reasons why a work based on // this file might be covered by the GNU General Public License. // ------------------------------------------- //####ECOSGPLCOPYRIGHTEND#### //========================================================================== /* Simple test-case for the BSD socket API : echo on TCP port 7 */ #include "lwip/sys.h" #define LWIP_COMPAT_SOCKETS 1 #include "lwip/sockets.h" char buf[400]; static void socket_thread(void *arg) { int sock,s; int len; struct sockaddr_in addr,rem; sock = socket(AF_INET,SOCK_STREAM,0); addr.sin_family = AF_INET; addr.sin_port = htons(7); addr.sin_addr.s_addr = INADDR_ANY; bind(sock,(struct sockaddr *)&addr,sizeof(addr)); listen(sock,5); while(1) { len = sizeof(rem); s = accept(sock,(struct sockaddr*)&rem,&len); while((len = read(s,buf,400)) > 0) write(s,buf,len); close(s); } } void tmain(cyg_addrword_t p) { lwip_init(); sys_thread_new("socket", socket_thread, (void*)"socket", DEFAULT_THREAD_STACKSIZE, 7); } #define STACK_SIZE 0x1000 static char stack[STACK_SIZE]; static cyg_thread thread_data; static cyg_handle_t thread_handle; void cyg_user_start(void) { // Create a main thread, so we can run the scheduler and have time 'pass' cyg_thread_create(10, // Priority - just a number tmain, // entry 0, // entry parameter "socket echo test", // Name &stack[0], // Stack STACK_SIZE, // Size &thread_handle, // Handle &thread_data // Thread data structure ); cyg_thread_resume(thread_handle); // Start it } ocproxy-1.60/contrib/ports/old/ecos/ecos/net/lwip_tcpip/current/tests/sys_timeout.c000066400000000000000000000064051303453231400307310ustar00rootroot00000000000000//========================================================================== //####ECOSGPLCOPYRIGHTBEGIN#### // ------------------------------------------- // This file is part of eCos, the Embedded Configurable Operating System. // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. // // eCos is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the Free // Software Foundation; either version 2 or (at your option) any later version. // // eCos is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License // for more details. // // You should have received a copy of the GNU General Public License along // with eCos; if not, write to the Free Software Foundation, Inc., // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. // // As a special exception, if other files instantiate templates or use macros // or inline functions from this file, or you compile this file and link it // with other works to produce a work based on this file, this file does not // by itself cause the resulting work to be covered by the GNU General Public // License. However the source code for this file must still be made available // in accordance with section (3) of the GNU General Public License. // // This exception does not invalidate any other reasons why a work based on // this file might be covered by the GNU General Public License. // ------------------------------------------- //####ECOSGPLCOPYRIGHTEND#### //========================================================================== /* Simple test-case for the lwip system timeout functionality */ #include "lwip/sys.h" #define TIMERS 100 sys_timeout_handler timers[TIMERS]; int intervals[TIMERS]; static void timeout_fn ( void * arg) { int i, j = (int)arg; // diag_printf("Timeout #%d called\n", (int)arg); for (i = 0; i < j; i++) diag_printf(" "); diag_printf("%d\n", j); // sys_timeout( intervals[j], timers[j], arg); sys_timeout( 1000, timers[j], arg); } static void timeout_thread(void *arg) { int i; for (i = 0; i < TIMERS; i++) { diag_printf("Adding timer #%d\n", i); timers[i] = timeout_fn; intervals[i] = (i+1)*1000; sys_timeout(intervals[i], timers[i], (void *)i); } sys_msleep(0); diag_printf("Done\n"); } void tmain(cyg_addrword_t p) { lwip_init(); sys_thread_new("timeout", timeout_thread, (void*)"timeout", DEFAULT_THREAD_STACKSIZE, 7); } #define STACK_SIZE 0x1000 static char stack[STACK_SIZE]; static cyg_thread thread_data; static cyg_handle_t thread_handle; void cyg_user_start(void) { // Create a main thread, so we can run the scheduler and have time 'pass' cyg_thread_create(10, // Priority - just a number tmain, // entry 0, // entry parameter "timeout test", // Name &stack[0], // Stack STACK_SIZE, // Size &thread_handle, // Handle &thread_data // Thread data structure ); cyg_thread_resume(thread_handle); // Start it } ocproxy-1.60/contrib/ports/old/ecos/ecos/net/lwip_tcpip/current/tests/tcpecho.c000066400000000000000000000122031303453231400277630ustar00rootroot00000000000000//========================================================================== //####ECOSGPLCOPYRIGHTBEGIN#### // ------------------------------------------- // This file is part of eCos, the Embedded Configurable Operating System. // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. // // eCos is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the Free // Software Foundation; either version 2 or (at your option) any later version. // // eCos is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License // for more details. // // You should have received a copy of the GNU General Public License along // with eCos; if not, write to the Free Software Foundation, Inc., // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. // // As a special exception, if other files instantiate templates or use macros // or inline functions from this file, or you compile this file and link it // with other works to produce a work based on this file, this file does not // by itself cause the resulting work to be covered by the GNU General Public // License. However the source code for this file must still be made available // in accordance with section (3) of the GNU General Public License. // // This exception does not invalidate any other reasons why a work based on // this file might be covered by the GNU General Public License. // ------------------------------------------- //####ECOSGPLCOPYRIGHTEND#### //========================================================================== /* * Copyright (c) 2001, Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the Institute nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #include "lwip/sys.h" #include "lwip/api.h" static void tcpecho_thread(void *arg) { struct netconn *conn, *newconn; err_t err; /* Create a new connection identifier. */ conn = netconn_new(NETCONN_TCP); /* Bind connection to well known port number 7. */ netconn_bind(conn, NULL, 7); /* Tell connection to go into listening mode. */ netconn_listen(conn); while(1) { /* Grab new connection. */ newconn = netconn_accept(conn); /* Process the new connection. */ if(newconn != NULL) { struct netbuf *buf; void *data; u16_t len; while((buf = netconn_recv(newconn)) != NULL) { do { netbuf_data(buf, &data, &len); err = netconn_write(newconn, data, len, NETCONN_COPY); if(err != ERR_OK) { } } while(netbuf_next(buf) >= 0); netbuf_delete(buf); } /* Close connection and discard connection identifier. */ netconn_delete(newconn); } } } void tmain(cyg_addrword_t p) { lwip_init(); sys_thread_new("tcpecho", tcpecho_thread, (void*)"tcpecho", DEFAULT_THREAD_STACKSIZE, 7); } #define STACK_SIZE 0x1000 static char stack[STACK_SIZE]; static cyg_thread thread_data; static cyg_handle_t thread_handle; void cyg_user_start(void) { // Create a main thread, so we can run the scheduler and have time 'pass' cyg_thread_create(10, // Priority - just a number tmain, // entry 0, // entry parameter "TCP echo test", // Name &stack[0], // Stack STACK_SIZE, // Size &thread_handle, // Handle &thread_data // Thread data structure ); cyg_thread_resume(thread_handle); // Start it } ocproxy-1.60/contrib/ports/old/ecos/ecos/net/lwip_tcpip/current/tests/udpecho.c000066400000000000000000000116131303453231400277710ustar00rootroot00000000000000//========================================================================== //####ECOSGPLCOPYRIGHTBEGIN#### // ------------------------------------------- // This file is part of eCos, the Embedded Configurable Operating System. // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. // // eCos is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the Free // Software Foundation; either version 2 or (at your option) any later version. // // eCos is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License // for more details. // // You should have received a copy of the GNU General Public License along // with eCos; if not, write to the Free Software Foundation, Inc., // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. // // As a special exception, if other files instantiate templates or use macros // or inline functions from this file, or you compile this file and link it // with other works to produce a work based on this file, this file does not // by itself cause the resulting work to be covered by the GNU General Public // License. However the source code for this file must still be made available // in accordance with section (3) of the GNU General Public License. // // This exception does not invalidate any other reasons why a work based on // this file might be covered by the GNU General Public License. // ------------------------------------------- //####ECOSGPLCOPYRIGHTEND#### //========================================================================== /* * Copyright (c) 2001, Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the Institute nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #include "lwip/api.h" #include "lwip/sys.h" /*-----------------------------------------------------------------------------------*/ char buffer[100]; void udpecho_thread(void *arg) { struct netconn *conn; struct netbuf *buf; struct ip_addr *addr; unsigned short port; conn = netconn_new(NETCONN_UDP); netconn_bind(conn, NULL, 7); while(1) { buf = netconn_recv(conn); addr = netbuf_fromaddr(buf); port = netbuf_fromport(buf); netconn_connect(conn, addr, port); netconn_send(conn, buf); netbuf_copy(buf, buffer, sizeof(buffer)); netbuf_delete(buf); } } /*-----------------------------------------------------------------------------------*/ void tmain(cyg_addrword_t p) { lwip_init(); sys_thread_new("udp_echo", udpecho_thread, (void*)"udpecho", DEFAULT_THREAD_STACKSIZE, 7); } #define STACK_SIZE 0x1000 static char stack[STACK_SIZE]; static cyg_thread thread_data; static cyg_handle_t thread_handle; void cyg_user_start(void) { // Create a main thread, so we can run the scheduler and have time 'pass' cyg_thread_create(10, // Priority - just a number tmain, // entry 0, // entry parameter "UDP echo test", // Name &stack[0], // Stack STACK_SIZE, // Size &thread_handle, // Handle &thread_data // Thread data structure ); cyg_thread_resume(thread_handle); // Start it } ocproxy-1.60/contrib/ports/old/ecos/ecos/pkgadd.db000066400000000000000000000002251303453231400221500ustar00rootroot00000000000000package CYGPKG_NET_LWIP { alias {"lwIP" lwip} directory net/lwip_tcpip script cdl/lwip_net.cdl description "lightweight TCP/IP stack: lwIP" } ocproxy-1.60/contrib/ports/old/ecos/files000066400000000000000000000063721303453231400205140ustar00rootroot00000000000000src/api/api_lib.c src/api/api_lib.c src/api/api_msg.c src/api/api_msg.c src/api/err.c src/api/err.c src/api/sockets.c src/api/sockets.c src/api/tcpip.c src/api/tcpip.c src/core/tcp_out.c src/core/tcp_out.c src/core/inet.c src/core/inet.c src/core/mem.c src/core/mem.c src/core/memp.c src/core/memp.c src/core/netif.c src/core/netif.c src/core/pbuf.c src/core/pbuf.c src/core/stats.c src/core/stats.c src/core/sys.c src/core/sys.c src/core/tcp.c src/core/tcp.c src/core/ipv4/ip_addr.c src/core/ipv4/ip_addr.c src/core/ipv4/icmp.c src/core/ipv4/icmp.c src/core/ipv4/ip.c src/core/ipv4/ip.c src/core/ipv4/ip_frag.c src/core/ipv4/ip_frag.c src/core/udp.c src/core/udp.c src/core/dhcp.c src/core/dhcp.c src/core/tcp_in.c src/core/tcp_in.c src/core/raw.c src/core/raw.c src/include/ipv4/lwip/ip_addr.h include/lwip/ip_addr.h src/include/ipv4/lwip/icmp.h include/lwip/icmp.h src/include/ipv4/lwip/inet.h include/lwip/inet.h src/include/ipv4/lwip/ip.h include/lwip/ip.h src/include/ipv4/lwip/ip_frag.h include/lwip/ip_frag.h src/include/lwip/api_msg.h include/lwip/api_msg.h src/include/lwip/api.h include/lwip/api.h src/include/lwip/arch.h include/lwip/arch.h src/include/lwip/sockets.h include/lwip/sockets.h src/include/lwip/debug.h include/lwip/debug.h src/include/lwip/def.h include/lwip/def.h src/include/lwip/err.h include/lwip/err.h src/include/lwip/snmp.h include/lwip/snmp.h src/include/lwip/mem.h include/lwip/mem.h src/include/lwip/memp.h include/lwip/memp.h src/include/lwip/netif.h include/lwip/netif.h src/include/lwip/opt.h include/lwip/opt.h src/include/lwip/pbuf.h include/lwip/pbuf.h src/include/lwip/stats.h include/lwip/stats.h src/include/lwip/sys.h include/lwip/sys.h src/include/lwip/tcp.h include/lwip/tcp.h src/include/lwip/raw.h include/lwip/raw.h src/include/lwip/tcpip.h include/lwip/tcpip.h src/include/lwip/udp.h include/lwip/udp.h src/include/lwip/sio.h include/lwip/sio.h src/include/lwip/dhcp.h include/lwip/dhcp.h src/include/netif/etharp.h include/netif/etharp.h src/include/netif/slipif.h include/netif/slipif.h src/include/netif/loopif.h include/netif/loopif.h src/netif/etharp.c src/netif/etharp.c src/netif/slipif.c src/netif/slipif.c src/netif/loopif.c src/netif/loopif.c src/netif/ppp/ppp.c src/netif/ppp/ppp.c src/netif/ppp/auth.c src/netif/ppp/auth.c src/netif/ppp/chap.c src/netif/ppp/chap.c src/netif/ppp/chpms.c src/netif/ppp/chpms.c src/netif/ppp/pap.c src/netif/ppp/pap.c src/netif/ppp/magic.c src/netif/ppp/magic.c src/netif/ppp/md5.c src/netif/ppp/md5.c src/netif/ppp/fsm.c src/netif/ppp/fsm.c src/netif/ppp/ipcp.c src/netif/ppp/ipcp.c src/netif/ppp/lcp.c src/netif/ppp/lcp.c src/netif/ppp/randm.c src/netif/ppp/randm.c src/netif/ppp/vj.c src/netif/ppp/vj.c src/netif/ppp/ppp.h src/netif/ppp/ppp.h src/netif/ppp/pppdebug.h src/netif/ppp/pppdebug.h src/netif/ppp/auth.h src/netif/ppp/auth.h src/netif/ppp/chap.h src/netif/ppp/chap.h src/netif/ppp/chpms.h src/netif/ppp/chpms.h src/netif/ppp/pap.h src/netif/ppp/pap.h src/netif/ppp/magic.h src/netif/ppp/magic.h src/netif/ppp/md5.h src/netif/ppp/md5.h src/netif/ppp/fsm.h src/netif/ppp/fsm.h src/netif/ppp/ipcp.h src/netif/ppp/ipcp.h src/netif/ppp/lcp.h src/netif/ppp/lcp.h src/netif/ppp/randm.h src/netif/ppp/randm.h src/netif/ppp/vj.h src/netif/ppp/vj.h src/netif/ppp/vjbsdhdr.h src/netif/ppp/vjbsdhdr.h ocproxy-1.60/contrib/ports/old/ecos/header000066400000000000000000000032711303453231400206350ustar00rootroot00000000000000//========================================================================== //####ECOSGPLCOPYRIGHTBEGIN#### // ------------------------------------------- // This file is part of eCos, the Embedded Configurable Operating System. // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. // // eCos is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the Free // Software Foundation; either version 2 or (at your option) any later version. // // eCos is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License // for more details. // // You should have received a copy of the GNU General Public License along // with eCos; if not, write to the Free Software Foundation, Inc., // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. // // As a special exception, if other files instantiate templates or use macros // or inline functions from this file, or you compile this file and link it // with other works to produce a work based on this file, this file does not // by itself cause the resulting work to be covered by the GNU General Public // License. However the source code for this file must still be made available // in accordance with section (3) of the GNU General Public License. // // This exception does not invalidate any other reasons why a work based on // this file might be covered by the GNU General Public License. // ------------------------------------------- //####ECOSGPLCOPYRIGHTEND#### //========================================================================== ocproxy-1.60/contrib/ports/old/ecos/mkepk000077500000000000000000000010461303453231400205150ustar00rootroot00000000000000#!/bin/sh #make an ecos epk from CVS lwIP if test $EPK"" == "" ; then echo you must set the EPK environment var to the dir you want the EPK in exit; fi if test $LWIP_CVS"" == "" ; then echo you must set the LWIP_CVS environment var to the dir you checked out the lwip module LWIP_CVS=../../../lwip; exit; fi EPK=$EPK/lwip_epk #cleanup rm -Rf $EPK #copy files from CVS xargs -n 2 ./copy < files #copy ecos specific files cd ecos && find . ! -path '*CVS*' -a -type f -exec cp --parents {} $EPK \; #make epk cd $EPK && tar czf lwip.epk * ocproxy-1.60/contrib/ports/old/rtxc/000077500000000000000000000000001303453231400175065ustar00rootroot00000000000000ocproxy-1.60/contrib/ports/old/rtxc/include/000077500000000000000000000000001303453231400211315ustar00rootroot00000000000000ocproxy-1.60/contrib/ports/old/rtxc/include/arch/000077500000000000000000000000001303453231400220465ustar00rootroot00000000000000ocproxy-1.60/contrib/ports/old/rtxc/include/arch/cc.h000066400000000000000000000040541303453231400226070ustar00rootroot00000000000000/* * Copyright (c) 2001-2003 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #ifndef __CC_H__ #define __CC_H__ typedef unsigned char u8_t; typedef signed char s8_t; typedef unsigned short u16_t; typedef signed short s16_t; typedef unsigned long u32_t; typedef signed long s32_t; #define U16_F "hu" #define S16_F "hd" #define X16_F "hx" #define U32_F "lu" #define S32_F "ld" #define X32_F "lx" #define PACK_STRUCT_BEGIN #define PACK_STRUCT_STRUCT #define PACK_STRUCT_END #define PACK_STRUCT_FIELD(x) x #endif /* __CC_H__ */ ocproxy-1.60/contrib/ports/old/rtxc/include/arch/cpu.h000066400000000000000000000032461303453231400230130ustar00rootroot00000000000000/* * Copyright (c) 2001-2003 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #ifndef __CPU_H__ #define __CPU_H__ #define BYTE_ORDER LITTLE_ENDIAN #endif /* __CPU_H__ */ ocproxy-1.60/contrib/ports/old/rtxc/include/arch/init.h000066400000000000000000000034141303453231400231640ustar00rootroot00000000000000/* * Copyright (c) 2001-2003 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #ifndef __ARCH_INIT_H__ #define __ARCH_INIT_H__ #define TCPIP_INIT_DONE(arg) tcpip_init_done(arg) void tcpip_init_done(void *); int wait_for_tcpip_init(void); #endif /* __ARCH_INIT_H__ */ ocproxy-1.60/contrib/ports/old/rtxc/include/arch/lib.h000066400000000000000000000032321303453231400227650ustar00rootroot00000000000000/* * Copyright (c) 2001-2003 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #ifndef __LIB_H__ #define __LIB_H__ #include #endif /* __LIB_H__ */ ocproxy-1.60/contrib/ports/old/rtxc/include/arch/perf.h000066400000000000000000000033401303453231400231530ustar00rootroot00000000000000/* * Copyright (c) 2001-2003 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #ifndef __PERF_H__ #define __PERF_H__ #define PERF_START /* null definition */ #define PERF_STOP(x) /* null definition */ #endif /* __PERF_H__ */ ocproxy-1.60/contrib/ports/old/rtxc/include/arch/sys_arch.h000066400000000000000000000034661303453231400240430ustar00rootroot00000000000000/* * Copyright (c) 2001-2003 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #ifndef __SYS_RTXC_H__ #define __SYS_RTXC_H__ #include "rtxcapi.h" #define SYS_MBOX_NULL (QUEUE)0 #define SYS_SEM_NULL (SEMA)0 typedef SEMA sys_sem_t; typedef QUEUE sys_mbox_t; typedef TASK sys_thread_t; #endif /* __SYS_RTXC_H__ */ ocproxy-1.60/contrib/ports/old/rtxc/include/netif/000077500000000000000000000000001303453231400222365ustar00rootroot00000000000000ocproxy-1.60/contrib/ports/old/rtxc/include/netif/cs8900if.h000066400000000000000000000034551303453231400236630ustar00rootroot00000000000000/* * Copyright (c) 2001-2003 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #ifndef __NETIF_CS8900IF_H__ #define __NETIF_CS8900IF_H__ #include "lwip/netif.h" void cs8900if_init(struct netif *); u8_t cs8900if_poll(struct netif *); void cs8900if_input(struct netif *); #endif /* __NETIF_CS8900IF_H__ */ ocproxy-1.60/contrib/ports/old/rtxc/include/netif/sioslipif.h000066400000000000000000000033471303453231400244170ustar00rootroot00000000000000/* * Copyright (c) 2001-2003 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #ifndef __NETIF_SIOSLIPIF_H__ #define __NETIF_SIOSLIPIF_H__ #include "lwip/netif.h" void sioslipif_init(struct netif *); #endif /* __NETIF_SIOSLIPIF_H__ */ ocproxy-1.60/contrib/ports/old/rtxc/lib.c000066400000000000000000000034521303453231400204240ustar00rootroot00000000000000/* * Copyright (c) 2001-2003 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ /* These are generic implementations of various library functions used * throughout the lwIP code. When porting, those should be optimized * for the particular processor architecture, preferably coded in * assembler. */ ocproxy-1.60/contrib/ports/old/rtxc/netif/000077500000000000000000000000001303453231400206135ustar00rootroot00000000000000ocproxy-1.60/contrib/ports/old/rtxc/netif/FILES000066400000000000000000000001131303453231400213730ustar00rootroot00000000000000sioslipif.c - Implementation of the SLIP protocol on top of a serial line. ocproxy-1.60/contrib/ports/old/rtxc/netif/sioslipif.c000066400000000000000000000112141303453231400227570ustar00rootroot00000000000000/* * Copyright (c) 2001-2003 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #include "lwip/debug.h" #include "lwip/def.h" #include "netif/sioslipif.h" #include "lwip/pbuf.h" #include "lwip/sys.h" #define SLIP_END 0300 #define SLIP_ESC 0333 #define SLIP_ESC_END 0334 #define SLIP_ESC_ESC 0335 /* This variable is used for passing the netif pointer between the threads. */ static struct netif *netif_pass; static int infd, outfd; /*-----------------------------------------------------------------------------------*/ static void sio_send(u8_t c) { write(outfd, &c, 1); } /*-----------------------------------------------------------------------------------*/ static u8_t sio_recv(void) { u8_t c; read(infd, &c, 1); return c; } /*-----------------------------------------------------------------------------------*/ static int sioslipif_output(struct netif *netif, struct pbuf *p, struct ip_addr *ipaddr) { struct pbuf *q; int i; u8_t c; /* Send pbuf out on the serial I/O device. */ sio_send(SLIP_END); for(q = p; q != NULL; q = q->next) { for(i = 0; i < q->len; i++) { c = ((u8_t *)q->payload)[i]; switch (c) { case SLIP_END: sio_send(SLIP_ESC); sio_send(SLIP_ESC_END); break; case SLIP_ESC: sio_send(SLIP_ESC); sio_send(SLIP_ESC_ESC); break; default: sio_send(c); break; } } } sio_send(SLIP_END); return 0; } /*-----------------------------------------------------------------------------------*/ static struct pbuf * sioslipif_input(void) { u8_t c; struct pbuf *p, *q; int recved; int i; p = pbuf_alloc(PBUF_LINK, PBUF_MAX_SIZE, PBUF_POOL); q = p; recved = i = 0; while (1) { c = sio_recv(); switch (c) { case SLIP_END: if (recved > 0) { /* Received whole packet. */ pbuf_realloc(p, recved); return p; } break; case SLIP_ESC: c = sio_recv(); switch (c) { case SLIP_ESC_END: c = SLIP_END; break; case SLIP_ESC_ESC: c = SLIP_ESC; break; } /* FALLTHROUGH */ default: if (recved < p->tot_len && q != NULL) { ((u8_t *)q->payload)[i] = c; recved++; i++; if (i >= q->len) { i = 0; q = q->next; } } break; } } } /*-----------------------------------------------------------------------------------*/ static void sioslipif_loop(void) { struct pbuf *p; struct netif *netif; netif = netif_pass; while (1) { p = sioslipif_input(); netif->input(p, netif); } } /*-----------------------------------------------------------------------------------*/ void sioslipif_init(struct netif *netif) { netif->state = NULL; netif->name[0] = 's'; netif->name[1] = 'l'; netif->output = sioslipif_output; netif_pass = netif; sys_thread_new("sioslipif_loop", (void *)sioslipif_loop, NULL, DEFAULT_THREAD_STACKSIZE, DEFAULT_THREAD_PRIO); /* Do some magic to make it possible to receive data from the serial I/O device. */ } /*-----------------------------------------------------------------------------------*/ ocproxy-1.60/contrib/ports/old/rtxc/perf.c000066400000000000000000000032011303453231400206020ustar00rootroot00000000000000/* * Copyright (c) 2001-2003 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #include "arch/perf.h" void perf_init(char *fname) { } ocproxy-1.60/contrib/ports/old/rtxc/sys_arch.c000066400000000000000000000172671303453231400215020ustar00rootroot00000000000000/* * Copyright (c) 2001-2003 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #include "lwip/debug.h" #include "lwip/def.h" #include "lwip/sys.h" #include "lwip/mem.h" #include "rtxcapi.h" #include "csema.h" #include "cclock.h" #include "cqueue.h" #include "cres.h" #include "cpart.h" #include "ctask.h" struct timeoutlist { struct sys_timeouts timeouts; TASK pid; }; #define SYS_THREAD_MAX 2 static struct timeoutlist timeoutlist[SYS_THREAD_MAX]; static u16_t nextthread = 0; /*-----------------------------------------------------------------------------------*/ sys_mbox_t sys_mbox_new(void) { QUEUE mbox; KS_dequeuew(IP_MBOXQ, &mbox); KS_purgequeue(mbox); return mbox; } /*-----------------------------------------------------------------------------------*/ void sys_mbox_free(sys_mbox_t mbox) { KS_enqueue(IP_MBOXQ, &mbox); } /*-----------------------------------------------------------------------------------*/ void sys_mbox_post(sys_mbox_t mbox, void *data) { if (KS_enqueue(mbox, &data) != RC_GOOD) { } } /*-----------------------------------------------------------------------------------*/ u16_t sys_arch_mbox_fetch(sys_mbox_t mbox, void **data, u16_t timeout) { KSRC ret; u16_t wtime = 1; if (timeout == 0) { LWIP_DEBUGF(SYS_DEBUG, ("PID: %d sys_mbox_fetch: without timeouts\n",KS_inqtask())); KS_dequeuew(mbox, data); } else { ret = KS_dequeuet(mbox, data, (TICKS)timeout/CLKTICK); if (ret == RC_TIMEOUT) { /* The call timed out, so we return 0. */ wtime = 0; } else { /* Calculate time we waited for the message to arrive. */ /* XXX: we cheat and just pretend that we waited for half the timeout value! */ wtime = timeout / 2; /* Make sure we don't return 0 here. */ if (wtime == 0) { wtime = 1; } } } return wtime; } /*-----------------------------------------------------------------------------------*/ sys_sem_t sys_sem_new(u8_t count) { SEMA sem; KS_dequeuew(IP_SEMQ, &sem); KS_pend(sem); if (count > 0) { KS_signal(sem); } return sem; } /*-----------------------------------------------------------------------------------*/ u16_t sys_arch_sem_wait(sys_sem_t sem, u16_t timeout) { KSRC ret; u16_t wtime = 1; if (timeout == 0) { LWIP_DEBUGF(SYS_DEBUG, ("PID: %d sys_mbox_fetch: without timeouts\n",KS_inqtask())); KS_wait(sem); } else { ret = KS_waitt(sem, (TICKS)timeout/CLKTICK); if (ret == RC_TIMEOUT) { /* The call timed out, so we return 0. */ wtime = 0; } else { /* Calculate time we waited for the message to arrive. */ /* XXX: we cheat and just pretend that we waited for half the timeout value! */ wtime = timeout / 2; /* Make sure we don't return 0 here. */ if (wtime == 0) { wtime = 1; } } } return wtime; } /*-----------------------------------------------------------------------------------*/ void sys_sem_signal(sys_sem_t sem) { KS_signal(sem); } /*-----------------------------------------------------------------------------------*/ void sys_sem_free(sys_sem_t sem) { KS_enqueue(IP_SEMQ, &sem); } /*-----------------------------------------------------------------------------------*/ void sys_init(void) { /* posta in alla semaforer i IP_SEMQ, posta in alla mboxar i IP_MBOXQ */ QUEUE mbox; SEMA sem; mbox = IP_Q_01; KS_enqueue(IP_MBOXQ, &mbox); mbox = IP_Q_02; KS_enqueue(IP_MBOXQ, &mbox); mbox = IP_Q_03; KS_enqueue(IP_MBOXQ, &mbox); mbox = IP_Q_04; KS_enqueue(IP_MBOXQ, &mbox); mbox = IP_Q_05; KS_enqueue(IP_MBOXQ, &mbox); mbox = IP_Q_06; KS_enqueue(IP_MBOXQ, &mbox); mbox = IP_Q_07; KS_enqueue(IP_MBOXQ, &mbox); mbox = IP_Q_08; KS_enqueue(IP_MBOXQ, &mbox); mbox = IP_Q_09; KS_enqueue(IP_MBOXQ, &mbox); mbox = IP_Q_10; KS_enqueue(IP_MBOXQ, &mbox); mbox = IP_Q_11; KS_enqueue(IP_MBOXQ, &mbox); mbox = IP_Q_12; KS_enqueue(IP_MBOXQ, &mbox); mbox = IP_Q_13; KS_enqueue(IP_MBOXQ, &mbox); mbox = IP_Q_14; KS_enqueue(IP_MBOXQ, &mbox); mbox = IP_Q_15; KS_enqueue(IP_MBOXQ, &mbox); sem = IP_S_01; KS_enqueue(IP_SEMQ, &sem); sem = IP_S_02; KS_enqueue(IP_SEMQ, &sem); sem = IP_S_03; KS_enqueue(IP_SEMQ, &sem); } /*-----------------------------------------------------------------------------------*/ struct sys_timeouts * sys_arch_timeouts(void) { int i; TASK pid; struct timeoutlist *tl; LWIP_DEBUGF(SYS_DEBUG, ("PID: %d sys_mbox_fetch: timeoutlist not empty\n",KS_inqtask())); pid = KS_inqtask(); for(i = 0; i < nextthread; i++) { tl = &timeoutlist[i]; if (tl->pid == pid) { LWIP_DEBUGF(SYS_DEBUG, ("PID: %d sys_mbox_fetch: corresponding pid found!\n",KS_inqtask())); return &(tl->timeouts); } } /* Error! */ return NULL; } /*-----------------------------------------------------------------------------------*/ struct sys_thread_arg { void (* thread)(void *); void *threadarg; SEMA sem; }; /*-----------------------------------------------------------------------------------*/ static void sys_thread(void) { struct sys_thread_arg *arg; void (* thread)(void *); void *threadarg; arg = KS_inqtask_arg(0); if (arg != NULL) { timeoutlist[nextthread].timeouts.next = NULL; timeoutlist[nextthread].pid = KS_inqtask(); ++nextthread; thread = arg->thread; threadarg = arg->threadarg; KS_signal(arg->sem); thread(threadarg); } KS_terminate(0); } /*-----------------------------------------------------------------------------------*/ sys_thread_t sys_thread_new(char *name, void (* function)(void *arg), void *arg, int istacksize, int prio) { TASK newtask; PRIORITY pri = prio; /* This may have to be changed. */ char *stack; /** @todo Replace this local constant by the "istacksize" parameter */ int stacksize = 512; /* This may have to be changed. */ struct sys_thread_arg threadarg; newtask = KS_alloc_task(); stack = KS_allocw(MAP512); KS_deftask(newtask, pri, (char ks_stk *)stack, (size_t)stacksize, (void (*)(void))sys_thread); threadarg.thread = function; threadarg.threadarg = arg; threadarg.sem = THRDSYNC; KS_deftask_arg(newtask, &threadarg); KS_execute(newtask); KS_wait(THRDSYNC); return newtask; } ocproxy-1.60/contrib/ports/old/ti_c6711/000077500000000000000000000000001303453231400177635ustar00rootroot00000000000000ocproxy-1.60/contrib/ports/old/ti_c6711/FILES000066400000000000000000000011151303453231400205460ustar00rootroot00000000000000This directory contains architecture and compiler specific stuff for porting lwIP to the TI TMS320C6711 DSP. It's done on the official C6711 DSK board, in CCS v2.10. The sequential API has not been ported; its functions are empties. If someone is interested in adding a sequential API, please contact the author (see below). The ethernet connection was based on an daughtercard design by the author. Schematic files can be found as part of project "ucos-lwip-c6x" on SourceForge.net The daughtercard is NE2000 compliant. And the driver supports interrupts. Zeng, Ming ocproxy-1.60/contrib/ports/old/ti_c6711/[Note] opt setting of lwIP .txt000066400000000000000000000042701303453231400254260ustar00rootroot00000000000000[Note]: Special options setting of lwIP in this project (for using it with uC/OS-II on TI C6000 DSP) ******************************************************************************************* This port was for project ucos-lwip-c6x (http://gro.clinux.org/projects/ucos-lwip-c6x/). For the moment we were writing this note, lwIP v1.1.0 was used in this project. This note was written in Jan.22 2005 by zengming99@mails.tsinghua.edu.cn. ******************************************************************************************* Usually, options of lwIP can be set in file "lwipopts.h". It was included by "opt.h", amd all options would be set as default value in "opt.h" if they were not defined in "lwipopts.h". Each project should have its own "lwiports.h", and keep "opt.h" as it was. In this project, for making lwIP work with uC/OS-II on a 32bits TI DSP, following options should be set: ------------------------------------------------------------------------------------ 1. Define symbol "LWIP_PROVIDE_ERRNO" in compiler of CodeComposerStudio 2. #define MEM_ALIGNMENT 4 (in "lwipopts.h" ) #define ETH_PAD_SIZE 2 (in "lwipopts.h" ) For the struct align problem on 32bits DSP. 3. #define ARP_QUEUEING 0 (in "lwipopts.h") ARP_QUEUEING has a bug in lwIP v1.0.0 with TCP 4. #define LWIP_TASK_MAX 5 (in "sys_arch.h" ) #define LWIP_START_PRIO 10 (in "sys_arch.h" ) #define TCPIP_THREAD_PRIO 5 (in "lwipopts.h" ) The default TCPIP_THREAD used priority 5. And, 5 lwIP threads were allowed, user defined lwIP thread should have its priority between 10 ~ 14. 5. #define SYS_LIGHTWEIGHT_PROT 1 (in "lwipopts.h" ) #define SYS_ARCH_DECL_PROTECT(lev) (in "sys_arch.h" ) #define SYS_ARCH_PROTECT(lev) OS_ENTER_CRITICAL() (in "sys_arch.h" ) #define SYS_ARCH_UNPROTECT(lev) OS_EXIT_CRITICAL() (in "sys_arch.h" ) These were very important when ethernet driver used intrrupt to check packet and pBuf function was called in ISR. Or else, uC/OS-II would run away. A much better and clean method is to set up a thread for the driver, in ISR just check packet and post MailBox to the thread. Zeng, Ming 2005-01-18 ocproxy-1.60/contrib/ports/old/ti_c6711/include/000077500000000000000000000000001303453231400214065ustar00rootroot00000000000000ocproxy-1.60/contrib/ports/old/ti_c6711/include/arch/000077500000000000000000000000001303453231400223235ustar00rootroot00000000000000ocproxy-1.60/contrib/ports/old/ti_c6711/include/arch/cc.h000066400000000000000000000050231303453231400230610ustar00rootroot00000000000000/* * Copyright (c) 2001, Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the Institute nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * * $Id: cc.h,v 1.1 2007/06/14 12:34:09 kieranm Exp $ */ #ifndef __CC_H__ #define __CC_H__ typedef unsigned char u8_t; typedef signed char s8_t; typedef unsigned short u16_t; typedef signed short s16_t; typedef unsigned int u32_t; typedef signed int s32_t; typedef u32_t mem_ptr_t; #define U16_F "hu" #define S16_F "hd" #define X16_F "hx" #define U32_F "u" #define S32_F "d" #define X32_F "x" #define BYTE_ORDER LITTLE_ENDIAN #define PACK_STRUCT_FIELD(x) x//; #pragma STRUCT_ALIGN(x,1) #define PACK_STRUCT_STRUCT #define PACK_STRUCT_BEGIN #define PACK_STRUCT_END #ifndef LWIP_PLATFORM_DIAG #define LWIP_PLATFORM_DIAG(x) do {printf x;} while(0) #endif #ifndef LWIP_PLATFORM_ASSERT #define LWIP_PLATFORM_ASSERT(x) do {printf("Assertion \"%s\" failed at line %d in %s\n", x, __LINE__, __FILE__); fflush(NULL); abort();} while(0) #endif #endif /* __CC_H__ */ ocproxy-1.60/contrib/ports/old/ti_c6711/include/arch/init.h000066400000000000000000000035611303453231400234440ustar00rootroot00000000000000/* * Copyright (c) 2001, Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the Institute nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * * $Id: init.h,v 1.1 2007/06/14 12:34:09 kieranm Exp $ */ #ifndef __ARCH_INIT_H__ #define __ARCH_INIT_H__ #define TCPIP_INIT_DONE(arg) sys_sem_signal(*(sys_sem_t *)arg) #endif /* __ARCH_INIT_H__ */ ocproxy-1.60/contrib/ports/old/ti_c6711/include/arch/lib.h000066400000000000000000000036111303453231400232430ustar00rootroot00000000000000/* * Copyright (c) 2001, Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the Institute nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * * $Id: lib.h,v 1.1 2007/06/14 12:34:09 kieranm Exp $ */ #ifndef __LIB_H__ #define __LIB_H__ #include "arch/cc.h" u16_t htons(u16_t n); u16_t ntohs(u16_t n); u32_t htonl(u32_t n); u32_t ntohl(u32_t n); #endif /* __LIB_H__ */ ocproxy-1.60/contrib/ports/old/ti_c6711/include/arch/perf.h000066400000000000000000000035671303453231400234430ustar00rootroot00000000000000/* * Copyright (c) 2001, Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the Institute nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * * $Id: perf.h,v 1.1 2007/06/14 12:34:09 kieranm Exp $ */ #ifndef __PERF_H__ #define __PERF_H__ #define PERF_START /* null definition */ #define PERF_STOP(x) /* null definition */ #endif /* __PERF_H__ */ ocproxy-1.60/contrib/ports/old/ti_c6711/include/arch/sys_arch.h000066400000000000000000000053251303453231400243140ustar00rootroot00000000000000/* ********************************************************************************************************* * lwIP TCP/IP Stack * port for uC/OS-II RTOS on TIC6711 DSK * * File : sys_arch.h * By : ZengMing @ DEP,Tsinghua University,Beijing,China * Reference: YangYe's source code for SkyEye project ********************************************************************************************************* */ #ifndef __SYS_ARCH_H__ #define __SYS_ARCH_H__ #include "os_cpu.h" #include "os_cfg.h" #include "ucos_ii.h" #define LWIP_STK_SIZE 4096 #define LWIP_TASK_MAX 5 //max number of lwip tasks #define LWIP_START_PRIO 5 //first prio of lwip tasks //!!!! so priority of lwip tasks is from 5-9 #define SYS_MBOX_NULL (void*)0 #define SYS_SEM_NULL (void*)0 #define MAX_QUEUES 20 #define MAX_QUEUE_ENTRIES 20 typedef struct { OS_EVENT* pQ; void* pvQEntries[MAX_QUEUE_ENTRIES]; } TQ_DESCR, *PQ_DESCR; typedef OS_EVENT* sys_sem_t; typedef PQ_DESCR sys_mbox_t;//the structure defined above typedef INT8U sys_thread_t; /* Critical Region Protection */ /* These functions must be implemented in the sys_arch.c file. In some implementations they can provide a more light-weight protection mechanism than using semaphores. Otherwise semaphores can be used for implementation */ /** SYS_ARCH_DECL_PROTECT * declare a protection variable. This macro will default to defining a variable of * type sys_prot_t. If a particular port needs a different implementation, then * this macro may be defined in sys_arch.h. */ #define SYS_ARCH_DECL_PROTECT(lev) /** SYS_ARCH_PROTECT * Perform a "fast" protect. This could be implemented by * disabling interrupts for an embedded system or by using a semaphore or * mutex. The implementation should allow calling SYS_ARCH_PROTECT when * already protected. The old protection level is returned in the variable * "lev". This macro will default to calling the sys_arch_protect() function * which should be implemented in sys_arch.c. If a particular port needs a * different implementation, then this macro may be defined in sys_arch.h */ #define SYS_ARCH_PROTECT(lev) OS_ENTER_CRITICAL() /** SYS_ARCH_UNPROTECT * Perform a "fast" set of the protection level to "lev". This could be * implemented by setting the interrupt level to "lev" within the MACRO or by * using a semaphore or mutex. This macro will default to calling the * sys_arch_unprotect() function which should be implemented in * sys_arch.c. If a particular port needs a different implementation, then * this macro may be defined in sys_arch.h */ #define SYS_ARCH_UNPROTECT(lev) OS_EXIT_CRITICAL() #endif ocproxy-1.60/contrib/ports/old/ti_c6711/include/netif/000077500000000000000000000000001303453231400225135ustar00rootroot00000000000000ocproxy-1.60/contrib/ports/old/ti_c6711/include/netif/ne2kif.h000066400000000000000000000235731303453231400240540ustar00rootroot00000000000000/* ********************************************************************************************************* * lwIP TCP/IP Stack * port for uC/OS-II RTOS on TIC6711 DSK * * File : tcp_ip.c * By : ZengMing @ DEP,Tsinghua University,Beijing,China * Reference: YangYe's source code for SkyEye project ********************************************************************************************************* */ #ifndef _NE2K_H_ #define _NE2K_H_ #include "lwip/netif.h" #define MIN_PACKET_SIZE 60 /* smallest legal size packet, no fcs */ #define MAX_PACKET_SIZE 1514 /* largest legal size packet, no fcs */ #define DELAY 0x590b2 //0.5s test by ming #define DELAY_2S 0xbf000 //2s test #define DELAY_MS 0x38F4 //20ms test /** * Driver functions. */ err_t ne2k_init(struct netif *netif); static void low_level_init(struct netif * netif); static void arp_timer(void *arg); static err_t low_level_output(struct netif * netif,struct pbuf *p); u16_t write_AX88796(u8_t * buf, u16_t remote_Addr, u16_t Count); static void ne2k_input(struct netif *netif); static struct pbuf * low_level_input(struct netif *netif); u16_t read_AX88796(u8_t * buf, u16_t remote_Addr, u16_t Count); /*---------------------------------------- * Register header of C6x DSP *----------------------------------------*/ #define EMIF_CE2 0x01800010 /* Define QDMA Memory Mapped Registers */ #define QDMA_OPT 0x02000000 /* Address of QDMA options register */ #define QDMA_SRC 0x02000004 /* Address of QDMA SRC address register */ #define QDMA_CNT 0x02000008 /* Address of QDMA counts register */ #define QDMA_DST 0x0200000C /* Address of QDMA DST address register */ #define QDMA_IDX 0x02000010 /* Address of QDMA index register */ /* Define QDMA Pseudo Registers */ #define QDMA_S_OPT 0x02000020 /* Address of QDMA options register */ #define QDMA_S_SRC 0x02000024 /* Address of QDMA SRC address register */ #define QDMA_S_CNT 0x02000028 /* Address of QDMA counts register */ #define QDMA_S_DST 0x0200002C /* Address of QDMA DST address register */ #define QDMA_S_IDX 0x02000030 /* Address of QDMA index register */ /*---------------------------------------- * Register header of NE2000 chip *----------------------------------------*/ #define Base_ADDR 0xA0000200 ///CE2 space of DSK is 0xA0000000 // and ethernet chip is at 0x200 by default // actual address on DSK #define EN_CMD *(unsigned char *)(Base_ADDR+0x00) /* The command register (for all pages) */ #define EN_DATA *(unsigned short *)(Base_ADDR+0x10) /*by ming (change to 16bit) Remote DMA Port10~17h (for all pages)*/ #define EN_RESET *(unsigned char *)(Base_ADDR+0x1F) /* Reset Port 1fh(for all pages) */ /* Page 0 register offsets */ #define EN0_STARTPG *(unsigned char *)(Base_ADDR+0x01) /* WR Starting page of ring buffer */ #define EN0_STOPPG *(unsigned char *)(Base_ADDR+0x02) /* WR Ending page +1 of ring buffer */ #define EN0_BOUNDARY *(unsigned char *)(Base_ADDR+0x03) /* RD/WR Boundary page of ring buffer */ #define EN0_TSR *(unsigned char *)(Base_ADDR+0x04) /* RD Transmit status reg */ #define EN0_TPSR *(unsigned char *)(Base_ADDR+0x04) /* WR Transmit starting page */ #define EN0_NCR *(unsigned char *)(Base_ADDR+0x05) /* RD Number of collision reg */ #define EN0_TCNTLO *(unsigned char *)(Base_ADDR+0x05) /* WR Low byte of tx byte count */ #define EN0_CRP *(unsigned char *)(Base_ADDR+0x06) /* Current Page Register */ #define EN0_TCNTHI *(unsigned char *)(Base_ADDR+0x06) /* WR High byte of tx byte count */ #define EN0_ISR *(unsigned char *)(Base_ADDR+0x07) /* RD/WR Interrupt status reg */ #define EN0_CRDALO *(unsigned char *)(Base_ADDR+0x08) /* RD low byte of current remote dma add*/ #define EN0_RSARLO *(unsigned char *)(Base_ADDR+0x08) /* WR Remote start address reg 0 */ #define EN0_CRDAHI *(unsigned char *)(Base_ADDR+0x09) /* RD high byte, current remote dma add.*/ #define EN0_RSARHI *(unsigned char *)(Base_ADDR+0x09) /* WR Remote start address reg 1 */ #define EN0_RCNTLO *(unsigned char *)(Base_ADDR+0x0A) /* WR Remote byte count reg 0 */ #define EN0_RCNTHI *(unsigned char *)(Base_ADDR+0x0B) /* WR Remote byte count reg 1 */ #define EN0_RSR *(unsigned char *)(Base_ADDR+0x0C) /* RD RX status reg */ #define EN0_RXCR *(unsigned char *)(Base_ADDR+0x0C) /* WR RX configuration reg */ #define EN0_TXCR *(unsigned char *)(Base_ADDR+0x0D) /* WR TX configuration reg */ #define EN0_DCFG *(unsigned char *)(Base_ADDR+0x0E) /* WR Data configuration reg */ #define EN0_IMR *(unsigned char *)(Base_ADDR+0x0F) /* WR Interrupt mask reg */ /* Page 1 register offsets */ #define EN1_PAR0 *(unsigned char *)(Base_ADDR+0x01) /* RD/WR This board's physical ethernet addr */ #define EN1_PAR1 *(unsigned char *)(Base_ADDR+0x02) #define EN1_PAR2 *(unsigned char *)(Base_ADDR+0x03) #define EN1_PAR3 *(unsigned char *)(Base_ADDR+0x04) #define EN1_PAR4 *(unsigned char *)(Base_ADDR+0x05) #define EN1_PAR5 *(unsigned char *)(Base_ADDR+0x06) #define EN1_CURR *(unsigned char *)(Base_ADDR+0x07) /* RD/WR current page reg */ #define EN1_CURPAG EN1_CURR #define EN1_MAR0 *(unsigned char *)(Base_ADDR+0x08) /* RD/WR Multicast filter mask array (8 bytes) */ #define EN1_MAR1 *(unsigned char *)(Base_ADDR+0x09) #define EN1_MAR2 *(unsigned char *)(Base_ADDR+0x0A) #define EN1_MAR3 *(unsigned char *)(Base_ADDR+0x0B) #define EN1_MAR4 *(unsigned char *)(Base_ADDR+0x0C) #define EN1_MAR5 *(unsigned char *)(Base_ADDR+0x0D) #define EN1_MAR6 *(unsigned char *)(Base_ADDR+0x0E) #define EN1_MAR7 *(unsigned char *)(Base_ADDR+0x0F) /* Command Values at EN_CMD */ #define EN_STOP 0x01 /* Stop and reset the chip */ #define EN_START 0x02 /* Start the chip, clear reset */ #define EN_TRANS 0x04 /* Transmit a frame */ #define EN_RREAD 0x08 /* Remote read */ #define EN_RWRITE 0x10 /* Remote write */ #define EN_NODMA 0x20 /* Remote DMA */ #define EN_PAGE0 0x00 /* Select page chip registers */ #define EN_PAGE1 0x40 /* using the two high-order bits */ //--------------------------------- // Values for Ring-Buffer setting //--------------------------------- #define NE_START_PG 0x40 /* First page of TX buffer */ #define NE_STOP_PG 0x80 /* Last page + 1 of RX Ring */ #define TX_PAGES 6 #define TX_START_PG NE_START_PG //0x40 #define RX_START_PG NE_START_PG + TX_PAGES //0x46 #define RX_CURR_PG RX_START_PG + 1 //0x47 #define RX_STOP_PG NE_STOP_PG //0x80 /* Bits in EN0_ISR - Interrupt status register (RD WR) */ #define ENISR_RX 0x01 /* Receiver, no error */ #define ENISR_TX 0x02 /* Transceiver, no error */ #define ENISR_RX_ERR 0x04 /* Receiver, with error */ //½ÓÊÕÊý¾Ý°ü³ö´í¡£×öÖØÐÂÉèÖÃBNRY£½CURR´¦Àí¡£ #define ENISR_TX_ERR 0x08 /* Transmitter, with error */ //ÓÉÓÚ³åÍ»´ÎÊý¹ý¶à£¬·¢Ëͳö´í¡£×öÖØ·¢´¦Àí #define ENISR_OVER 0x10 /* Receiver overwrote the ring */ /* Gap area of receiver ring buffer was disappeared */ //Íø¿¨ÄÚ´æÒç³ö¡£×öÈí¼þÖØÆôÍø¿¨´¦Àí¡£¼ûÊֲᡣ #define ENISR_COUNTERS 0x20 /* Counters need emptying */ /* MSB of network tally counter became 1 */ //³ö´í¼ÆÊýÆ÷Öжϣ¬ÆÁ±Îµô£¨ÆÁ±ÎÓÃIMR¼Ä´æÆ÷£©¡£ #define ENISR_RDC 0x40 /* remote dma complete */ //ÆÁ±Îµô¡£ÂÖѯµÈ´ýDMA½áÊø¡£ #define ENISR_RESET 0x80 /* Reset completed */ //Íø¿¨Reset£¬ÆÁ±Îµô¡£ #define ENISR_ALL 0x3f /* 3f Interrupts we will enable */ /* RST RDC CNT OVW TXE RXE PTX PRX */ /* Bits in EN0_RXCR - RX configuration reg */ //#define ENRXCR_RXCONFIG 0x04 /* EN0_RXCR: broadcasts,no multicast,errors */ #define ENRXCR_RXCONFIG 0x00 /* EN0_RXCR: only unicast */ #define ENRXCR_CRC 0x01 /* Save error packets(admit) */ #define ENRXCR_RUNT 0x02 /* Accept runt pckt(below 64bytes) */ #define ENRXCR_BCST 0x04 /* Accept broadcasts when 1 */ #define ENRXCR_MULTI 0x08 /* Multicast (if pass filter) when 0 */ #define ENRXCR_PROMP 0x10 /* Promiscuous physical addresses when 1*/ /* when 0,accept assigned PAR0~5 address */ #define ENRXCR_MON 0x20 /* Monitor mode (no packets rcvd) */ /* Bits in EN0_TXCR - TX configuration reg */ #define ENTXCR_TXCONFIG 0x00 /* Normal transmit mode */ #define ENTXCR_CRC 0x01 /* inhibit CRC,do not append crc when 1 */ #define ENTXCR_LOOP 0x02 /* set internal loopback mode ? */ #define ENTXCR_LB01 0x06 /* encoded loopback control ? */ #define ENTXCR_ATD 0x08 /* auto tx disable */ /* when 1, if specified multicast packet was received, disable transmit */ #define ENTXCR_OFST 0x10 /* collision offset enable */ /* selection of collision algorithm. When 0, gererally back-off algorithm select */ #endif /* _NE2K_H_ */ ocproxy-1.60/contrib/ports/old/ti_c6711/lib_arch.c000066400000000000000000000046021303453231400216740ustar00rootroot00000000000000/* * Copyright (c) 2001, Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the Institute nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * * $Id: lib_arch.c,v 1.1 2007/06/14 12:34:09 kieranm Exp $ */ /* These are generic implementations of various library functions used * throughout the lwIP code. When porting, those should be optimized * for the particular processor architecture, preferably coded in * assembler. */ //yangye 2003-1-22 #include "lwip/arch.h" /*u16_t htons(u16_t n) { return ((n & 0xff) << 8) | ((n & 0xff00) >> 8); } u16_t ntohs(u16_t n) { return htons(n); } u32_t htonl(u32_t n) { return ((n & 0xff) << 24) | ((n & 0xff00) << 8) | ((n & 0xff0000) >> 8) | ((n & 0xff000000) >> 24); } u32_t ntohl(u32_t n) { return htonl(n); }*/ /*-----------------------------------------------------------------------------------*/ ocproxy-1.60/contrib/ports/old/ti_c6711/netif/000077500000000000000000000000001303453231400210705ustar00rootroot00000000000000ocproxy-1.60/contrib/ports/old/ti_c6711/netif/ne2kif.c000066400000000000000000000416421303453231400224210ustar00rootroot00000000000000/* ********************************************************************************************************* * lwIP TCP/IP Stack * port for uC/OS-II RTOS on TIC6711 DSK * * File : tcp_ip.c * By : ZengMing @ DEP,Tsinghua University,Beijing,China * Reference: YangYe's source code for SkyEye project ********************************************************************************************************* */ #include "lwip/opt.h" #include "lwip/def.h" #include "lwip/mem.h" #include "lwip/pbuf.h" #include "lwip/sys.h" #include #include "netif/etharp.h" #include "netif/ne2kif.h" /* define this to use QDMA, which is much faster! */ #define QDMA_Enabled /* Define those to better describe your network interface. */ #define IFNAME0 'e' #define IFNAME1 't' struct ne2k_if { struct eth_addr *ethaddr; //MAC Address }; struct netif *ne2k_if_netif; /*---------------------------------------------------------------------------------------- **************************************************************************************** ----------------------------------------------------------------------------------------*/ /* * ethernetif_init(): * * Should be called at the beginning of the program to set up the * network interface. It calls the function low_level_init() to do the * actual setup of the hardware. * */ err_t ne2k_init(struct netif *netif) { struct ne2k_if *ne2k_if; ne2k_if = mem_malloc(sizeof(struct ne2k_if));//MAC Address if (ne2k_if == NULL) { LWIP_DEBUGF(NETIF_DEBUG,("ne2k_init: out of memory!\n")); return ERR_MEM; } netif->state = ne2k_if; netif->name[0] = IFNAME0; netif->name[1] = IFNAME1; netif->output = etharp_output; netif->linkoutput = low_level_output; ne2k_if->ethaddr = (struct eth_addr *)&(netif->hwaddr[0]); low_level_init(netif); etharp_init(); sys_timeout(ARP_TMR_INTERVAL, arp_timer, NULL); return ERR_OK; } /** * arp_timer. */ static void arp_timer(void *arg) { etharp_tmr(); sys_timeout(ARP_TMR_INTERVAL, (sys_timeout_handler)arp_timer, NULL); } /** * Initialize the ne2k ethernet chip, resetting the interface and getting the ethernet * address. */ static void low_level_init(struct netif * netif) { u16_t i; struct ne2k_if *ne2k_if; ne2k_if = netif->state; // the meaning of "netif->state" can be defined in drivers, here for MAC address! netif->hwaddr_len=6; netif->mtu = 1500; netif->flags = NETIF_FLAG_BROADCAST; // ---------- start ------------- *(u32_t *)EMIF_CE2 = 0x11D4C714; // Set CE2 to 16bits mode, // AX88796 required no less than 160ns period i = EN_RESET; //this instruction let NE2K chip soft reset for (i=0;iethaddr->addr[0] = (u8_t) 0x12;//MAC_addr.addr[0]; ne2k_if->ethaddr->addr[1] = (u8_t) 0x34;//MAC_addr.addr[1]; ne2k_if->ethaddr->addr[2] = (u8_t) 0x56;//MAC_addr.addr[2]; ne2k_if->ethaddr->addr[3] = (u8_t) 0x78;//MAC_addr.addr[3]; ne2k_if->ethaddr->addr[4] = (u8_t) 0x9a;//MAC_addr.addr[4]; ne2k_if->ethaddr->addr[5] = (u8_t) 0xe0;//MAC_addr.addr[5]; /* Initialize the multicast list to reject-all. If we enable multicast the higher levels can do the filtering. */ EN1_MAR0 = (u8_t) 0x00; EN1_MAR1 = (u8_t) 0x00; EN1_MAR2 = (u8_t) 0x00; EN1_MAR3 = (u8_t) 0x00; EN1_MAR4 = (u8_t) 0x00; EN1_MAR5 = (u8_t) 0x00; EN1_MAR6 = (u8_t) 0x00; EN1_MAR7 = (u8_t) 0x00; EN_CMD = (u8_t) (EN_PAGE0 + EN_NODMA + EN_STOP); EN0_IMR = (u8_t) (ENISR_OVER + ENISR_RX + ENISR_RX_ERR); EN0_TXCR = (u8_t) 0x00; //E0 //TCR EN0_RXCR = (u8_t) 0x44; //CC //RCR EN_CMD = (u8_t) (EN_PAGE0 + EN_NODMA + EN_START); EN0_ISR = (u8_t) 0xff; // clear the all flag bits in EN0_ISR ne2k_if_netif = netif; } /*---------------------------------------------------------------------------------------- **************************************************************************************** ----------------------------------------------------------------------------------------*/ /* * low_level_output(): * * Should do the actual transmission of the packet. The packet is * contained in the pbuf that is passed to the function. This pbuf * might be chained. * */ static err_t low_level_output(struct netif * netif, struct pbuf *p) { struct pbuf *q; u16_t packetLength,remote_Addr,Count; u8_t *buf; packetLength = p->tot_len - ETH_PAD_SIZE; //05 01 millin if ((packetLength) < 64) packetLength = 64; //add pad by the AX88796 automatically // turn off RX int EN0_IMR = (u8_t) (ENISR_OVER); /* We should already be in page 0, but to be safe... */ EN_CMD = (u8_t) (EN_PAGE0 + EN_START + EN_NODMA); // clear the RDC bit EN0_ISR = (u8_t) ENISR_RDC; remote_Addr = (u16_t)(TX_START_PG<<8); /* * Write packet to ring buffers. */ for(q = p; q != NULL; q = q->next) { /* Send the data from the pbuf to the interface, one pbuf at a time. The size of the data in each pbuf is kept in the ->len variable. */ Count = q->len; buf = q->payload; if (q == p){ buf += ETH_PAD_SIZE; Count -= ETH_PAD_SIZE;//Pad in Eth_hdr struct } // Write data to AX88796 remote_Addr = write_AX88796(buf, remote_Addr, Count); } //for /* Just send it, and does not check */ while (EN_CMD & EN_TRANS); EN0_TPSR = (u8_t) TX_START_PG; EN0_TCNTLO = (u8_t) (packetLength & 0xff); EN0_TCNTHI = (u8_t) (packetLength >> 8); EN_CMD = (u8_t) (EN_PAGE0 + EN_NODMA + EN_TRANS + EN_START); EN0_IMR = (u8_t) (ENISR_OVER + ENISR_RX + ENISR_RX_ERR); #if LINK_STATS lwip_stats.link.xmit++; #endif /* LINK_STATS */ return ERR_OK; } /** * write_AX88796. */ u16_t write_AX88796(u8_t * buf, u16_t remote_Addr, u16_t Count) { #ifndef QDMA_Enabled u16_t loop; #endif /* AX88796. */ EN0_RCNTLO = (u8_t) ( Count & 0xff); EN0_RCNTHI = (u8_t) ( Count >> 8); EN0_RSARLO = (u8_t) ( remote_Addr & 0xff); EN0_RSARHI = (u8_t) ( remote_Addr >> 8); EN_CMD = (u8_t) (EN_RWRITE + EN_START + EN_PAGE0); // Add for next loop... remote_Addr += Count; Count = (Count + 1) >> 1; // Turn to 16bits count. #ifdef QDMA_Enabled *(u32_t *)QDMA_SRC = (u32_t) buf; *(u32_t *)QDMA_DST = (u32_t) &EN_DATA; *(u32_t *)QDMA_CNT = (u32_t) Count; *(u32_t *)QDMA_IDX = 0x00000000; *(u32_t *)QDMA_S_OPT = 0x29000001; #else for (loop=0;loop < Count ;loop++){ EN_DATA = *(u16_t *)buf; buf += 2; } #endif //QDMA_Enabled while ((EN0_ISR & ENISR_RDC) == 0); EN0_ISR = (u8_t) ENISR_RDC; return remote_Addr; } /*---------------------------------------------------------------------------------------- **************************************************************************************** ----------------------------------------------------------------------------------------*/ /* * ethernetif_input(): * * This function should be called when a packet is ready to be read * from the interface. It uses the function low_level_input() that * should handle the actual reception of bytes from the network * interface. * */ static void ne2k_input(struct netif *netif) { struct ne2k_if *ne2k_if; struct eth_hdr *ethhdr; struct pbuf *p; ne2k_if = netif->state; /* move received packet into a new pbuf */ p = low_level_input(netif); /* no packet could be read, silently ignore this */ if (p == NULL) return; /* points to packet payload, which starts with an Ethernet header */ ethhdr = p->payload; #if LINK_STATS lwip_stats.link.recv++; #endif /* LINK_STATS */ switch(htons(ethhdr->type)) { /* IP packet? */ case ETHTYPE_IP: /* update ARP table */ etharp_ip_input(netif, p); /* skip Ethernet header */ pbuf_header(p, -(14+ETH_PAD_SIZE)); /* pass to network layer */ netif->input(p, netif); break; case ETHTYPE_ARP: /* pass p to ARP module */ etharp_arp_input(netif, ne2k_if->ethaddr, p); break; default: pbuf_free(p); p = NULL; break; } } /* * low_level_input(): * * Should allocate a pbuf and transfer the bytes of the incoming * packet from the interface into the pbuf. * */ static struct pbuf * low_level_input(struct netif *netif) { u16_t packetLength, Count, remote_Addr; u8_t *buf, PDHeader[4]; u8_t curr, this_frame, next_frame; struct pbuf *p, *q, *r; EN_CMD = (u8_t) (EN_PAGE1 + EN_NODMA + EN_START); curr = (u8_t) EN1_CURR; EN_CMD = (u8_t) (EN_PAGE0 + EN_NODMA + EN_START); this_frame = (u8_t) EN0_BOUNDARY + 1; if (this_frame >= RX_STOP_PG) this_frame = RX_START_PG; //---------- get the first 4 bytes from AX88796 --------- (void) read_AX88796(PDHeader, (u16_t)(this_frame<<8), 4); //----- Store real length, set len to packet length - header --------- packetLength = ((unsigned) PDHeader[2] | (PDHeader[3] << 8 )) - 4; // minus PDHeader[4] next_frame = (u8_t) (this_frame + 1 + ((packetLength + 4) >> 8)); // Bad frame! if ((PDHeader[1] != (u8_t)next_frame) && (PDHeader[1] != (u8_t)(next_frame + 1)) && (PDHeader[1] != (u8_t)(next_frame - RX_STOP_PG + RX_START_PG)) && (PDHeader[1] != (u8_t)(next_frame + 1 - RX_STOP_PG + RX_START_PG))) { EN0_BOUNDARY = (u8_t) (curr - 1); return NULL; } // Bogus Packet Size if (packetLength > MAX_PACKET_SIZE || packetLength < MIN_PACKET_SIZE) { next_frame = PDHeader[1]; EN0_BOUNDARY = (u8_t) (next_frame-1); return NULL; } EN_CMD = (u8_t) (EN_PAGE0 + EN_NODMA + EN_START); EN0_ISR = (u8_t) ENISR_RDC; // clear the RDC bit remote_Addr = (u16_t)((this_frame << 8) + 4); if ((remote_Addr + packetLength + ETH_PAD_SIZE) > (u16_t)(RX_STOP_PG<<8)) { p = pbuf_alloc(PBUF_RAW, (u16_t)(RX_STOP_PG<<8) - remote_Addr, PBUF_POOL); /* length of buf */ packetLength -= (u16_t)(RX_STOP_PG<<8) - remote_Addr - ETH_PAD_SIZE; } else { p = pbuf_alloc(PBUF_RAW, packetLength+ETH_PAD_SIZE, PBUF_POOL); /* length of buf */ packetLength = 0; } if(p != NULL) { /* We iterate over the pbuf chain until we have read the entire packet into the pbuf. */ for(q = p; q != NULL; q= q->next){ /* Read enough bytes to fill this pbuf in the chain. The avaliable data in the pbuf is given by the q->len variable. */ buf = q->payload; Count = q->len; if (q == p){ // if it's the first pbuf in chain... buf += ETH_PAD_SIZE; Count -= ETH_PAD_SIZE; // pad in Eth_hdr struct } remote_Addr = read_AX88796(buf, remote_Addr, Count); #if LINK_STATS lwip_stats.link.recv++; #endif /* LINK_STATS */ } //for(q = p; q != NULL; q= q->next) } //if(p != NULL) else { // p == NULL #if LINK_STATS lwip_stats.link.memerr++; lwip_stats.link.drop++; #endif /* LINK_STATS */ } if (packetLength) // ring buffer cycled { remote_Addr = (u16_t)(RX_START_PG << 8); r = pbuf_alloc(PBUF_RAW, packetLength, PBUF_POOL); /* length of buf */ if(r != NULL) { /* We iterate over the pbuf chain until we have read the entire packet into the pbuf. */ for(q = r; q != NULL; q= q->next){ /* Read enough bytes to fill this pbuf in the chain. The avaliable data in the pbuf is given by the q->len variable. */ buf = q->payload; Count = q->len; remote_Addr = read_AX88796(buf, remote_Addr, Count); } //for // link pbuf p & r pbuf_cat(p, r); } else // r == NULL { #if LINK_STATS lwip_stats.link.memerr++; lwip_stats.link.drop++; #endif } } // if (packetLength) next_frame = PDHeader[1]; EN0_BOUNDARY = (u8_t) (next_frame-1); return p; } /** * read_AX88796. */ u16_t read_AX88796(u8_t * buf, u16_t remote_Addr, u16_t Count) { u8_t flagOdd=0; #ifndef QDMA_Enabled u16_t loop; #endif flagOdd = (Count & 0x0001); // set Flag if Count is odd. Count -= flagOdd; EN0_RCNTLO = (u8_t) (Count & 0xff); EN0_RCNTHI = (u8_t) (Count >> 8); EN0_RSARLO = (u8_t) (remote_Addr & 0xff); EN0_RSARHI = (u8_t) (remote_Addr >> 8); EN_CMD = (u8_t) (EN_PAGE0 + EN_RREAD + EN_START); remote_Addr += Count; Count = Count>>1; #ifdef QDMA_Enabled *(u32_t *)QDMA_SRC = (u32_t) &EN_DATA; *(u32_t *)QDMA_DST = (u32_t) buf; *(u32_t *)QDMA_CNT = (u32_t) Count; *(u32_t *)QDMA_IDX = 0x00000000; *(u32_t *)QDMA_S_OPT = 0x28200001; buf += Count*2; #else for (loop=0;loop < Count ;loop++){ *(u16_t *)buf = EN_DATA ; buf += 2; } #endif //QDMA_Enabled while ((EN0_ISR & ENISR_RDC) == 0); EN0_ISR = (u8_t) ENISR_RDC; if (flagOdd) { EN0_RCNTLO = 0x01; EN0_RCNTHI = 0x00; EN0_RSARLO = (u8_t) (remote_Addr & 0xff); EN0_RSARHI = (u8_t) (remote_Addr >> 8); EN_CMD = (u8_t) (EN_PAGE0 + EN_RREAD + EN_START); remote_Addr += 1; *(u8_t *)buf = *(u8_t *)(Base_ADDR+0x10) ; while ((EN0_ISR & ENISR_RDC) == 0); EN0_ISR = (u8_t) ENISR_RDC; } return remote_Addr; } /*---------------------------------------------------------------------------------------- **************************************************************************************** ----------------------------------------------------------------------------------------*/ /** * ne2k_rx_err. */ void ne2k_rx_err(void) { u8_t curr; EN_CMD = (u8_t) (EN_PAGE1 + EN_NODMA + EN_STOP); curr = (u8_t) EN1_CURR; EN_CMD = (u8_t) (EN_PAGE0 + EN_NODMA + EN_STOP); EN0_BOUNDARY = (u8_t) curr-1; } /** * ne2k_rx. */ void ne2k_rx(void) { u8_t curr,bnry,loopCnt = 0; while(loopCnt < 10) { EN_CMD = (u8_t) (EN_PAGE1 + EN_NODMA + EN_STOP); curr = (u8_t) EN1_CURR; EN_CMD = (u8_t) (EN_PAGE0 + EN_NODMA + EN_STOP); bnry = (u8_t) EN0_BOUNDARY + 1; if (bnry >= RX_STOP_PG) bnry = RX_START_PG; if (curr == bnry) break; ne2k_input(ne2k_if_netif); loopCnt++; } } /*---*---*---*---*---*---*---* * void ne2k_isr(void) * can be int 4 5 6 or 7 *---*---*---*---*---*---*---*/ void ne2k_isr(void) { DSP_C6x_Save(); OSIntEnter(); if (OSIntNesting == 1) { OSTCBCur->OSTCBStkPtr = (OS_STK *) DSP_C6x_GetCurrentSP(); } /* You can enable Interrupt again here, if want to use nested interrupt..... */ //------------------------------------------------------------ EN_CMD = (u8_t) (EN_PAGE0 + EN_NODMA + EN_STOP); //outb(CMD_PAGE0 | CMD_NODMA | CMD_STOP,NE_CR); EN0_IMR = (u8_t) 0x00;//close // ram overflow interrupt if (EN0_ISR & ENISR_OVER) { EN0_ISR = (u8_t) ENISR_OVER; // clear interrupt } // error transfer interrupt ,NIC abort tx due to excessive collisions if (EN0_ISR & ENISR_TX_ERR) { EN0_ISR = (u8_t) ENISR_TX_ERR; // clear interrupt //temporarily do nothing } // Rx error , reset BNRY pointer to CURR (use SEND PACKET mode) if (EN0_ISR & ENISR_RX_ERR) { EN0_ISR = (u8_t) ENISR_RX_ERR; // clear interrupt ne2k_rx_err(); } //got packet with no errors if (EN0_ISR & ENISR_RX) { EN0_ISR = (u8_t) ENISR_RX; ne2k_rx(); } //Transfer complelte, do nothing here if (EN0_ISR & ENISR_TX){ EN0_ISR = (u8_t) ENISR_TX; // clear interrupt } EN_CMD = (u8_t) (EN_PAGE0 + EN_NODMA + EN_STOP); EN0_ISR = (u8_t) 0xff; // clear ISR EN0_IMR = (u8_t) (ENISR_OVER + ENISR_RX + ENISR_RX_ERR); //open nic for next packet EN_CMD = (u8_t) (EN_PAGE0 + EN_NODMA + EN_START); if (led_stat & 0x04) {LED3_on;} else {LED3_off;} //-------------------------------------------------------- OSIntExit(); DSP_C6x_Resume(); asm (" nop 5"); //important! // this can avoid a stack error when compile with the optimization! } ocproxy-1.60/contrib/ports/old/ti_c6711/proj/000077500000000000000000000000001303453231400207355ustar00rootroot00000000000000ocproxy-1.60/contrib/ports/old/ti_c6711/proj/lwIP.c000066400000000000000000000105021303453231400217520ustar00rootroot00000000000000/* ********************************************************************************************************* * lwIP TCP/IP Stack * port for uC/OS-II RTOS on TIC6711 DSK * * File : tcp_ip.c * By : ZengMing @ DEP,Tsinghua University,Beijing,China ********************************************************************************************************* */ #include #include #include #include #include "..\uCOS-II\TI_C6711\DSP_C6x_Vectors\DSP_C6x_Vectors.H" // -- Architecture Files -- #include "..\lwIP\arch\TI_C6711\sys_arch.c" #include "..\lwIP\arch\TI_C6711\netif\ne2kif.c" // -- Generic network interface -- #include "..\lwIP\src\netif\loopif.c" #include "..\lwIP\src\netif\etharp.c" // -- common file #include "..\lwIP\src\core\mem.c" #include "..\lwIP\src\core\memp.c" #include "..\lwIP\src\core\netif.c" #include "..\lwIP\src\core\pbuf.c" #include "..\lwIP\src\core\stats.c" #include "..\lwIP\src\core\sys.c" #include "..\lwIP\src\core\tcp.c" #include "..\lwIP\src\core\tcp_in.c" #include "..\lwIP\src\core\tcp_out.c" #include "..\lwIP\src\core\udp.c" #include "..\lwIP\src\core\raw.c" // -- target ipv4 -- #include "..\lwIP\src\core\ipv4\icmp.c" #include "..\lwIP\src\core\ipv4\ip.c" #include "..\lwIP\src\core\inet.c" #include "..\lwIP\src\core\ipv4\ip_addr.c" #include "..\lwIP\src\core\ipv4\ip_frag.c" // -- sequential and socket APIs -- #include "..\lwIP\src\api\api_lib.c" #include "..\lwIP\src\api\api_msg.c" #include "..\lwIP\src\api\tcpip.c" #include "..\lwIP\src\api\err.c" #include "..\lwIP\src\api\sockets.c" // sample task code (http demo) #include "sample_http.c" struct netif ne2kif_if; //struct netif loop_if; void ethernet_hardreset(void); //These reset codes are built for C6711 DSP void tcpip_init_done_ok(void * arg); void Task_lwip_init(void * pParam) { struct ip_addr ipaddr, netmask, gw; sys_sem_t sem; ethernet_hardreset();//hard reset of EthernetDaughterCard #if LWIP_STATS stats_init(); #endif // initial lwIP stack sys_init(); mem_init(); memp_init(); pbuf_init(); netif_init(); lwip_socket_init(); printf("TCP/IP initializing...\n"); sem = sys_sem_new(0); tcpip_init(tcpip_init_done_ok, &sem); sys_sem_wait(sem); sys_sem_free(sem); printf("TCP/IP initialized.\n"); //add loop interface //set local loop-interface 127.0.0.1 /* IP4_ADDR(&gw, 127,0,0,1); IP4_ADDR(&ipaddr, 127,0,0,1); IP4_ADDR(&netmask, 255,0,0,0); netif_add(&loop_if, &ipaddr, &netmask, &gw, NULL, loopif_init, tcpip_input);*/ //add ne2k interface IP4_ADDR(&gw, 166,111,32,1); IP4_ADDR(&ipaddr, 166,111,33,120); IP4_ADDR(&netmask, 255,255,254,0); netif_add(&ne2kif_if, &ipaddr, &netmask, &gw, NULL, ne2k_init, tcpip_input); netif_set_default(&ne2kif_if); netif_set_up(&ne2kif_if); // new step from lwip 1.0.0 printf("Applications started.\n"); //------------------------------------------------------------ //All thread(task) of lwIP must have their PRI between 10 and 14. // sys_thread_new("httpd_init", httpd_init, (void*)"httpd", DEFAULT_THREAD_STACKSIZE, 10); //------------------------------------------------------------ httpd_init();//sample_http printf("lwIP threads created!\n"); DSP_C6x_TimerInit(); // Timer interrupt enabled DSP_C6x_Int4Init(); // Int4(Ethernet Chip int) enabled /* Block for ever. */ sem = sys_sem_new(0); sys_sem_wait(sem); printf(" never goes here, should not appear!\n"); } //--------------------------------------------------------- void tcpip_init_done_ok(void * arg) { sys_sem_t *sem; sem = arg; sys_sem_signal(*sem); } /*-----------------------------------------------------------*/ /* This function do the hard reset of EthernetDaughterCard * * through the DaughterBoardControl0 signal in DB-IF */ /*-----------------------------------------------------------*/ void ethernet_hardreset(void) //These reset codes are built for C6711 DSK { u32_t i; OS_ENTER_CRITICAL(); //SET LED1 ON AND /RST pin Low *(unsigned char *)0x90080003 = 0x06; for (i=0;i * * $Id: lwipopts.h,v 1.2 2007/09/07 23:28:54 fbernon Exp $ */ #ifndef __LWIPOPTS_H__ #define __LWIPOPTS_H__ // for TI C6000 DSP target, struct align.... //------------------------------------------------ #define ETH_PAD_SIZE 2 //------------------------------------------------ //------------------------------------------------ /* Critical Region Protection */ //------------------------------------------------ /** SYS_LIGHTWEIGHT_PROT * define SYS_LIGHTWEIGHT_PROT in lwipopts.h if you want inter-task protection * for certain critical regions during buffer allocation, deallocation and memory * allocation and deallocation. */ #define SYS_LIGHTWEIGHT_PROT 1 //millin //---------------------------------------------------------------------- /* ---------- Memory options ---------- */ //---------------------------------------------------------------------- /* MEM_ALIGNMENT: should be set to the alignment of the CPU for which lwIP is compiled. 4 byte alignment -> define MEM_ALIGNMENT to 4, 2 byte alignment -> define MEM_ALIGNMENT to 2. */ #define MEM_ALIGNMENT 4 /* MEM_SIZE: the size of the heap memory. If the application will send a lot of data that needs to be copied, this should be set high. */ #define MEM_SIZE 65536 /* MEMP_NUM_PBUF: the number of memp struct pbufs. If the application sends a lot of data out of ROM (or other static memory), this should be set high. */ #define MEMP_NUM_PBUF 32 /* Number of raw connection PCBs */ #define MEMP_NUM_RAW_PCB 8 /* MEMP_NUM_UDP_PCB: the number of UDP protocol control blocks. One per active UDP "connection". */ #define MEMP_NUM_UDP_PCB 8 /* MEMP_NUM_TCP_PCB: the number of simulatenously active TCP connections. */ #define MEMP_NUM_TCP_PCB 8 /* MEMP_NUM_TCP_PCB_LISTEN: the number of listening TCP connections. */ #define MEMP_NUM_TCP_PCB_LISTEN 2 /* MEMP_NUM_TCP_SEG: the number of simultaneously queued TCP segments. */ #define MEMP_NUM_TCP_SEG 32 /* MEMP_NUM_SYS_TIMEOUT: the number of simulateously active timeouts. */ #define MEMP_NUM_SYS_TIMEOUT 8 //---------------------------------------------------------------------- /* The following four are used only with the sequential API and can be set to 0 if the application only will use the raw API. */ //---------------------------------------------------------------------- /* MEMP_NUM_NETBUF: the number of struct netbufs. */ #define MEMP_NUM_NETBUF 32 /* MEMP_NUM_NETCONN: the number of struct netconns. */ #define MEMP_NUM_NETCONN 32 /* MEMP_NUM_TCPIP_MSG: the number of struct tcpip_msg, which is used for sequential API communication and incoming packets. Used in src/api/tcpip.c. */ #define MEMP_NUM_TCPIP_MSG_API 32 #define MEMP_NUM_TCPIP_MSG_INPKT 32 //---------------------------------------------------------------------- /* ---------- Pbuf options ---------- */ //---------------------------------------------------------------------- /* PBUF_POOL_SIZE: the number of buffers in the pbuf pool. */ #define PBUF_POOL_SIZE 16 /* PBUF_POOL_BUFSIZE: the size of each pbuf in the pbuf pool. */ #define PBUF_POOL_BUFSIZE 1536 //---------------------------------------------------------------------- /* ---------- ARP options ---------- */ //---------------------------------------------------------------------- /** Number of active hardware address, IP address pairs cached */ #define ARP_TABLE_SIZE 10//10 /** * If enabled, outgoing packets are queued during hardware address * resolution. * * This feature has not stabilized yet. Single-packet queueing is * believed to be stable, multi-packet queueing is believed to * clash with the TCP segment queueing. * * As multi-packet-queueing is currently disabled, enabling this * _should_ work, but we need your testing feedback on lwip-users. * */ #define ARP_QUEUEING 0 // if TCP was used, must disable this in v1.1.0 //millin //---------------------------------------------------------------------- /* ---------- IP options ---------- */ //---------------------------------------------------------------------- /* Define IP_FORWARD to 1 if you wish to have the ability to forward IP packets across network interfaces. If you are going to run lwIP on a device with only one network interface, define this to 0. */ #define IP_FORWARD 0 /* If defined to 1, IP options are allowed (but not parsed). If defined to 0, all packets with IP options are dropped. */ #define IP_OPTIONS 0 /** IP reassembly and segmentation. Even if they both deal with IP * fragments, note that these are orthogonal, one dealing with incoming * packets, the other with outgoing packets */ /** Reassemble incoming fragmented IP packets */ #define IP_REASSEMBLY 0 /** Fragment outgoing IP packets if their size exceeds MTU */ #define IP_FRAG 0 //---------------------------------------------------------------------- /* ---------- DHCP options ---------- */ //---------------------------------------------------------------------- /* Define LWIP_DHCP to 1 if you want DHCP configuration of interfaces. DHCP is not implemented in lwIP 0.5.1, however, so turning this on does currently not work. */ #define LWIP_DHCP 0 /* 1 if you want to do an ARP check on the offered address (recommended). */ #define DHCP_DOES_ARP_CHECK 1 //---------------------------------------------------------------------- /* ---------- UDP options ---------- */ //---------------------------------------------------------------------- #define LWIP_UDP 1 //---------------------------------------------------------------------- /* ---------- TCP options ---------- */ //---------------------------------------------------------------------- #define LWIP_TCP 1 /* TCP receive window. */ #define TCP_WND 32768 /* Maximum number of retransmissions of data segments. */ #define TCP_MAXRTX 4 /* Maximum number of retransmissions of SYN segments. */ #define TCP_SYNMAXRTX 4 /* Controls if TCP should queue segments that arrive out of order. Define to 0 if your device is low on memory. */ #define TCP_QUEUE_OOSEQ 1 /* TCP Maximum segment size. */ #define TCP_MSS 1476 /* TCP sender buffer space (bytes). */ #define TCP_SND_BUF 32768 //---------------------------------------------------------------------- /* ---------- Other options ---------- */ //---------------------------------------------------------------------- /* Support loop interface (127.0.0.1) */ #define LWIP_HAVE_LOOPIF 0 #define LWIP_COMPAT_SOCKETS 1 // for uC/OS-II port on TI DSP #define TCPIP_THREAD_PRIO 5 //millin //#define SLIPIF_THREAD_PRIO 1 //#define PPP_THREAD_PRIO 1 //---------------------------------------------------------------------- /* ---------- Socket Options ---------- */ //---------------------------------------------------------------------- /* Enable SO_REUSEADDR and SO_REUSEPORT options */ #define SO_REUSE 0 //---------------------------------------------------------------------- /* ---------- Statistics options ---------- */ //---------------------------------------------------------------------- #define STATS 0 #if LWIP_STATS #define LWIP_STATS_DISPLAY 1 #define LINK_STATS 1 #define IP_STATS 1 #define IPFRAG_STATS 1 #define ICMP_STATS 1 #define UDP_STATS 1 #define TCP_STATS 1 #define MEM_STATS 1 #define MEMP_STATS 1 #define PBUF_STATS 1 #define SYS_STATS 1 #endif /* STATS */ //---------------------------------------------------------------------- /* ------------if you need to do debug-------------*/ //---------------------------------------------------------------------- /* define LWIP_DEBUG in compiler and following... */ #define LWIP_DBG_MIN_LEVEL LWIP_DBG_LEVEL_SERIOUS //LWIP_DBG_LEVEL_WARNING LWIP_DBG_LEVEL_SERIOUS LWIP_DBG_LEVEL_SEVERE #define LWIP_DBG_TYPES_ON 0//LWIP_DBG_TRACE | LWIP_DBG_STATE |LWIP_DBG_FRESH | LWIP_DBG_HALT /* Then, define debug class in opt.h * --------------------------------------------------*/ #define ETHARP_DEBUG LWIP_DBG_OFF #define NETIF_DEBUG LWIP_DBG_OFF #define PBUF_DEBUG LWIP_DBG_OFF #define API_LIB_DEBUG LWIP_DBG_OFF #define API_MSG_DEBUG LWIP_DBG_OFF #define SOCKETS_DEBUG LWIP_DBG_OFF #define ICMP_DEBUG LWIP_DBG_OFF #define INET_DEBUG LWIP_DBG_OFF #define IP_DEBUG LWIP_DBG_OFF #define IP_REASS_DEBUG LWIP_DBG_OFF #define RAW_DEBUG LWIP_DBG_OFF #define MEM_DEBUG LWIP_DBG_OFF #define MEMP_DEBUG LWIP_DBG_OFF #define SYS_DEBUG LWIP_DBG_OFF #define TCP_DEBUG LWIP_DBG_OFF #define TCP_INPUT_DEBUG LWIP_DBG_OFF #define TCP_FR_DEBUG LWIP_DBG_OFF #define TCP_RTO_DEBUG LWIP_DBG_OFF #define TCP_CWND_DEBUG LWIP_DBG_OFF #define TCP_WND_DEBUG LWIP_DBG_OFF #define TCP_OUTPUT_DEBUG LWIP_DBG_OFF #define TCP_RST_DEBUG LWIP_DBG_OFF #define TCP_QLEN_DEBUG LWIP_DBG_OFF #define UDP_DEBUG LWIP_DBG_OFF #define TCPIP_DEBUG LWIP_DBG_OFF #define PPP_DEBUG LWIP_DBG_OFF #define SLIP_DEBUG LWIP_DBG_OFF #define DHCP_DEBUG LWIP_DBG_OFF #endif /* __LWIPOPTS_H__ */ ocproxy-1.60/contrib/ports/old/ti_c6711/sys_arch.c000066400000000000000000000130331303453231400217420ustar00rootroot00000000000000/* ********************************************************************************************************* * lwIP TCP/IP Stack * port for uC/OS-II RTOS on TIC6711 DSK * * File : sys_arch.c * By : ZengMing @ DEP,Tsinghua University,Beijing,China * Reference: YangYe's source code for SkyEye project ********************************************************************************************************* */ //#include "lwip/debug.h" #include "lwip/def.h" #include "lwip/sys.h" #include "lwip/mem.h" #include "arch/sys_arch.h" static OS_MEM *pQueueMem; const void * const pvNullPointer; static char pcQueueMemoryPool[MAX_QUEUES * sizeof(TQ_DESCR) ]; struct sys_timeouts lwip_timeouts[LWIP_TASK_MAX+1]; struct sys_timeouts null_timeouts; OS_STK LWIP_TASK_STK[LWIP_TASK_MAX+1][LWIP_STK_SIZE]; /*-----------------------------------------------------------------------------------*/ /* This func should be called first in lwip task! * ------------------------------------------------- */ void sys_init(void) { u8_t i; u8_t ucErr; //init mem used by sys_mbox_t //use ucosII functions pQueueMem = OSMemCreate( (void*)pcQueueMemoryPool, MAX_QUEUES, sizeof(TQ_DESCR), &ucErr ); //init lwip_timeouts for every lwip task for(i=0;i 65535) //ucOS only support u16_t pend ucos_timeout = 65535; } OSSemPend ((OS_EVENT *)sem,(u16_t)ucos_timeout, (u8_t *)&err); if(err == OS_TIMEOUT) return 0; // only when timeout! else return 1; } /*-----------------------------------------------------------------------------------*/ sys_mbox_t sys_mbox_new(void) { u8_t ucErr; PQ_DESCR pQDesc; pQDesc = OSMemGet( pQueueMem, &ucErr ); if( ucErr == OS_NO_ERR ) { pQDesc->pQ = OSQCreate( &(pQDesc->pvQEntries[0]), MAX_QUEUE_ENTRIES ); if( pQDesc->pQ != NULL ) { return pQDesc; } } return SYS_MBOX_NULL; } /*-----------------------------------------------------------------------------------*/ void sys_mbox_free(sys_mbox_t mbox) { u8_t ucErr; //clear OSQ EVENT OSQFlush( mbox->pQ ); //del OSQ EVENT (void)OSQDel( mbox->pQ, OS_DEL_NO_PEND, &ucErr); //put mem back to mem queue ucErr = OSMemPut( pQueueMem, mbox ); } /*-----------------------------------------------------------------------------------*/ void sys_mbox_post(sys_mbox_t mbox, void *msg) { if( !msg ) msg = (void*)&pvNullPointer; (void)OSQPost( mbox->pQ, msg); } /*-----------------------------------------------------------------------------------*/ u32_t sys_arch_mbox_fetch(sys_mbox_t mbox, void **msg, u32_t timeout) { u8_t ucErr; u32_t ucos_timeout; ucos_timeout = 0; if(timeout != 0){ ucos_timeout = (timeout * OS_TICKS_PER_SEC)/1000; if(ucos_timeout < 1) ucos_timeout = 1; else if(ucos_timeout > 65535) //ucOS only support u16_t timeout ucos_timeout = 65535; } if(msg != NULL){ *msg = OSQPend( mbox->pQ, (u16_t)ucos_timeout, &ucErr ); }else{ //just discard return value if msg==NULL OSQPend(mbox->pQ,(u16_t)ucos_timeout,&ucErr); } if( ucErr == OS_TIMEOUT ) { timeout = 0; } else { if(*msg == (void*)&pvNullPointer ) *msg = NULL; timeout = 1; } return timeout; } /*----------------------------------------------------------------------*/ struct sys_timeouts * sys_arch_timeouts(void) { u8_t curr_prio; s16_t offset; OS_TCB curr_task_pcb; null_timeouts.next = NULL; OSTaskQuery(OS_PRIO_SELF,&curr_task_pcb); curr_prio = curr_task_pcb.OSTCBPrio; offset = curr_prio - LWIP_START_PRIO; if(curr_prio == TCPIP_THREAD_PRIO) return &lwip_timeouts[LWIP_TASK_MAX]; else if(offset >= 0 && offset < LWIP_TASK_MAX) return &lwip_timeouts[offset]; else return &null_timeouts; //if not called by a lwip task ,return timeouts->NULL } /*------------------------------------------------------------------------*/ sys_thread_t sys_thread_new(char *name, void (* thread)(void *arg), void *arg, int stacksize, int prio) { /** @todo Replace LWIP_TASK_STK by the use of "stacksize" parameter */ if(prio == TCPIP_THREAD_PRIO){ OSTaskCreate(thread, (void *)0x1111, &LWIP_TASK_STK[LWIP_TASK_MAX][LWIP_STK_SIZE-1], prio); return prio; } else if(prio - LWIP_START_PRIO < LWIP_TASK_MAX){ OSTaskCreate(thread, (void *)0x1111, &LWIP_TASK_STK[prio - LWIP_START_PRIO][LWIP_STK_SIZE-1], prio); return prio; } else { printf(" lwip task prio out of range ! error! "); return 0; } } ocproxy-1.60/contrib/ports/old/v2pro/000077500000000000000000000000001303453231400175765ustar00rootroot00000000000000ocproxy-1.60/contrib/ports/old/v2pro/Makefile000077500000000000000000000141431303453231400212440ustar00rootroot00000000000000############################################################################### # Copyright (c) 2001-2003 Swedish Institute of Computer Science. # All rights reserved. # # Copyright (c) 2003 Xilinx, Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # 1. Redistributions of source code must retain the above copyright notice, # this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright notice, # this list of conditions and the following disclaimer in the documentation # and/or other materials provided with the distribution. # 3. The name of the author may not be used to endorse or promote products # derived from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED # WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO # EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; # OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, # WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR # OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF # ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS". # BY PROVIDING THIS DESIGN, CODE, OR INFORMATION AS ONE POSSIBLE # IMPLEMENTATION OF THIS FEATURE, APPLICATION OR STANDARD, XILINX # IS MAKING NO REPRESENTATION THAT THIS IMPLEMENTATION IS FREE FROM # ANY CLAIMS OF INFRINGEMENT, AND YOU ARE RESPONSIBLE FOR OBTAINING # ANY RIGHTS YOU MAY REQUIRE FOR YOUR IMPLEMENTATION. XILINX # EXPRESSLY DISCLAIMS ANY WARRANTY WHATSOEVER WITH RESPECT TO THE # ADEQUACY OF THE IMPLEMENTATION, INCLUDING BUT NOT LIMITED TO ANY # WARRANTIES OR REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE # FROM CLAIMS OF INFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY # AND FITNESS FOR A PARTICULAR PURPOSE. # # This file is part of the lwIP TCP/IP stack. # # Author: Chris Borrelli # ############################################################################### COMPILER=powerpc-eabi-gcc ARCHIVER=powerpc-eabi-ar ARFLAGS=rs CP=cp COMPILERFLAGS=-Wall -gdwarf #EXTRA_COMPILER_FLAGS = -DIPv4 -fpack-struct -msdata=eabi -mcpu=403 EXTRA_COMPILER_FLAGS = -DIPv4 -msdata=eabi -mcpu=403 LWIPDIR=../../../lwip/src LIB=liblwip4.a RELEASEDIR=../../../../../ppc405_i/lib INCLUDEDIR=../../../../../ppc405_i/include LEVEL=0 XLIBINCLUDEDIR=../../../../../ppc405_i/include INCLUDES= \ -I$(LWIPDIR)/include \ -I$(LWIPDIR)/include/ipv4 \ -I$(XLIBINCLUDEDIR) \ -I./include \ -I. INCLUDEFILES=../../../lwip/src/include/ipv4/lwip \ ../../../lwip/src/include/lwip \ ../../../lwip/src/include/netif \ ./include/netif \ ./include/arch \ ./lwipopts.h # COREFILES, CORE4FILES: The minimum set of files needed for lwIP. COREFILES=$(LWIPDIR)/core/mem.c \ $(LWIPDIR)/core/memp.c \ $(LWIPDIR)/core/netif.c \ $(LWIPDIR)/core/pbuf.c \ $(LWIPDIR)/core/stats.c \ $(LWIPDIR)/core/sys.c \ $(LWIPDIR)/core/tcp.c \ $(LWIPDIR)/core/tcp_in.c \ $(LWIPDIR)/core/tcp_out.c \ $(LWIPDIR)/core/udp.c \ CORE4FILES=$(LWIPDIR)/core/ipv4/icmp.c \ $(LWIPDIR)/core/ipv4/ip.c \ $(LWIPDIR)/core/inet.c \ $(LWIPDIR)/core/ipv4/ip_addr.c \ $(LWIPDIR)/core/ipv4/ip_frag.c # NETIFFILES: Files implementing various generic network interface functions. NETIFFILES=$(LWIPDIR)/netif/etharp.c # ARCHFILES: Archiecture specific files. ARCHFILES=$(wildcard *.c \ netif/*.c) # LWIPFILES: All the above. LWIPFILES=$(COREFILES) $(CORE4FILES) $(NETIFFILES) $(ARCHFILES) LWIPFILESW=$(wildcard $(LWIPFILES)) LWIPOBJS=$(notdir $(LWIPFILESW:.c=.o)) help: @echo "" @echo "This Makefile generates a library for the v2pro port of lwIP." @echo "" @echo " Below are the targets:" @echo "" @echo " make libs" @echo " This is the target that will compile all lwIP files, and" @echo " build the library, $(LIB). The final library will be" @echo " copied to $(RELEASEDIR)." @echo "" @echo " make include" @echo " Copies the lwIP include files into the EDK directory," @echo " $(INCLUDEDIR)" @echo "" @echo " make clean" @echo " Removes all object files and the $(LIB) library from" @echo " the local directory." @echo "" @echo " make depend" @echo " Generates the .depend file, which contains the" @echo " dependancies needed to compile each .c file. The" @echo " .depend file will be generated automatically for" @echo " other targets, so it is not nessessary to run" @echo " make depend." @echo "" %.o: @echo "" @echo "Building File: $@" @echo "" $(COMPILER) $(COMPILERFLAGS) $(EXTRA_COMPILER_FLAGS) $(INCLUDES) -c $(<:.o=.c) all ipv4 libs: include $(LIB) .PHONY: all ipv4 libs include help include: @for i in $(INCLUDEFILES); do \ echo ${CP} -r $$i ${INCLUDEDIR}; \ ${CP} -r $$i ${INCLUDEDIR}; \ done clean: @echo "" @echo "Cleaning up..." @echo "" @rm -f *.o *.a .depend* core depend dep: .depend @exit $(LIB): $(LWIPOBJS) @echo "" @echo "Building lwIP Library, $@" $(ARCHIVER) $(ARFLAGS) $@ $? @cp $@ $(RELEASEDIR)/ .depend: $(LWIPFILES) $(APPFILES) @echo "" @echo "Building dependancies..." $(COMPILER) $(COMPILERFLAGS) $(EXTRA_COMPILER_FLAGS) $(INCLUDES) \ -MM $^ > .depend || rm -f .depend ifneq ($(MAKECMDGOALS), clean) ifneq ($(MAKECMDGOALS), depend) ifneq ($(MAKECMDGOALS), dep) ifneq ($(MAKECMDGOALS), ) ifneq ($(MAKECMDGOALS), help) -include .depend endif endif endif endif endif ocproxy-1.60/contrib/ports/old/v2pro/include/000077500000000000000000000000001303453231400212215ustar00rootroot00000000000000ocproxy-1.60/contrib/ports/old/v2pro/include/arch/000077500000000000000000000000001303453231400221365ustar00rootroot00000000000000ocproxy-1.60/contrib/ports/old/v2pro/include/arch/cc.h000066400000000000000000000042501303453231400226750ustar00rootroot00000000000000/* * Copyright (c) 2001-2003 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #ifndef __ARCH_CC_H__ #define __ARCH_CC_H__ #define BYTE_ORDER BIG_ENDIAN typedef unsigned char u8_t; typedef signed char s8_t; typedef unsigned short u16_t; typedef signed short s16_t; typedef unsigned long u32_t; typedef signed long s32_t; typedef u32_t mem_ptr_t; #define U16_F "hu" #define S16_F "hd" #define X16_F "hx" #define U32_F "lu" #define S32_F "ld" #define X32_F "lx" #define PACK_STRUCT_FIELD(x) x __attribute__((packed)) #define PACK_STRUCT_STRUCT __attribute__((packed)) #define PACK_STRUCT_BEGIN #define PACK_STRUCT_END #endif /* __ARCH_CC_H__ */ ocproxy-1.60/contrib/ports/old/v2pro/include/arch/cpu.h000066400000000000000000000032661303453231400231050ustar00rootroot00000000000000/* * Copyright (c) 2001-2003 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #ifndef __ARCH_CPU_H__ #define __ARCH_CPU_H__ #define BYTE_ORDER BIG_ENDIAN #endif /* __ARCH_CPU_H__ */ ocproxy-1.60/contrib/ports/old/v2pro/include/arch/perf.h000066400000000000000000000034211303453231400232430ustar00rootroot00000000000000/* * Copyright (c) 2001-2003 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #ifndef __ARCH_PERF_H__ #define __ARCH_PERF_H__ #define PERF_START /* null definition */ #define PERF_STOP(x) /* null definition */ void perf_init(char *fname); #endif /* __ARCH_PERF_H__ */ ocproxy-1.60/contrib/ports/old/v2pro/include/arch/sys_arch.h000066400000000000000000000033021303453231400241200ustar00rootroot00000000000000/* * Copyright (c) 2001-2003 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #ifndef __SYS_XILINX_V2P_H__ #define __SYS_XILINX_V2P_H__ #define SYS_MBOX_NULL 0 #endif /* __SYS_XILINX_V2P_H__ */ ocproxy-1.60/contrib/ports/old/v2pro/include/netif/000077500000000000000000000000001303453231400223265ustar00rootroot00000000000000ocproxy-1.60/contrib/ports/old/v2pro/include/netif/xemacif.h000066400000000000000000000041261303453231400241160ustar00rootroot00000000000000/* * Copyright (c) 2001, 2002, 2003 Xilinx, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Chris Borrelli * */ #ifndef __NETIF_XEMACIF_H__ #define __NETIF_XEMACIF_H__ #include "lwip/netif.h" #include "netif/etharp.h" #include "xemac.h" void xemacif_setmac(u32_t index, u8_t *addr); u8_t * xemacif_getmac(u32_t index); err_t xemacif_init(struct netif *netif); err_t xemacif_input(void *CallBackRef); /** * This typedef contains configuration information for an xemac instance. */ typedef struct { Xuint32 DevId; Xuint32 IntrId; struct eth_addr ethaddr; XEmac* instance_ptr; } XEmacIf_Config; #endif /* __NETIF_XEMACIF_H__ */ ocproxy-1.60/contrib/ports/old/v2pro/lib_arch.c000066400000000000000000000031141303453231400215040ustar00rootroot00000000000000/* * Copyright (c) 2001-2003 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ ocproxy-1.60/contrib/ports/old/v2pro/lwipopts.h000077500000000000000000000145201303453231400216350ustar00rootroot00000000000000/* * Copyright (c) 2001, 2002 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #ifndef __LWIPOPTS_H__ #define __LWIPOPTS_H__ #define NO_SYS 1 #define LWIP_CALLBACK_API 1 /* -------- TCP Timer Intervals ------- */ #define TCP_TMR_INTERVAL 1 /* The TCP timer interval in milliseconds. */ #define TCP_FAST_INTERVAL 2 /* the fine grained timeout in milliseconds */ #define TCP_SLOW_INTERVAL 5 /* the coarse grained timeout in milliseconds */ /* ---------- Memory options ---------- */ /* MEM_ALIGNMENT: should be set to the alignment of the CPU for which lwIP is compiled. 4 byte alignment -> define MEM_ALIGNMENT to 4, 2 byte alignment -> define MEM_ALIGNMENT to 2. */ #define MEM_ALIGNMENT 4 /* MEM_SIZE: the size of the heap memory. If the application will send a lot of data that needs to be copied, this should be set high. */ #define MEM_SIZE 8 * 1024 * 1024 /* MEMP_NUM_PBUF: the number of memp struct pbufs. If the application sends a lot of data out of ROM (or other static memory), this should be set high. */ #define MEMP_NUM_PBUF 64 /* MEMP_NUM_UDP_PCB: the number of UDP protocol control blocks. One per active UDP "connection". */ #define MEMP_NUM_UDP_PCB 1 /* MEMP_NUM_TCP_PCB: the number of simulatenously active TCP connections. */ #define MEMP_NUM_TCP_PCB 8 /* MEMP_NUM_TCP_PCB_LISTEN: the number of listening TCP connections. */ #define MEMP_NUM_TCP_PCB_LISTEN 16 /* MEMP_NUM_TCP_SEG: the number of simultaneously queued TCP segments. */ #define MEMP_NUM_TCP_SEG 255 /* The following four are used only with the sequential API and can be set to 0 if the application only will use the raw API. */ /* MEMP_NUM_NETBUF: the number of struct netbufs. */ #define MEMP_NUM_NETBUF 0 /* MEMP_NUM_NETCONN: the number of struct netconns. */ #define MEMP_NUM_NETCONN 0 /* MEMP_NUM_TCPIP_MSG: the number of struct tcpip_msg, which is used for sequential API communication and incoming packets. Used in src/api/tcpip.c. */ #define MEMP_NUM_TCPIP_MSG_API 0 #define MEMP_NUM_TCPIP_MSG_INPKT 0 /* MEMP_NUM_SYS_TIMEOUT: the number of simulateously active timeouts. */ #define MEMP_NUM_SYS_TIMEOUT 0 /* ---------- Pbuf options ---------- */ /* PBUF_POOL_SIZE: the number of buffers in the pbuf pool. */ #define PBUF_POOL_SIZE 512 /* PBUF_POOL_BUFSIZE: the size of each pbuf in the pbuf pool. */ #define PBUF_POOL_BUFSIZE 1536 /* PBUF_LINK_HLEN: the number of bytes that should be allocated for a link level header. */ #define PBUF_LINK_HLEN 16 /* ---------- TCP options ---------- */ #define LWIP_TCP 1 #define TCP_TTL 255 /* Controls if TCP should queue segments that arrive out of order. Define to 0 if your device is low on memory. */ #define TCP_QUEUE_OOSEQ 1 /* TCP Maximum segment size. */ #define TCP_MSS 1476 /* TCP sender buffer space (bytes). */ #define TCP_SND_BUF 32 * 1024 /* TCP sender buffer space (pbufs). This must be at least = 2 * TCP_SND_BUF/TCP_MSS for things to work. */ #define TCP_SND_QUEUELEN 2 * TCP_SND_BUF/TCP_MSS /* TCP receive window. */ #define TCP_WND 16 * 1024 /* Maximum number of retransmissions of data segments. */ #define TCP_MAXRTX 12 /* Maximum number of retransmissions of SYN segments. */ #define TCP_SYNMAXRTX 4 /* ---------- ARP options ---------- */ #define ARP_TABLE_SIZE 10 #define ARP_QUEUEING 1 /* ---------- IP options ---------- */ /* Define IP_FORWARD to 1 if you wish to have the ability to forward IP packets across network interfaces. If you are going to run lwIP on a device with only one network interface, define this to 0. */ #define IP_FORWARD 0 /* If defined to 1, IP options are allowed (but not parsed). If defined to 0, all packets with IP options are dropped. */ #define IP_OPTIONS 1 /* ---------- ICMP options ---------- */ #define ICMP_TTL 255 /* ---------- DHCP options ---------- */ /* Define LWIP_DHCP to 1 if you want DHCP configuration of interfaces. DHCP is not implemented in lwIP 0.5.1, however, so turning this on does currently not work. */ #define LWIP_DHCP 0 /* 1 if you want to do an ARP check on the offered address (recommended). */ #define DHCP_DOES_ARP_CHECK 1 /* ---------- UDP options ---------- */ #define LWIP_UDP 0 #define UDP_TTL 255 /* ---------- Statistics options ---------- */ /*#define STATS*/ #ifdef STATS #define LINK_STATS #define IP_STATS #define ICMP_STATS #define UDP_STATS #define TCP_STATS #define MEM_STATS #define MEMP_STATS #define PBUF_STATS #define SYS_STATS #endif /* STATS */ #endif /* __LWIPOPTS_H__ */ ocproxy-1.60/contrib/ports/old/v2pro/netif/000077500000000000000000000000001303453231400207035ustar00rootroot00000000000000ocproxy-1.60/contrib/ports/old/v2pro/netif/xemacif.c000077500000000000000000000352341303453231400224750ustar00rootroot00000000000000/* * Copyright (c) 2001-2003 Swedish Institute of Computer Science. * All rights reserved. * * Copyright (c) 2001, 2002, 2003 Xilinx, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS". * BY PROVIDING THIS DESIGN, CODE, OR INFORMATION AS ONE POSSIBLE * IMPLEMENTATION OF THIS FEATURE, APPLICATION OR STANDARD, XILINX * IS MAKING NO REPRESENTATION THAT THIS IMPLEMENTATION IS FREE FROM * ANY CLAIMS OF INFRINGEMENT, AND YOU ARE RESPONSIBLE FOR OBTAINING * ANY RIGHTS YOU MAY REQUIRE FOR YOUR IMPLEMENTATION. XILINX * EXPRESSLY DISCLAIMS ANY WARRANTY WHATSOEVER WITH RESPECT TO THE * ADEQUACY OF THE IMPLEMENTATION, INCLUDING BUT NOT LIMITED TO ANY * WARRANTIES OR REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE * FROM CLAIMS OF INFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE. * * This file is part of the lwIP TCP/IP stack. * * Author: Chris Borrelli * * Based on example ethernetif.c, Adam Dunkels * */ /*---------------------------------------------------------------------------*/ /* EDK Include Files */ /*---------------------------------------------------------------------------*/ #include "xemac.h" #include "xparameters.h" #include "xstatus.h" #include "xexception_l.h" /*---------------------------------------------------------------------------*/ /* LWIP Include Files */ /*---------------------------------------------------------------------------*/ #include "lwip/debug.h" #include "lwip/opt.h" #include "lwip/def.h" #include "lwip/mem.h" #include "lwip/pbuf.h" #include "lwip/stats.h" #include "lwip/sys.h" #include "lwip/netif.h" #include "netif/etharp.h" #include "netif/xemacif.h" /*---------------------------------------------------------------------------*/ /* Describe network interface */ /*---------------------------------------------------------------------------*/ #define IFNAME0 'e' #define IFNAME1 '0' /*---------------------------------------------------------------------------*/ /* Constant Definitions */ /*---------------------------------------------------------------------------*/ #define XEM_MAX_FRAME_SIZE_IN_WORDS ((XEM_MAX_FRAME_SIZE/sizeof(Xuint32))+1) extern XEmacIf_Config XEmacIf_ConfigTable[]; /*---------------------------------------------------------------------------*/ /* low_level_init function */ /* - hooks up the data structures and sets the mac options and mac */ /*---------------------------------------------------------------------------*/ static err_t low_level_init(struct netif *netif_ptr) { XEmac *InstancePtr = mem_malloc(sizeof(XEmac)); XEmacIf_Config *xemacif_ptr = (XEmacIf_Config *) netif_ptr->state; Xuint16 DeviceId = xemacif_ptr->DevId; XStatus Result; Xuint32 Options; xemacif_ptr->instance_ptr = InstancePtr; /* Call Initialize Function of EMAC driver */ Result = XEmac_Initialize(InstancePtr, DeviceId); if (Result != XST_SUCCESS) return ERR_MEM; /* Stop the EMAC hardware */ XEmac_Stop(InstancePtr); /* Set MAC Address of EMAC */ Result = XEmac_SetMacAddress(InstancePtr, (Xuint8*) netif_ptr->hwaddr); if (Result != XST_SUCCESS) return ERR_MEM; /* Set MAC Options */ Options = ( XEM_INSERT_FCS_OPTION | XEM_INSERT_PAD_OPTION | XEM_UNICAST_OPTION | XEM_BROADCAST_OPTION | XEM_POLLED_OPTION | XEM_STRIP_PAD_FCS_OPTION); Result = XEmac_SetOptions(InstancePtr, Options); if (Result != XST_SUCCESS) return ERR_MEM; /* Start the EMAC hardware */ Result = XEmac_Start(InstancePtr); if (Result != XST_SUCCESS) return ERR_MEM; /* Clear driver stats */ XEmac_ClearStats(InstancePtr); return ERR_OK; } /*---------------------------------------------------------------------------*/ /* low_level_output() */ /* */ /* Should do the actual transmission of the packet. The packet is */ /* contained in the pbuf that is passed to the function. This pbuf */ /* might be chained. */ /*---------------------------------------------------------------------------*/ static err_t low_level_output(struct netif *netif, struct pbuf *p) { struct pbuf *q; u32_t frame_buffer[XEM_MAX_FRAME_SIZE_IN_WORDS]; /* word aligned */ Xuint8 *frame_ptr; int payload_size = 0, i; XStatus Result; Xuint32 Options; XEmacIf_Config *xemacif_ptr = netif->state; frame_ptr = (Xuint8 *) frame_buffer; for(q = p; q != NULL; q = q->next) { /* * Send the data from the pbuf to the interface, one pbuf at a * time. The size of the data in each pbuf is kept in the ->len * variable. */ for(i = 0 ; i < q->len ; i++) { *(frame_ptr++) = (Xuint8) *(((u8_t *) q->payload) + i); payload_size++; } } Result = XEmac_PollSend(xemacif_ptr->instance_ptr, (Xuint8 *) frame_buffer, payload_size); if (Result != XST_SUCCESS) { xil_printf("XEmac_PollSend: failed\r\n"); if (Result == XST_FIFO_ERROR) { XEmac_Reset(xemacif_ptr->instance_ptr); XEmac_SetMacAddress(xemacif_ptr->instance_ptr, (Xuint8*) xemacif_ptr->ethaddr.addr); Options = ( XEM_INSERT_FCS_OPTION | XEM_INSERT_PAD_OPTION | XEM_UNICAST_OPTION | XEM_BROADCAST_OPTION | XEM_POLLED_OPTION | XEM_STRIP_PAD_FCS_OPTION); XEmac_SetOptions(xemacif_ptr->instance_ptr, Options); XEmac_Start(xemacif_ptr->instance_ptr); xil_printf("XEmac_PollSend: returned XST_FIFO_ERROR\r\n"); } return ERR_MEM; } #if 0 xil_printf("\r\n\r\n TXFRAME:\r\n"); for (i=0 ; i < payload_size ; i++) { xil_printf("%2X", ((Xuint8 *) frame_buffer)[i]); if (! (i%20) && i) xil_printf("\r\n"); else xil_printf(" "); } xil_printf ("\r\n\r\n"); #endif #ifdef LINK_STATS lwip_stats.link.xmit++; #endif /* LINK_STATS */ return ERR_OK; } /*---------------------------------------------------------------------------*/ /* low_level_input() */ /* */ /* Allocates a pbuf pool and transfers bytes of */ /* incoming packet from the interface into the pbuf. */ /*---------------------------------------------------------------------------*/ static struct pbuf * low_level_input(XEmacIf_Config *xemacif_ptr) { struct pbuf *p = NULL, *q = NULL; XEmac *EmacPtr = (XEmac *) xemacif_ptr->instance_ptr; Xuint32 RecvBuffer[XEM_MAX_FRAME_SIZE_IN_WORDS]; Xuint32 FrameLen = XEM_MAX_FRAME_SIZE; Xuint32 i, Options; u8_t * frame_bytes = (u8_t *) RecvBuffer; XStatus Result; Result = XEmac_PollRecv(EmacPtr, (Xuint8 *)RecvBuffer, &FrameLen); if (Result != XST_SUCCESS) { if (!(Result == XST_NO_DATA || Result == XST_BUFFER_TOO_SMALL)) { XEmac_Reset(xemacif_ptr->instance_ptr); XEmac_SetMacAddress(xemacif_ptr->instance_ptr, (Xuint8*) xemacif_ptr->ethaddr.addr); Options = ( XEM_INSERT_FCS_OPTION | XEM_INSERT_PAD_OPTION | XEM_UNICAST_OPTION | XEM_BROADCAST_OPTION | XEM_POLLED_OPTION | XEM_STRIP_PAD_FCS_OPTION); XEmac_SetOptions(xemacif_ptr->instance_ptr, Options); XEmac_Start(xemacif_ptr->instance_ptr); } return p; } #if 0 xil_printf("\r\n"); for (i=0 ; i < FrameLen ; i++) { xil_printf("%2X", frame_bytes[i]); if (! (i%20) && i) xil_printf("\r\n"); else xil_printf(" "); } xil_printf ("\r\n"); #endif /* Allocate a pbuf chain of pbufs from the pool. */ p = pbuf_alloc(PBUF_RAW, FrameLen, PBUF_POOL); if (p != NULL) { /* Iterate over the pbuf chain until we have * read the entire packet into the pbuf. */ for(q = p; q != NULL; q = q->next) { /* Read enough bytes to fill this pbuf * in the chain. The available data in * the pbuf is given by the q->len variable. */ for (i = 0 ; i < q->len ; i++) { ((u8_t *)q->payload)[i] = *(frame_bytes++); } } #ifdef LINK_STATS lwip_stats.link.recv++; #endif /* LINK_STATS */ } else { #ifdef LINK_STATS lwip_stats.link.memerr++; lwip_stats.link.drop++; #endif /* LINK_STATS */ ; } return p; } /*---------------------------------------------------------------------------*/ /* xemacif_input(): */ /* */ /* This function should be called when a packet is ready to be read */ /* from the interface. It uses the function low_level_input() that */ /* should handle the actual reception of bytes from the network */ /* interface. */ /*---------------------------------------------------------------------------*/ err_t xemacif_input(void *CallBackRef) { struct netif * netif_ptr = (struct netif *) CallBackRef; XEmacIf_Config * xemacif_ptr; struct eth_hdr * ethernet_header; struct pbuf *p; xemacif_ptr = netif_ptr->state; p = low_level_input(xemacif_ptr); if (p != NULL) { ethernet_header = p->payload; q = NULL; switch (htons(ethernet_header->type)) { case ETHTYPE_IP: etharp_ip_input(netif_ptr, p); pbuf_header(p, -14); netif_ptr->input(p, netif_ptr); break; case ETHTYPE_ARP: etharp_arp_input(netif_ptr, &(xemacif_ptr->ethaddr), p); break; default: pbuf_free(p); break; } } return ERR_OK; } /*---------------------------------------------------------------------------*/ /* xemacif_setmac(): */ /* */ /* Sets the MAC address of the system. */ /* Note: Should only be called before xemacif_init is called. */ /* - the stack calls xemacif_init after the user calls netif_add */ /*---------------------------------------------------------------------------*/ void xemacif_setmac(u32_t index, u8_t *addr) { XEmacIf_ConfigTable[index].ethaddr.addr[0] = addr[0]; XEmacIf_ConfigTable[index].ethaddr.addr[1] = addr[1]; XEmacIf_ConfigTable[index].ethaddr.addr[2] = addr[2]; XEmacIf_ConfigTable[index].ethaddr.addr[3] = addr[3]; XEmacIf_ConfigTable[index].ethaddr.addr[4] = addr[4]; XEmacIf_ConfigTable[index].ethaddr.addr[5] = addr[5]; } /*---------------------------------------------------------------------------*/ /* xemacif_getmac(): */ /* */ /* Returns a pointer to the ethaddr variable in the ConfigTable */ /* (6 bytes in length) */ /*---------------------------------------------------------------------------*/ u8_t * xemacif_getmac(u32_t index) { return &(XEmacIf_ConfigTable[index].ethaddr.addr[0]); } /*---------------------------------------------------------------------------*/ /* xemacif_init(): */ /* */ /* Should be called at the beginning of the program to set up the */ /* network interface. It calls the function low_level_init() to do the */ /* actual setup of the hardware. */ /*---------------------------------------------------------------------------*/ err_t xemacif_init(struct netif *netif_ptr) { XEmacIf_Config *xemacif_ptr; xemacif_ptr = (XEmacIf_Config *) netif_ptr->state; netif_ptr->mtu = 1500; netif_ptr->hwaddr_len = 6; netif_ptr->hwaddr[0] = xemacif_ptr->ethaddr.addr[0]; netif_ptr->hwaddr[1] = xemacif_ptr->ethaddr.addr[1]; netif_ptr->hwaddr[2] = xemacif_ptr->ethaddr.addr[2]; netif_ptr->hwaddr[3] = xemacif_ptr->ethaddr.addr[3]; netif_ptr->hwaddr[4] = xemacif_ptr->ethaddr.addr[4]; netif_ptr->hwaddr[5] = xemacif_ptr->ethaddr.addr[5]; netif_ptr->name[0] = IFNAME0; netif_ptr->name[1] = IFNAME1; netif_ptr->output = etharp_output; netif_ptr->linkoutput = low_level_output; /* removed this statement because the ethaddr in the XEmacIf_Config * structure is now a struct not a pointer to a struct */ //xemacif_ptr->ethaddr = (struct eth_addr *)&(netif_ptr->hwaddr[0]); low_level_init(netif_ptr); etharp_init(); return ERR_OK; } ocproxy-1.60/contrib/ports/old/v2pro/perf.c000066400000000000000000000032171303453231400207010ustar00rootroot00000000000000/* * Copyright (c) 2001-2003 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #include "arch/perf.h" void perf_init(char *fname) { return; } ocproxy-1.60/contrib/ports/old/v2pro/sw_services/000077500000000000000000000000001303453231400221325ustar00rootroot00000000000000ocproxy-1.60/contrib/ports/old/v2pro/sw_services/lwip_v1_00_a/000077500000000000000000000000001303453231400243125ustar00rootroot00000000000000ocproxy-1.60/contrib/ports/old/v2pro/sw_services/lwip_v1_00_a/data/000077500000000000000000000000001303453231400252235ustar00rootroot00000000000000ocproxy-1.60/contrib/ports/old/v2pro/sw_services/lwip_v1_00_a/data/lwip_v2_1_0.mld000066400000000000000000000071231303453231400277450ustar00rootroot00000000000000############################################################################### # Copyright (c) 2001-2003 Swedish Institute of Computer Science. # All rights reserved. # # Copyright (c) 2003 Xilinx, Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # 1. Redistributions of source code must retain the above copyright notice, # this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright notice, # this list of conditions and the following disclaimer in the documentation # and/or other materials provided with the distribution. # 3. The name of the author may not be used to endorse or promote products # derived from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED # WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO # EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; # OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, # WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR # OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF # ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS". # BY PROVIDING THIS DESIGN, CODE, OR INFORMATION AS ONE POSSIBLE # IMPLEMENTATION OF THIS FEATURE, APPLICATION OR STANDARD, XILINX # IS MAKING NO REPRESENTATION THAT THIS IMPLEMENTATION IS FREE FROM # ANY CLAIMS OF INFRINGEMENT, AND YOU ARE RESPONSIBLE FOR OBTAINING # ANY RIGHTS YOU MAY REQUIRE FOR YOUR IMPLEMENTATION. XILINX # EXPRESSLY DISCLAIMS ANY WARRANTY WHATSOEVER WITH RESPECT TO THE # ADEQUACY OF THE IMPLEMENTATION, INCLUDING BUT NOT LIMITED TO ANY # WARRANTIES OR REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE # FROM CLAIMS OF INFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY # AND FITNESS FOR A PARTICULAR PURPOSE. # # This file is part of the lwIP TCP/IP stack. # # Author: Sathya Thammanur # ############################################################################### OPTION psf_version = 2.1; BEGIN LIBRARY lwip OPTION drc = lwip_drc; OPTION copyfiles = (Makefile); BEGIN ARRAY emac_instances PROPERTY desc = "List of Ethernet instances to be used with lwip"; PROPERTY size = 0; PARAM name = emac_instname, desc = "Name of Emac instance", type = peripheral_instance; PARAM name = eth_addr1, desc = "First byte of MAC address", type = int; PARAM name = eth_addr2, desc = "Second byte of MAC address", type = int; PARAM name = eth_addr3, desc = "Third byte of MAC address", type = int; PARAM name = eth_addr4, desc = "Fourth byte of MAC address", type = int; PARAM name = eth_addr5, desc = "Fifth byte of MAC address", type = int; PARAM name = eth_addr6, desc = "Sixth byte of MAC address", type = int; END ARRAY BEGIN ARRAY gemac_instances PROPERTY desc = "List of Gigabit Ethernet instances to be used with lwip"; PROPERTY size = 0; PARAM name = gemac_instname, desc = "Name of GEmac instance", type = peripheral_instance; END ARRAY PARAM name = lwip_srcdir, desc = "Source directory of lwip", type = string; END LIBRARY ocproxy-1.60/contrib/ports/old/v2pro/sw_services/lwip_v1_00_a/data/lwip_v2_1_0.tcl000066400000000000000000000254201303453231400277530ustar00rootroot00000000000000############################################################################### # Copyright (c) 2001-2003 Swedish Institute of Computer Science. # All rights reserved. # # Copyright (c) 2003 Xilinx, Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # 1. Redistributions of source code must retain the above copyright notice, # this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright notice, # this list of conditions and the following disclaimer in the documentation # and/or other materials provided with the distribution. # 3. The name of the author may not be used to endorse or promote products # derived from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED # WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO # EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; # OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, # WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR # OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF # ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS". # BY PROVIDING THIS DESIGN, CODE, OR INFORMATION AS ONE POSSIBLE # IMPLEMENTATION OF THIS FEATURE, APPLICATION OR STANDARD, XILINX # IS MAKING NO REPRESENTATION THAT THIS IMPLEMENTATION IS FREE FROM # ANY CLAIMS OF INFRINGEMENT, AND YOU ARE RESPONSIBLE FOR OBTAINING # ANY RIGHTS YOU MAY REQUIRE FOR YOUR IMPLEMENTATION. XILINX # EXPRESSLY DISCLAIMS ANY WARRANTY WHATSOEVER WITH RESPECT TO THE # ADEQUACY OF THE IMPLEMENTATION, INCLUDING BUT NOT LIMITED TO ANY # WARRANTIES OR REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE # FROM CLAIMS OF INFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY # AND FITNESS FOR A PARTICULAR PURPOSE. # # This file is part of the lwIP TCP/IP stack. # # Author: Sathya Thammanur # Author: Chris Borrelli # ############################################################################### # Globals lappend emac_list lappend gemac_list ############################################################################### # lwip_drc - run drc checking (future work) ############################################################################### proc lwip_drc {lib_handle} { puts "LWIP DRC..." puts " ...not implemented yet." } ############################################################################### # generate - generates the .c file ############################################################################### proc generate {libname} { global emac_list global gemac_list # generate emac_list of instances to be used with lwip set emac_inst_array [xget_handle $libname "ARRAY" "emac_instances"] if {[string compare -nocase $emac_inst_array ""] != 0} { set emac_inst_array_elems [xget_handle $emac_inst_array "ELEMENTS" "*"] puts "XEmac Instances : [llength $emac_inst_array_elems]" if {[string compare -nocase $emac_inst_array_elems ""] != 0} { set emac_list $emac_inst_array_elems } } # generate gemac_list of instances to be used with lwip set gemac_inst_array [xget_handle $libname "ARRAY" "gemac_instances"] if {[string compare -nocase $gemac_inst_array ""] != 0} { set gemac_inst_array_elems [xget_handle $gemac_inst_array "ELEMENTS" "*"] puts "XGEmac Instances : [llength $gemac_inst_array_elems]" if {[string compare -nocase $gemac_inst_array_elems ""] != 0} { set gemac_list $gemac_inst_array_elems } } # Generate XEmacIf_Config Table in xemacif_g.c file if {[string compare -nocase $emac_list ""] != 0} { xgen_config_file "xemacif_g.c" "XEmacIf" } # Generate XGEmacIf_Config Table in xgemacif_g.c file if {[string compare -nocase $gemac_list ""] != 0} { xgen_config_file "xgemacif_g.c" "XGEmacIf" } } ############################################################################### # xgen_config_file - does the real work of generating a C header file ############################################################################### proc xgen_config_file {file_name if_type} { global emac_list global gemac_list lappend list puts "Generating $file_name ..." set config_file [open [file join "src" $file_name] w] xprint_generated_header $config_file "$if_type Configuration" puts $config_file "#include \"xparameters.h\"" set if_file [file join "netif" [format "%s.h" [string tolower $if_type]]] puts $config_file "#include \"$if_file\"" if {[string compare -nocase $if_type "XEmacIf"] == 0} { puts $config_file "#include \"xemac.h\"" set list $emac_list } elseif {[string compare -nocase $if_type "XGEmacIf"] == 0} { puts $config_file "#include \"xgemac.h\"" set list $gemac_list } #set list_size [llength $list] #puts $config_file "\n/*" #puts $config_file " * Number of $if_type Instances" #puts $config_file " */\n" #puts $config_file [format "#define %s_ConfigTableSize %s" $if_type $list_size] puts $config_file "\n/*" puts $config_file " * The configuration table for devices" puts $config_file " */\n" puts $config_file [format "%s_Config %s_ConfigTable\[\] =" $if_type $if_type] puts $config_file "\{" set start_comma "" foreach elem $list { puts $config_file [format "%s\t\{" $start_comma] set comma "" if {[string compare -nocase $if_type "XEmacIf"] == 0} { set inst [xget_value $elem "PARAMETER" "emac_instname"] set ethaddr1 [xget_value $elem "PARAMETER" "eth_addr1"] set ethaddr2 [xget_value $elem "PARAMETER" "eth_addr2"] set ethaddr3 [xget_value $elem "PARAMETER" "eth_addr3"] set ethaddr4 [xget_value $elem "PARAMETER" "eth_addr4"] set ethaddr5 [xget_value $elem "PARAMETER" "eth_addr5"] set ethaddr6 [xget_value $elem "PARAMETER" "eth_addr6"] } elseif {[string compare -nocase $if_type "XGEmacIf"] == 0} { set inst [xget_value $elem "PARAMETER" "emac_instname"] set ethaddr1 "" set ethaddr2 "" set ethaddr3 "" set ethaddr4 "" set ethaddr5 "" set ethaddr6 "" } # Get the instance handle - # for example, get pointer to an instance named my_opb_ethernet # Get the handle to the interrupt port -ip2intc_irpt # (same name in emac and gemac) set inst_handle [xget_hwhandle $inst] set intr_port_name "IP2INTC_Irpt" ######################################################################## # generate device id ######################################################################## puts -nonewline $config_file [format "%s\t\t%s" $comma [xget_name $inst_handle "DEVICE_ID"]] set comma ",\n" ######################################################################## # generate intr id - doesn't work in EDK 3.2.2 ######################################################################## # START : CHRISB COMMENTED THIS OUT #set intr_id [xget_intr_name $inst_handle $intr_port_name] #puts -nonewline $config_file [format "%s\t\t%s" $comma $intr_id] # END : CHRISB COMMENTED THIS OUT # START : CHRISB ADDED THIS puts -nonewline $config_file [format "%s\t\t%s" $comma "0"] # END : CHRISB ADDED THIS ######################################################################## # generate ethaddr ######################################################################## puts -nonewline $config_file [format "%s\t\t{{%s,%s,%s,%s,%s,%s}}" $comma $ethaddr1 $ethaddr2 $ethaddr3 $ethaddr4 $ethaddr5 $ethaddr6] ######################################################################## # generate instance ptr - always NULL because it is setup at runtime ######################################################################## puts -nonewline $config_file [format "%s\t\tNULL" $comma ] puts -nonewline $config_file [format "\n\t\}" ] set start_comma ",\n" } puts $config_file "\n\};" close $config_file } ############################################################################### # This procedure does not work under EDK 3.2.2 ############################################################################### #proc xget_intr_name {periph_handle port_name} { # # set intr_port [xget_handle $periph_handle "PORT" $port_name] # set intr_signal [xget_value $intr_port "VALUE"] # #puts "intr_signal : $intr_signal" # # set mhs_handle [xget_handle $periph_handle "parent"] # set source_port [xget_connected_ports_handle $mhs_handle $intr_signal "sink"] # #puts "sourceport : $source_port" # # set intc_handle [xget_handle $source_port "parent"] # set intc_name [xget_value $intc_handle "NAME"] # # set periph_name [xget_value $periph_handle "NAME"] # # set intc_drvhandle [xget_swhandle $intc_name] # #puts "intcdrvname: [xget_value $intc_drvhandle "NAME"]" # # set level [xget_value $intc_drvhandle "PARAMETER" "level"] # set intr_string "" # if {$level == 0} { # set intr_string "MASK" # set retval [format "XPAR_%s_%s_%s" [string toupper $periph_name] [string toupper $port_name] [string toupper $intr_string]] # } elseif {$level == 1} { # set intr_string "INTR" # set retval [format "XPAR_%s_%s_%s_%s" [string toupper $intc_name] [string toupper $periph_name] [string toupper $port_name] [string toupper $intr_string]] # } # # return $retval #} ############################################################################### # post_generate - doesn't do anything at the moment ############################################################################### proc post_generate {libname} { } ############################################################################### # execs_generate # This procedure builds the liblwipv4.a # library. ############################################################################### proc execs_generate {libname} { global errorCode global errorInfo set topdir [xget_value $libname "PARAMETER" "lwip_srcdir"] puts "\n********************************" puts " Building lwIP library" puts "********************************\n" puts "Using LWIP sources from directory $topdir " if { [catch {exec bash -c "cd src;make all \"TOPDIR=$topdir\" >& logs"} errmsg] } { error $errmsg $errorInfo } } ocproxy-1.60/contrib/ports/old/v2pro/sw_services/lwip_v1_00_a/src/000077500000000000000000000000001303453231400251015ustar00rootroot00000000000000ocproxy-1.60/contrib/ports/old/v2pro/sw_services/lwip_v1_00_a/src/Makefile000077500000000000000000000146101303453231400265460ustar00rootroot00000000000000############################################################################### # Copyright (c) 2001-2003 Swedish Institute of Computer Science. # All rights reserved. # # Copyright (c) 2003 Xilinx, Inc. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # 1. Redistributions of source code must retain the above copyright notice, # this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright notice, # this list of conditions and the following disclaimer in the documentation # and/or other materials provided with the distribution. # 3. The name of the author may not be used to endorse or promote products # derived from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED # WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO # EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; # OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, # WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR # OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF # ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS". # BY PROVIDING THIS DESIGN, CODE, OR INFORMATION AS ONE POSSIBLE # IMPLEMENTATION OF THIS FEATURE, APPLICATION OR STANDARD, XILINX # IS MAKING NO REPRESENTATION THAT THIS IMPLEMENTATION IS FREE FROM # ANY CLAIMS OF INFRINGEMENT, AND YOU ARE RESPONSIBLE FOR OBTAINING # ANY RIGHTS YOU MAY REQUIRE FOR YOUR IMPLEMENTATION. XILINX # EXPRESSLY DISCLAIMS ANY WARRANTY WHATSOEVER WITH RESPECT TO THE # ADEQUACY OF THE IMPLEMENTATION, INCLUDING BUT NOT LIMITED TO ANY # WARRANTIES OR REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE # FROM CLAIMS OF INFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY # AND FITNESS FOR A PARTICULAR PURPOSE. # # This file is part of the lwIP TCP/IP stack. # # Author: Chris Borrelli # # # This Makefile is meant to be run from EDK (libgen). Please do not try # try using this Makefile stand-alone on the command line; it will not work # COMPILER=powerpc-eabi-gcc ARCHIVER=powerpc-eabi-ar ARFLAGS=rs CP=cp COMPILERFLAGS=-Wall -gdwarf #EXTRA_COMPILER_FLAGS = -DIPv4 -fpack-struct -msdata=eabi -mcpu=403 EXTRA_COMPILER_FLAGS = -DIPv4 -msdata=eabi -mcpu=403 LWIPDIR=$(TOPDIR)/lwip/src ARCHDIR=$(TOPDIR)/contrib/ports/v2pro LIB=liblwip4.a RELEASEDIR=../../../lib INCLUDEDIR=../../../include INCLUDES= \ -I$(LWIPDIR)/include \ -I$(LWIPDIR)/include/ipv4 \ -I$(ARCHDIR) \ -I$(ARCHDIR)/include \ -I$(INCLUDEDIR) INCLUDEFILES=$(TOPDIR)/lwip/src/include/ipv4/lwip \ $(TOPDIR)/lwip/src/include/lwip \ $(TOPDIR)/lwip/src/include/netif \ $(TOPDIR)/contrib/ports/v2pro/include/netif \ $(TOPDIR)/contrib/ports/v2pro/include/arch \ $(TOPDIR)/contrib/ports/v2pro/lwipopts.h # COREFILES, CORE4FILES: The minimum set of files needed for lwIP. COREFILES=$(LWIPDIR)/core/mem.c \ $(LWIPDIR)/core/memp.c \ $(LWIPDIR)/core/netif.c \ $(LWIPDIR)/core/pbuf.c \ $(LWIPDIR)/core/stats.c \ $(LWIPDIR)/core/sys.c \ $(LWIPDIR)/core/tcp.c \ $(LWIPDIR)/core/tcp_in.c \ $(LWIPDIR)/core/tcp_out.c \ $(LWIPDIR)/core/udp.c \ CORE4FILES=$(LWIPDIR)/core/ipv4/icmp.c \ $(LWIPDIR)/core/ipv4/ip.c \ $(LWIPDIR)/core/inet.c \ $(LWIPDIR)/core/ipv4/ip_addr.c \ $(LWIPDIR)/core/ipv4/ip_frag.c # NETIFFILES: Files implementing various generic network interface functions. NETIFFILES=$(LWIPDIR)/netif/etharp.c # ARCHFILES: Archiecture specific files. ARCHFILES=$(ARCHDIR)/lib_arch.c \ $(ARCHDIR)/perf.c \ $(ARCHDIR)/netif/xemacif.c \ xemacif_g.c # LWIPFILES: All the above. LWIPFILES=$(COREFILES) $(CORE4FILES) $(NETIFFILES) $(ARCHFILES) LWIPFILESW=$(wildcard $(LWIPFILES)) LWIPOBJS=$(notdir $(LWIPFILESW:.c=.o)) help: @echo "" @echo "This Makefile generates a library for the v2pro port of lwIP." @echo "" @echo " Below are the targets:" @echo "" @echo " make lwiplibs" @echo " This is the target that will compile all lwIP files, and" @echo " build the library, $(LIB). The final library will be" @echo " copied to $(RELEASEDIR)." @echo "" @echo " make lwipinclude" @echo " Copies the lwIP include files into the EDK directory," @echo " $(INCLUDEDIR)" @echo "" @echo " make clean" @echo " Removes all object files and the $(LIB) library from" @echo " the local directory." @echo "" @echo " make depend" @echo " Generates the .depend file, which contains the" @echo " dependancies needed to compile each .c file. The" @echo " .depend file will be generated automatically for" @echo " other targets, so it is not nessessary to run" @echo " make depend." @echo "" %.o: @echo "" @echo "Building File: $@" @echo "" $(COMPILER) $(COMPILERFLAGS) $(EXTRA_COMPILER_FLAGS) $(INCLUDES) -c $(<:.o=.c) all ipv4 lwiplibs: lwipinclude $(LIB) .PHONY: all ipv4 lwiplibs lwip_include help lwipinclude: @for i in $(INCLUDEFILES); do \ echo ${CP} -r $$i ${INCLUDEDIR}; \ ${CP} -r $$i ${INCLUDEDIR}; \ done include: @exit libs: @exit clean: @echo "" @echo "Cleaning up..." @echo "" @rm -f *.o *.a .depend* core depend dep: .depend @exit $(LIB): $(LWIPOBJS) @echo "" @echo "Building lwIP Library, $@" $(ARCHIVER) $(ARFLAGS) $@ $? @cp $@ $(RELEASEDIR)/ .depend: $(LWIPFILES) $(APPFILES) @echo "" @echo "Building dependancies..." $(COMPILER) $(COMPILERFLAGS) $(EXTRA_COMPILER_FLAGS) $(INCLUDES) \ -MM $^ > .depend || rm -f .depend ifneq ($(MAKECMDGOALS), clean) ifneq ($(MAKECMDGOALS), depend) ifneq ($(MAKECMDGOALS), dep) ifneq ($(MAKECMDGOALS), libs) ifneq ($(MAKECMDGOALS), include) ifneq ($(MAKECMDGOALS), help) -include .depend endif endif endif endif endif endif ocproxy-1.60/contrib/ports/unix/000077500000000000000000000000001303453231400167335ustar00rootroot00000000000000ocproxy-1.60/contrib/ports/unix/check/000077500000000000000000000000001303453231400200105ustar00rootroot00000000000000ocproxy-1.60/contrib/ports/unix/check/README000066400000000000000000000004461303453231400206740ustar00rootroot00000000000000 Helper files to run lwIP unit tests on unix-like systems. 1. Install the check library, through a package manager or from http://check.sourceforge.net/ 2. Put the lwip code in a directory called 'lwip' in the same directory as lwip-contrib is 3. Run `make check` 4. Make sure all tests pass ocproxy-1.60/contrib/ports/unix/check/sys_arch.c000066400000000000000000000003151303453231400217660ustar00rootroot00000000000000#include #include "lwip/opt.h" u32_t sys_now(void) { struct timeval tv; if (gettimeofday(&tv, NULL)) return 0; else return tv.tv_sec * 1000 + tv.tv_usec / 1000; } ocproxy-1.60/contrib/ports/unix/include/000077500000000000000000000000001303453231400203565ustar00rootroot00000000000000ocproxy-1.60/contrib/ports/unix/include/arch/000077500000000000000000000000001303453231400212735ustar00rootroot00000000000000ocproxy-1.60/contrib/ports/unix/include/arch/cc.h000066400000000000000000000061521303453231400220350ustar00rootroot00000000000000/* * Copyright (c) 2001-2003 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #ifndef LWIP_ARCH_CC_H #define LWIP_ARCH_CC_H /* Include some files for defining library routines */ #include #include #include #define LWIP_TIMEVAL_PRIVATE 0 /* Define platform endianness */ #ifndef BYTE_ORDER #define BYTE_ORDER LITTLE_ENDIAN #endif /* BYTE_ORDER */ /* Define generic types used in lwIP */ typedef unsigned char u8_t; typedef signed char s8_t; typedef unsigned short u16_t; typedef signed short s16_t; typedef unsigned int u32_t; typedef signed int s32_t; typedef unsigned long mem_ptr_t; /* Define (sn)printf formatters for these lwIP types */ #define X8_F "02x" #define U16_F "hu" #define S16_F "hd" #define X16_F "hx" #define U32_F "u" #define S32_F "d" #define X32_F "x" /* If only we could use C99 and get %zu */ #if defined(__x86_64__) #define SZT_F "lu" #else #define SZT_F "u" #endif /* Compiler hints for packing structures */ #define PACK_STRUCT_FIELD(x) x #define PACK_STRUCT_STRUCT __attribute__((packed)) #define PACK_STRUCT_BEGIN #define PACK_STRUCT_END /* prototypes for printf() and abort() */ #include #include /* Plaform specific diagnostic output */ #define LWIP_PLATFORM_DIAG(x) do {printf x;} while(0) #ifdef LWIP_UNIX_EMPTY_ASSERT #define LWIP_PLATFORM_ASSERT(x) #else #define LWIP_PLATFORM_ASSERT(x) do {printf("Assertion \"%s\" failed at line %d in %s\n", \ x, __LINE__, __FILE__); fflush(NULL); abort();} while(0) #endif #define LWIP_RAND() ((u32_t)rand()) #endif /* LWIP_ARCH_CC_H */ ocproxy-1.60/contrib/ports/unix/include/arch/perf.h000066400000000000000000000051471303453231400224070ustar00rootroot00000000000000/* * Copyright (c) 2001-2003 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #ifndef LWIP_ARCH_PERF_H #define LWIP_ARCH_PERF_H #include #ifdef PERF #define PERF_START { \ unsigned long __c1l, __c1h, __c2l, __c2h; \ __asm__(".byte 0x0f, 0x31" : "=a" (__c1l), "=d" (__c1h)) #define PERF_STOP(x) __asm__(".byte 0x0f, 0x31" : "=a" (__c2l), "=d" (__c2h)); \ perf_print(__c1l, __c1h, __c2l, __c2h, x);} /*#define PERF_START do { \ struct tms __perf_start, __perf_end; \ times(&__perf_start) #define PERF_STOP(x) times(&__perf_end); \ perf_print_times(&__perf_start, &__perf_end, x);\ } while(0)*/ #else /* PERF */ #define PERF_START /* null definition */ #define PERF_STOP(x) /* null definition */ #endif /* PERF */ void perf_print(unsigned long c1l, unsigned long c1h, unsigned long c2l, unsigned long c2h, char *key); void perf_print_times(struct tms *start, struct tms *end, char *key); void perf_init(char *fname); #endif /* LWIP_ARCH_PERF_H */ ocproxy-1.60/contrib/ports/unix/include/arch/sys_arch.h000066400000000000000000000044671303453231400232720ustar00rootroot00000000000000/* * Copyright (c) 2001-2003 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #ifndef LWIP_ARCH_SYS_ARCH_H #define LWIP_ARCH_SYS_ARCH_H #include #define SYS_MBOX_NULL NULL #define SYS_SEM_NULL NULL typedef u32_t sys_prot_t; struct sys_sem; typedef struct sys_sem * sys_sem_t; #define sys_sem_valid(sem) (((sem) != NULL) && (*(sem) != NULL)) #define sys_sem_set_invalid(sem) do { if((sem) != NULL) { *(sem) = NULL; }}while(0) /* let sys.h use binary semaphores for mutexes */ #define LWIP_COMPAT_MUTEX 1 struct sys_mbox; typedef struct sys_mbox *sys_mbox_t; #define sys_mbox_valid(mbox) (((mbox) != NULL) && (*(mbox) != NULL)) #define sys_mbox_set_invalid(mbox) do { if((mbox) != NULL) { *(mbox) = NULL; }}while(0) struct sys_thread; typedef struct sys_thread * sys_thread_t; #endif /* LWIP_ARCH_SYS_ARCH_H */ ocproxy-1.60/contrib/ports/unix/include/netif/000077500000000000000000000000001303453231400214635ustar00rootroot00000000000000ocproxy-1.60/contrib/ports/unix/include/netif/delif.h000066400000000000000000000034241303453231400227220ustar00rootroot00000000000000/* * Copyright (c) 2001-2003 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #ifndef LWIP_DELIF_H #define LWIP_DELIF_H #include "lwip/netif.h" #include "lwip/pbuf.h" err_t delif_init(struct netif *netif); err_t delif_init_thread(struct netif *netif); #endif /* LWIP_DELIF_H */ ocproxy-1.60/contrib/ports/unix/include/netif/dropif.h000066400000000000000000000033521303453231400231220ustar00rootroot00000000000000/* * Copyright (c) 2001-2003 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #ifndef LWIP_DROPIF_H #define LWIP_DROPIF_H #include "lwip/netif.h" #include "lwip/pbuf.h" err_t dropif_init(struct netif *netif); #endif /* LWIP_DROPIF_H */ ocproxy-1.60/contrib/ports/unix/include/netif/fifo.h000066400000000000000000000032501303453231400225570ustar00rootroot00000000000000#ifndef FIFO_H #define FIFO_H #include "lwip/sys.h" /** How many bytes in fifo */ #define FIFOSIZE 2048 /** fifo data structure, this one is passed to all fifo functions */ typedef struct fifo_t { u8_t data[FIFOSIZE+10]; /* data segment, +10 is a hack probably not needed.. FIXME! */ int dataslot; /* index to next char to be read */ int emptyslot; /* index to next empty slot */ int len; /* len probably not needed, may be calculated from dataslot and emptyslot in conjunction with FIFOSIZE */ sys_sem_t sem; /* semaphore protecting simultaneous data manipulation */ sys_sem_t getSem; /* sepaphore used to signal new data if getWaiting is set */ u8_t getWaiting; /* flag used to indicate that fifoget is waiting for data. fifoput is suposed to clear */ /* this flag prior to signaling the getSem semaphore */ } fifo_t; /** * Get a character from fifo * Blocking call. * @param pointer to fifo data structure * @return character read from fifo */ u8_t fifoGet(fifo_t * fifo); /** * Get a character from fifo * Non blocking call. * @param pointer to fifo data structure * @return character read from fifo, or < zero if non was available */ s16_t fifoGetNonBlock(fifo_t * fifo); /** * fifoput is called by the signalhandler when new data has arrived (or some other event is indicated) * fifoput reads directly from the serialport and is thus highly dependent on unix arch at this moment * @param fifo pointer to fifo data structure * @param fd unix file descriptor */ void fifoPut(fifo_t * fifo, int fd); /** * fifoinit initiate fifo * @param fifo pointer to fifo data structure, allocated by the user */ void fifoInit(fifo_t * fifo); #endif ocproxy-1.60/contrib/ports/unix/include/netif/list.h000066400000000000000000000010021303453231400226000ustar00rootroot00000000000000 #ifndef LWIP_LIST_H #define LWIP_LIST_H struct elem; struct list { struct elem *first, *last; int size, elems; }; struct elem { struct elem *next; void *data; }; struct list *list_new(int size); int list_push(struct list *list, void *data); void *list_pop(struct list *list); void *list_first(struct list *list); int list_elems(struct list *list); void list_delete(struct list *list); int list_remove(struct list *list, void *elem); void list_map(struct list *list, void (* func)(void *arg)); #endif ocproxy-1.60/contrib/ports/unix/include/netif/pcapif.h000066400000000000000000000033221303453231400230760ustar00rootroot00000000000000/* * Copyright (c) 2001-2003 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #ifndef LWIP_PCAPIF_H #define LWIP_PCAPIF_H #include "lwip/netif.h" err_t pcapif_init(struct netif *netif); #endif /* LWIP_PCAPIF_H */ ocproxy-1.60/contrib/ports/unix/include/netif/sio.h000066400000000000000000000046101303453231400224270ustar00rootroot00000000000000#ifndef SIO_H #define SIO_H #include "lwip/sys.h" #include "lwip/netif.h" #include "netif/fifo.h" /*#include "netif/pppif.h"*/ /* BAUDRATE is defined in sio.c as it is implementation specific */ typedef struct sio_status_t { int fd; fifo_t myfifo; } sio_status_t; /** Baudrates */ typedef enum sioBaudrates { SIO_BAUD_9600, SIO_BAUD_19200, SIO_BAUD_38400, SIO_BAUD_57600, SIO_BAUD_115200 } sioBaudrates; /** * Read a char from incoming data stream, this call blocks until data has arrived * @param siostat siostatus struct, contains sio instance data, given by sio_open * @return char read from input stream */ u8_t sio_recv( sio_status_t * siostat ); /** * Poll for a new character from incoming data stream * @param siostat siostatus struct, contains sio instance data, given by sio_open * @return char read from input stream, or < 0 if no char was available */ s16_t sio_poll(sio_status_t * siostat); /** * Parse incoming characters until a string str is recieved, blocking call * @param str zero terminated string to expect * @param siostat siostatus struct, contains sio instance data, given by sio_open */ void sio_expect_string(u8_t *str, sio_status_t * siostat); /** * Write a char to output data stream * @param c char to write to output stream * @param siostat siostatus struct, contains sio instance data, given by sio_open */ void sio_send( u8_t c, sio_status_t * siostat ); /** * Write a char to output data stream * @param str pointer to a zero terminated string * @param siostat siostatus struct, contains sio instance data, given by sio_open */ void sio_send_string(u8_t *str, sio_status_t * siostat); /** * Flush outbuffer (send everything in buffer now), useful if some layer below is * holding on to data, waitng to fill a buffer * @param siostat siostatus struct, contains sio instance data, given by sio_open */ void sio_flush( sio_status_t * siostat ); /** * Open serial port entry point from serial protocol (slipif, pppif) * @param devnum the device number to use, i.e. ttySx, comx:, etc. there x = devnum * @return siostatus struct, contains sio instance data, use when calling sio functions */ sio_status_t * sio_open( int devnum ); /** * Change baudrate of port, may close and reopen port * @param baud new baudrate * @param siostat siostatus struct, contains sio instance data, given by sio_open */ void sio_change_baud( sioBaudrates baud, sio_status_t * siostat ); #endif ocproxy-1.60/contrib/ports/unix/include/netif/tapif.h000066400000000000000000000033161303453231400227420ustar00rootroot00000000000000/* * Copyright (c) 2001-2003 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #ifndef LWIP_TAPIF_H #define LWIP_TAPIF_H #include "lwip/netif.h" err_t tapif_init(struct netif *netif); #endif /* LWIP_TAPIF_H */ ocproxy-1.60/contrib/ports/unix/include/netif/tcpdump.h000066400000000000000000000033651303453231400233170ustar00rootroot00000000000000/* * Copyright (c) 2001-2003 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #ifndef LWIP_NETIF_TCPDUMP_H #define LWIP_NETIF_TCPDUMP_H #include "lwip/pbuf.h" void tcpdump_init(void); void tcpdump(struct pbuf *p); #endif /* LWIP_NETIF_TCPDUMP_H */ ocproxy-1.60/contrib/ports/unix/include/netif/tunif.h000066400000000000000000000033461303453231400227670ustar00rootroot00000000000000/* * Copyright (c) 2001-2003 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #ifndef LWIP_TUNIF_H #define LWIP_TUNIF_H #include "lwip/netif.h" #include "lwip/pbuf.h" err_t tunif_init(struct netif *netif); #endif /* LWIP_TUNIF_H */ ocproxy-1.60/contrib/ports/unix/include/netif/unixif.h000066400000000000000000000034101303453231400231340ustar00rootroot00000000000000/* * Copyright (c) 2001-2003 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #ifndef LWIP_UNIXIF_H #define LWIP_UNIXIF_H #include "lwip/netif.h" err_t unixif_init_server(struct netif *netif); err_t unixif_init_client(struct netif *netif); #endif /* LWIP_UNIXIF_H */ ocproxy-1.60/contrib/ports/unix/lwip_chksum.c000066400000000000000000000050631303453231400214300ustar00rootroot00000000000000/* * Copyright (c) 2001-2003 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #include "lwip/debug.h" #include "lwip/arch.h" #include "lwip/def.h" #include "lwip/inet.h" /*-----------------------------------------------------------------------------------*/ /* lwip_chksum: * * Sums up all 16 bit words in a memory portion. Also includes any odd byte. * This function is used by the other checksum functions. * */ /*-----------------------------------------------------------------------------------*/ #if 0 u16_t lwip_chksum(void *dataptr, int len) { u32_t acc; for(acc = 0; len > 1; len -= 2) { acc += *((u16_t *)dataptr)++; } /* add up any odd byte */ if (len == 1) { acc += htons((u16_t)((*(u8_t *)dataptr) & 0xff) << 8); LWIP_DEBUGF(INET_DEBUG, ("inet: chksum: odd byte %d\n", *(u8_t *)dataptr)); } acc = (acc >> 16) + (acc & 0xffffUL); if (acc & 0xffff0000 != 0) { acc = (acc >> 16) + (acc & 0xffffUL); } return (u16_t)acc; } /*-----------------------------------------------------------------------------------*/ #endif ocproxy-1.60/contrib/ports/unix/netif/000077500000000000000000000000001303453231400200405ustar00rootroot00000000000000ocproxy-1.60/contrib/ports/unix/netif/delif.c000066400000000000000000000203701303453231400212710ustar00rootroot00000000000000/* * Copyright (c) 2001-2003 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #include "lwip/debug.h" #include #include "lwip/def.h" #include "netif/delif.h" #ifdef linux #include "netif/tapif.h" #else /* linux */ #include "netif/tunif.h" #endif /* linux */ #include "lwip/sys.h" #define DELIF_INPUT_DROPRATE 0.1 #define DELIF_OUTPUT_DROPRATE 0.1 #define DELIF_INPUT_DELAY 500 /* Miliseconds. */ #define DELIF_OUTPUT_DELAY 500 /* Miliseconds. */ #define DELIF_TIMEOUT 10 struct delif { err_t (* input)(struct pbuf *p, struct netif *inp); struct netif *netif; }; struct delif_pbuf { struct delif_pbuf *next; struct pbuf *p; ip_addr_t *ipaddr; unsigned int time; }; static struct delif_pbuf *input_list = NULL; static struct delif_pbuf *output_list = NULL; /*-----------------------------------------------------------------------------------*/ static void delif_input_timeout(void *arg) { struct netif *netif; struct delif *delif; struct delif_pbuf *dp; unsigned int timeout, now; timeout = DELIF_TIMEOUT; netif = arg; delif = netif->state; /* Check if there is anything on the input list. */ dp = input_list; while (dp != NULL) { now = sys_now(); if (dp->time <= now) { delif->input(dp->p, netif); if (dp->next != NULL) { if (dp->next->time > now) { timeout = dp->next->time - now; } else { timeout = 0; } LWIP_DEBUGF(DELIF_DEBUG, ("delif_output_timeout: timeout %u.\n", timeout)); } input_list = dp->next; free(dp); dp = input_list; } else { dp = dp->next; } } sys_timeout(timeout, delif_input_timeout, arg); } /*-----------------------------------------------------------------------------------*/ static void delif_output_timeout(void *arg) { struct netif *netif; struct delif *delif; struct delif_pbuf *dp; unsigned int timeout, now; timeout = DELIF_TIMEOUT; netif = arg; delif = netif->state; /* Check if there is anything on the output list. */ dp = output_list; while (dp != NULL) { now = sys_now(); if (dp->time <= now) { LWIP_DEBUGF(DELIF_DEBUG, ("delif_output_timeout: now %u dp->time %u\n", now, dp->time)); delif->netif->output(delif->netif, dp->p, dp->ipaddr); if (dp->next != NULL) { if (dp->next->time > now) { timeout = dp->next->time - now; } else { timeout = 0; } LWIP_DEBUGF(DELIF_DEBUG, ("delif_output_timeout: timeout %u.\n", timeout)); } pbuf_free(dp->p); output_list = dp->next; free(dp); dp = output_list; } else { dp = dp->next; } } sys_timeout(timeout, delif_output_timeout, arg); } /*-----------------------------------------------------------------------------------*/ static err_t delif_output(struct netif *netif, struct pbuf *p, ip_addr_t *ipaddr) { struct delif_pbuf *dp, *np; struct pbuf *q; int i, j; char *data; LWIP_DEBUGF(DELIF_DEBUG, ("delif_output\n")); #ifdef DELIF_OUTPUT_DROPRATE if (((double)rand()/(double)RAND_MAX) < DELIF_OUTPUT_DROPRATE) { LWIP_DEBUGF(DELIF_DEBUG, ("delif_output: Packet dropped\n")); return 0; } #endif /* DELIF_OUTPUT_DROPRATE */ LWIP_DEBUGF(DELIF_DEBUG, ("delif_output\n")); dp = malloc(sizeof(struct delif_pbuf)); data = malloc(p->tot_len); i = 0; for(q = p; q != NULL; q = q->next) { for(j = 0; j < q->len; j++) { data[i] = ((char *)q->payload)[j]; i++; } } dp->p = pbuf_alloc(PBUF_LINK, 0, PBUF_ROM); dp->p->payload = data; dp->p->len = p->tot_len; dp->p->tot_len = p->tot_len; dp->ipaddr = ipaddr; dp->time = sys_now() + DELIF_OUTPUT_DELAY; dp->next = NULL; if (output_list == NULL) { output_list = dp; } else { for(np = output_list; np->next != NULL; np = np->next); np->next = dp; } return ERR_OK; } /*-----------------------------------------------------------------------------------*/ static err_t delif_input(struct pbuf *p, struct netif *inp) { struct delif_pbuf *dp, *np; LWIP_DEBUGF(DELIF_DEBUG, ("delif_input\n")); #ifdef DELIF_INPUT_DROPRATE if (((double)rand()/(double)RAND_MAX) < DELIF_INPUT_DROPRATE) { LWIP_DEBUGF(DELIF_DEBUG, ("delif_input: Packet dropped\n")); pbuf_free(p); return ERR_OK; } #endif /* DELIF_INPUT_DROPRATE */ dp = malloc(sizeof(struct delif_pbuf)); dp->p = p; dp->time = sys_now() + DELIF_INPUT_DELAY; dp->next = NULL; if (input_list == NULL) { input_list = dp; } else { for(np = input_list; np->next != NULL; np = np->next); np->next = dp; } return ERR_OK; } /*-----------------------------------------------------------------------------------*/ err_t delif_init(struct netif *netif) { struct delif *del; del = malloc(sizeof(struct delif)); if (!del) return ERR_MEM; netif->state = del; netif->name[0] = 'd'; netif->name[1] = 'e'; netif->output = delif_output; del->netif = malloc(sizeof(struct netif)); if (!del->netif) { free(del); return ERR_MEM; } #ifdef linux /* tapif_init(del->netif);*/ tunif_init(del->netif); #else /* linux */ tunif_init(del->netif); #endif /* linux */ del->input = netif->input; del->netif->input = delif_input; sys_timeout(DELIF_TIMEOUT, delif_input_timeout, netif); sys_timeout(DELIF_TIMEOUT, delif_output_timeout, netif); return ERR_OK; } /*-----------------------------------------------------------------------------------*/ static void delif_thread(void *arg) { struct netif *netif = arg; struct delif *del; sys_sem_t sem; del = netif->state; #ifdef linux tapif_init(del->netif); #else /* linux */ tunif_init(del->netif); #endif /* linux */ sys_timeout(DELIF_TIMEOUT, delif_input_timeout, netif); sys_timeout(DELIF_TIMEOUT, delif_output_timeout, netif); if(sys_sem_new(&sem, 0) != ERR_OK) { LWIP_ASSERT("Failed to create semaphore", 0); } sys_sem_wait(&sem); } /*-----------------------------------------------------------------------------------*/ err_t delif_init_thread(struct netif *netif) { struct delif *del; LWIP_DEBUGF(DELIF_DEBUG, ("delif_init_thread\n")); del = malloc(sizeof(struct delif)); if (!del) return ERR_MEM; netif->state = del; netif->name[0] = 'd'; netif->name[1] = 'e'; netif->output = delif_output; del->netif = malloc(sizeof(struct netif)); if (!del->netif) { free(del); return ERR_MEM; } del->netif->ip_addr = netif->ip_addr; del->netif->gw = netif->gw; del->netif->netmask = netif->netmask; del->input = netif->input; del->netif->input = delif_input; sys_thread_new("delif_thread", delif_thread, netif, DEFAULT_THREAD_STACKSIZE, DEFAULT_THREAD_PRIO); return ERR_OK; } /*-----------------------------------------------------------------------------------*/ ocproxy-1.60/contrib/ports/unix/netif/fifo.c000066400000000000000000000057571303453231400211450ustar00rootroot00000000000000/* Author: Magnus Ivarsson */ /* ---------------------------------------------- */ /* --- fifo 4 unix ------------------------------ */ /* ---------------------------------------------- */ #include "netif/fifo.h" #include "lwip/debug.h" #include "lwip/def.h" #include "lwip/sys.h" #include "lwip/arch.h" #include #ifndef TRUE #define TRUE 1 #endif #ifndef FALSE #define FALSE 0 #endif u8_t fifoGet(fifo_t * fifo) { u8_t c; sys_sem_wait(&fifo->sem); /* enter critical section */ if (fifo->dataslot == fifo->emptyslot) { fifo->getWaiting = TRUE; /* tell putFifo to signal us when data is available */ sys_sem_signal(&fifo->sem); /* leave critical section (allow input from serial port..) */ sys_sem_wait(&fifo->getSem); /* wait 4 data */ sys_sem_wait(&fifo->sem); /* reenter critical section */ } c = fifo->data[fifo->dataslot++]; fifo->len--; if (fifo->dataslot == FIFOSIZE) { fifo->dataslot = 0; } sys_sem_signal(&fifo->sem); /* leave critical section */ return c; } s16_t fifoGetNonBlock(fifo_t * fifo) { u16_t c; sys_sem_wait(&fifo->sem); /* enter critical section */ if (fifo->dataslot == fifo->emptyslot) { /* empty fifo */ c = -1; } else { c = fifo->data[fifo->dataslot++]; fifo->len--; if (fifo->dataslot == FIFOSIZE) { fifo->dataslot = 0; } } sys_sem_signal(&fifo->sem); /* leave critical section */ return c; } void fifoPut(fifo_t * fifo, int fd) { /* FIXME: mutex around struct data.. */ int cnt=0; sys_sem_wait(&fifo->sem ); /* enter critical */ LWIP_DEBUGF( SIO_FIFO_DEBUG,("fifoput: len%d dat%d empt%d --> ", fifo->len, fifo->dataslot, fifo->emptyslot ) ); if ( fifo->emptyslot < fifo->dataslot ) { cnt = read( fd, &fifo->data[fifo->emptyslot], fifo->dataslot - fifo->emptyslot ); } else { cnt = read( fd, &fifo->data[fifo->emptyslot], FIFOSIZE-fifo->emptyslot ); } fifo->emptyslot += cnt; fifo->len += cnt; LWIP_DEBUGF( SIO_FIFO_DEBUG,("len%d dat%d empt%d\n", fifo->len, fifo->dataslot, fifo->emptyslot ) ); if ( fifo->len > FIFOSIZE ) { printf( "ERROR: fifo overrun detected len=%d, flushing\n", fifo->len ); fifo->dataslot = 0; fifo->emptyslot = 0; fifo->len = 0; } if ( fifo->emptyslot == FIFOSIZE ) { fifo->emptyslot = 0; LWIP_DEBUGF( SIO_FIFO_DEBUG, ("(WRAP) ") ); sys_sem_signal(&fifo->sem ); /* leave critical */ fifoPut( fifo, fd ); return; } if ( fifo->getWaiting ) { fifo->getWaiting = FALSE; sys_sem_signal(&fifo->getSem ); } sys_sem_signal(&fifo->sem ); /* leave critical */ return; } void fifoInit(fifo_t * fifo) { fifo->dataslot = 0; fifo->emptyslot = 0; fifo->len = 0; if(sys_sem_new(&fifo->sem, 1) != ERR_OK) { /* critical section 1=free to enter */ LWIP_ASSERT("Failed to create semaphore", 0); } if(sys_sem_new(&fifo->getSem, 0) != ERR_OK) { /* 0 = no one waiting */ LWIP_ASSERT("Failed to create semaphore", 0); } fifo->getWaiting = FALSE; } ocproxy-1.60/contrib/ports/unix/netif/list.c000066400000000000000000000101671303453231400211640ustar00rootroot00000000000000/* * Copyright (c) 2001-2003 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #include #include /*-----------------------------------------------------------------------------------*/ struct list * list_new(int size) { struct list *list; list = (struct list *)malloc(sizeof(struct list)); list->first = list->last = NULL; list->size = size; list->elems = 0; return list; } /*-----------------------------------------------------------------------------------*/ int list_push(struct list *list, void *data) { struct elem *elem; if (list->elems < list->size) { elem = (struct elem *)malloc(sizeof(struct elem)); elem->data = data; elem->next = NULL; if (list->last != NULL) { list->last->next = elem; } list->last = elem; if (list->first == NULL) { list->first = elem; } list->elems++; return 1; } return 0; } /*-----------------------------------------------------------------------------------*/ void * list_pop(struct list *list) { struct elem *elem; void *data; if (list->elems > 0) { elem = list->first; if (elem == list->last) { list->last = elem->next; } list->first = elem->next; list->elems--; data = elem->data; free(elem); return data; } return NULL; } /*-----------------------------------------------------------------------------------*/ void * list_first(struct list *list) { return list->first; } /*-----------------------------------------------------------------------------------*/ int list_elems(struct list *list) { return list->elems; } /*-----------------------------------------------------------------------------------*/ void list_delete(struct list *list) { while (list_pop(list) != NULL); free(list); } /*-----------------------------------------------------------------------------------*/ int list_remove(struct list *list, void *elem) { struct elem *e, *p; p = NULL; for(e = list->first; e != NULL; e = e->next) { if (e->data == elem) { if (p != NULL) { p->next = e->next; } else { list->first = e->next; } if (list->last == e) { list->last = p; if (p != NULL) { p->next = NULL; } } free(e); list->elems--; return 1; } p = e; } return 0; } /*-----------------------------------------------------------------------------------*/ void list_map(struct list *list, void (* func)(void *arg)) { struct elem *e; for(e = list->first; e != NULL; e = e->next) { func(e->data); } } /*-----------------------------------------------------------------------------------*/ ocproxy-1.60/contrib/ports/unix/netif/pcapif.c000066400000000000000000000141731303453231400214540ustar00rootroot00000000000000/* * Copyright (c) 2001-2003 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #ifndef linux /* Apparently, this doesn't work under Linux. */ #include "lwip/debug.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "netif/etharp.h" #include "lwip/stats.h" #include "lwip/def.h" #include "lwip/mem.h" #include "lwip/pbuf.h" #include "netif/unixif.h" #include "lwip/sys.h" #include "lwip/ip.h" #if defined(LWIP_DEBUG) && defined(LWIP_TCPDUMP) #include "netif/tcpdump.h" #endif /* LWIP_DEBUG && LWIP_TCPDUMP */ struct pcapif { pcap_t *pd; sys_sem_t sem; u8_t pkt[2048]; u32_t len; u32_t lasttime; struct pbuf *p; struct eth_addr *ethaddr; }; static char errbuf[PCAP_ERRBUF_SIZE]; /*-----------------------------------------------------------------------------------*/ static err_t pcapif_output(struct netif *netif, struct pbuf *p, ip_addr_t *ipaddr) { return ERR_OK; } /*-----------------------------------------------------------------------------------*/ static void timeout(void *arg) { struct netif *netif; struct pcapif *pcapif; struct pbuf *p, *q; u8_t *bufptr; struct eth_hdr *ethhdr; netif = (struct netif *)arg; pcapif = netif->state; ethhdr = (struct eth_hdr *)pcapif->pkt; if (htons(ethhdr->type) != ETHTYPE_IP || ip_lookup(pcapif->pkt + 14, netif)) { /* We allocate a pbuf chain of pbufs from the pool. */ p = pbuf_alloc(PBUF_LINK, pcapif->len, PBUF_POOL); if (p != NULL) { /* We iterate over the pbuf chain until we have read the entire packet into the pbuf. */ bufptr = (u_char *)pcapif->pkt; for(q = p; q != NULL; q = q->next) { /* Read enough bytes to fill this pbuf in the chain. The available data in the pbuf is given by the q->len variable. */ /* read data into(q->payload, q->len); */ bcopy(bufptr, q->payload, q->len); bufptr += q->len; } #if defined(LWIP_DEBUG) && defined(LWIP_TCPDUMP) tcpdump(p); #endif /* LWIP_DEBUG && LWIP_TCPDUMP */ ethhdr = p->payload; switch (htons(ethhdr->type)) { /* IP or ARP packet? */ case ETHTYPE_IP: case ETHTYPE_ARP: #if PPPOE_SUPPORT /* PPPoE packet? */ case ETHTYPE_PPPOEDISC: case ETHTYPE_PPPOE: #endif /* PPPOE_SUPPORT */ /* full packet send to tcpip_thread to process */ if (netif->input(p, netif) != ERR_OK) { LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_input: IP input error\n")); pbuf_free(p); p = NULL; } break; default: pbuf_free(p); break; } } } else { printf("ip_lookup dropped\n"); } sys_sem_signal(&pcapif->sem); } /*-----------------------------------------------------------------------------------*/ static void callback(u_char *arg, const struct pcap_pkthdr *hdr, const u_char *pkt) { struct netif *netif; struct pcapif *pcapif; u32_t time, lasttime; netif = (struct netif *)arg; pcapif = netif->state; pcapif->len = hdr->len; bcopy(pkt, pcapif->pkt, hdr->len); time = hdr->ts.tv_sec * 1000 + hdr->ts.tv_usec / 1000; lasttime = pcapif->lasttime; pcapif->lasttime = time; if (lasttime == 0) { sys_timeout(1000, timeout, netif); } else { sys_timeout(time - lasttime, timeout, netif); } } /*-----------------------------------------------------------------------------------*/ static void pcapif_thread(void *arg) { struct netif *netif; struct pcapif *pcapif; netif = arg; pcapif = netif->state; while (1) { pcap_loop(pcapif->pd, 1, callback, (u_char *)netif); sys_sem_wait(&pcapif->sem); if (pcapif->p != NULL) { netif->input(pcapif->p, netif); } } } /*-----------------------------------------------------------------------------------*/ err_t pcapif_init(struct netif *netif) { struct pcapif *p; p = malloc(sizeof(struct pcapif)); if (p == NULL) return ERR_MEM; netif->state = p; netif->name[0] = 'p'; netif->name[1] = 'c'; netif->output = pcapif_output; p->pd = pcap_open_offline("pcapdump", errbuf); if (p->pd == NULL) { printf("pcapif_init: failed %s\n", errbuf); return ERR_IF; } if(sys_sem_new(&p->sem, 0) != ERR_OK) { LWIP_ASSERT("Failed to create semaphore", 0); } p->p = NULL; p->lasttime = 0; sys_thread_new("pcapif_thread", pcapif_thread, netif, DEFAULT_THREAD_STACKSIZE, DEFAULT_THREAD_PRIO); return ERR_OK; } /*-----------------------------------------------------------------------------------*/ #endif /* linux */ ocproxy-1.60/contrib/ports/unix/netif/sio.c000066400000000000000000000216641303453231400210070ustar00rootroot00000000000000/* Author: Magnus Ivarsson */ #include "netif/sio.h" #include "netif/fifo.h" #include "lwip/debug.h" #include "lwip/def.h" #include "lwip/sys.h" #include "lwip/arch.h" /* Following #undefs are here to keep compiler from issuing warnings about them being double defined. (They are defined in lwip/inet.h as well as the Unix #includes below.) */ #undef htonl #undef ntohl #undef htons #undef ntohs #undef HTONL #undef NTOHL #undef HTONS #undef NTOHS #include #if defined(openbsd) #include #endif #include #include #include #include #include #include #include #if PPP_SUPPORT && defined(linux) #include #endif /*#define BAUDRATE B19200 */ /*#define BAUDRATE B57600 */ #define BAUDRATE B115200 #ifndef TRUE #define TRUE 1 #endif #ifndef FALSE #define FALSE 0 #endif /* for all of you who dont define SIO_DEBUG in debug.h */ #ifndef SIO_DEBUG #define SIO_DEBUG 0 #endif /* typedef struct siostruct_t */ /* { */ /* sio_status_t *sio; */ /* } siostruct_t; */ /** array of ((siostruct*)netif->state)->sio structs */ static sio_status_t statusar[3]; #if ! PPP_SUPPORT /* --private-functions----------------------------------------------------------------- */ /** * Signal handler for ttyXX0 to indicate bytes received * one per interface is needed since we cannot send a instance number / pointer as callback argument (?) */ static void signal_handler_IO_0( int status ) { LWIP_UNUSED_ARG(status); LWIP_DEBUGF(SIO_DEBUG, ("SigHand: rxSignal channel 0\n")); fifoPut( &statusar[0].myfifo, statusar[0].fd ); } /** * Signal handler for ttyXX1 to indicate bytes received * one per interface is needed since we cannot send a instance number / pointer as callback argument (?) */ static void signal_handler_IO_1( int status ) { LWIP_UNUSED_ARG(status); LWIP_DEBUGF(SIO_DEBUG, ("SigHand: rxSignal channel 1\n")); fifoPut( &statusar[1].myfifo, statusar[1].fd ); } #endif /** * Initiation of serial device * @param device : string with the device name and path, eg. "/dev/ttyS0" * @param netif : netinterface struct, contains interface instance data * @return file handle to serial dev. */ static int sio_init( char * device, int devnum, sio_status_t * siostat ) { struct termios oldtio,newtio; #if ! PPP_SUPPORT struct sigaction saio; /* definition of signal action */ #endif int fd; LWIP_UNUSED_ARG(siostat); /* open the device to be non-blocking (read will return immediately) */ fd = open( device, O_RDWR | O_NOCTTY | O_NONBLOCK ); if ( fd < 0 ) { perror( device ); exit( -1 ); } #if ! PPP_SUPPORT /* install the signal handler before making the device asynchronous */ switch ( devnum ) { case 0: LWIP_DEBUGF( SIO_DEBUG, ("sioinit, signal_handler_IO_0\n") ); saio.sa_handler = signal_handler_IO_0; break; case 1: LWIP_DEBUGF( SIO_DEBUG, ("sioinit, signal_handler_IO_1\n") ); saio.sa_handler = signal_handler_IO_1; break; default: LWIP_DEBUGF( SIO_DEBUG,("sioinit, devnum not allowed\n") ); break; } saio.sa_flags = 0; #if linux saio.sa_restorer = NULL; #endif /* linux */ sigaction( SIGIO,&saio,NULL ); /* allow the process to receive SIGIO */ fcntl( fd, F_SETOWN, getpid( ) ); /* Make the file descriptor asynchronous (the manual page says only O_APPEND and O_NONBLOCK, will work with F_SETFL...) */ fcntl( fd, F_SETFL, FASYNC ); #else fcntl( fd, F_SETFL, 0 ); #endif /* ! PPP_SUPPORT */ tcgetattr( fd,&oldtio ); /* save current port settings */ /* set new port settings */ /* see 'man termios' for further settings */ newtio.c_cflag = BAUDRATE | CS8 | CLOCAL | CREAD | CRTSCTS; newtio.c_iflag = 0; newtio.c_oflag = 0; newtio.c_lflag = 0; /*ECHO; */ newtio.c_cc[VMIN] = 1; /* Read 1 byte at a time, no timer */ newtio.c_cc[VTIME] = 0; tcsetattr( fd,TCSANOW,&newtio ); tcflush( fd, TCIOFLUSH ); return fd; } /** * */ static void sio_speed( int fd, int speed ) { struct termios oldtio,newtio; /* int fd; */ LWIP_DEBUGF( 1,("sio_speed: baudcode:%d enter\n",speed ) ); if ( fd < 0 ) { LWIP_DEBUGF(SIO_DEBUG, ( "sio_speed: fd ERROR\n" )); exit( -1 ); } tcgetattr( fd,&oldtio ); /* get current port settings */ /* set new port settings * see 'man termios' for further settings */ newtio.c_cflag = speed | CS8 | CLOCAL | CREAD; /*§ | CRTSCTS; */ newtio.c_iflag = 0; newtio.c_oflag = 0; newtio.c_lflag = 0; /*ECHO; */ newtio.c_cc[VMIN] = 1; /* Read 1 byte at a time, no timer */ newtio.c_cc[VTIME] = 0; tcsetattr( fd,TCSANOW,&newtio ); tcflush( fd, TCIOFLUSH ); LWIP_DEBUGF( SIO_DEBUG ,("sio_speed: leave\n" )); } /* --public-functions----------------------------------------------------------------------------- */ void sio_send( u8_t c, sio_status_t * siostat ) { /* sio_status_t * siostat = ((siostruct_t*)netif->state)->sio; */ if ( write( siostat->fd, &c, 1 ) <= 0 ) { LWIP_DEBUGF( SIO_DEBUG,("sio_send: write refused\n") ); } } void sio_send_string( u8_t *str, sio_status_t * siostat ) { /* sio_status_t * siostat = ((siostruct_t*)netif->state)->sio; */ int len = strlen( (const char *)str ); if ( write( siostat->fd, str, len ) <= 0 ) { LWIP_DEBUGF( SIO_DEBUG,("sio_send_string: write refused\n") ); } LWIP_DEBUGF( (PPP_DEBUG | SIO_DEBUG),("sent:%s\n",str ) ); } void sio_flush( sio_status_t * siostat ) { LWIP_UNUSED_ARG(siostat); /* not implemented in unix as it is not needed */ /*sio_status_t * siostat = ((siostruct_t*)netif->state)->sio; */ } #if ! PPP_SUPPORT /*u8_t sio_recv( struct netif * netif )*/ u8_t sio_recv( sio_status_t * siostat ) { /* sio_status_t * siostat = ((siostruct_t*)netif->state)->sio; */ return fifoGet( &(siostat->myfifo) ); } s16_t sio_poll(sio_status_t * siostat) { /* sio_status_t * siostat = ((siostruct_t*)netif->state)->sio;*/ return fifoGetNonBlock( &(siostat->myfifo) ); } void sio_expect_string( u8_t *str, sio_status_t * siostat ) { /* sio_status_t * siostat = ((siostruct_t*)netif->state)->sio;*/ u8_t c; int finger=0; LWIP_DEBUGF( (PPP_DEBUG | SIO_DEBUG), ("expect:%s\n",str) ); while ( 1 ) { c=fifoGet( &(siostat->myfifo) ); LWIP_DEBUGF( (PPP_DEBUG | SIO_DEBUG), ("_%c",c) ); if ( c==str[finger] ) { finger++; } else if ( finger > 0 ) { /*it might fit in the beginning? */ if ( str[0] == c ) { finger = 1; } } if ( 0 == str[finger] ) break; /* done, we have a match */ } LWIP_DEBUGF( (PPP_DEBUG | SIO_DEBUG), ("[match]\n") ); } #endif /* ! PPP_SUPPORT */ #if PPP_SUPPORT u32_t sio_write(sio_status_t * siostat, u8_t *buf, u32_t size) { return write( siostat->fd, buf, size ); } u32_t sio_read(sio_status_t * siostat, u8_t *buf, u32_t size) { return read( siostat->fd, buf, size ); } void sio_read_abort(sio_status_t * siostat) { printf("sio_read_abort: not yet implemented for unix\n"); } #endif /* PPP_SUPPORT */ sio_status_t * sio_open( int devnum ) { char dev[20]; /* would be nice with dynamic memory alloc */ sio_status_t * siostate = &statusar[ devnum ]; /* siostruct_t * tmp; */ /* tmp = (siostruct_t*)(netif->state); */ /* tmp->sio = siostate; */ /* tmp = (siostruct_t*)(netif->state); */ /* ((sio_status_t*)(tmp->sio))->fd = 0; */ #if ! PPP_SUPPORT fifoInit( &siostate->myfifo ); #endif /* ! PPP_SUPPORT */ snprintf( dev, sizeof(dev), "/dev/ttyS%d", devnum ); if ( (devnum == 1) || (devnum == 0) ) { if ( ( siostate->fd = sio_init( dev, devnum, siostate ) ) == 0 ) { LWIP_DEBUGF(SIO_DEBUG, ( "sio_open: ERROR opening serial device\n" )); abort( ); return NULL; } } #if PPP_SUPPORT else if (devnum == 2) { pid_t childpid; childpid = forkpty(&siostate->fd, NULL, NULL, NULL); if(childpid < 0) { perror("forkpty"); exit (1); } if(childpid == 0) { execl("/usr/sbin/pppd", "pppd", "ms-dns", "198.168.100.7", "local", "crtscts", "debug", #ifdef LWIP_PPP_CHAP_TEST "auth", "require-chap", "remotename", "lwip", #else "noauth", #endif "192.168.1.1:192.168.1.2", NULL); perror("execl pppd"); exit (1); } else { LWIP_DEBUGF(SIO_DEBUG, ( "sio_open: spawned pppd pid %d\n", childpid)); } } #endif else { LWIP_DEBUGF(SIO_DEBUG, ( "sio_open: device %s (%d) is not supported\n", dev, devnum )); return NULL; } LWIP_DEBUGF( 1,("sio_open: dev=%s open.\n", dev )); return siostate; } /** * */ void sio_change_baud( sioBaudrates baud, sio_status_t * siostat ) { /* sio_status_t * siostat = ((siostruct_t*)netif->state)->sio;*/ LWIP_DEBUGF( 1,("sio_change_baud\n" )); switch ( baud ) { case SIO_BAUD_9600: sio_speed( siostat->fd, B9600 ); break; case SIO_BAUD_19200: sio_speed( siostat->fd, B19200 ); break; case SIO_BAUD_38400: sio_speed( siostat->fd, B38400 ); break; case SIO_BAUD_57600: sio_speed( siostat->fd, B57600 ); break; case SIO_BAUD_115200: sio_speed( siostat->fd, B115200 ); break; default: LWIP_DEBUGF( 1,("sio_change_baud: Unknown baudrate, code:%d\n", baud )); break; } } ocproxy-1.60/contrib/ports/unix/netif/tapif.c000066400000000000000000000234051303453231400213130ustar00rootroot00000000000000/* * Copyright (c) 2001-2003 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #include "netif/tapif.h" #include #include #include #include #include #include #include #include #include "lwip/debug.h" #include "lwip/opt.h" #include "lwip/def.h" #include "lwip/ip.h" #include "lwip/mem.h" #include "lwip/pbuf.h" #include "lwip/sys.h" #include "netif/etharp.h" #include "lwip/ethip6.h" #if defined(LWIP_DEBUG) && defined(LWIP_TCPDUMP) #include "netif/tcpdump.h" #endif /* LWIP_DEBUG && LWIP_TCPDUMP */ #define IFCONFIG_BIN "/sbin/ifconfig " #if defined(linux) #include #include #include #define DEVTAP "/dev/net/tun" #define IFCONFIG_ARGS "tap0 inet %d.%d.%d.%d" #elif defined(openbsd) #define DEVTAP "/dev/tun0" #define IFCONFIG_ARGS "tun0 inet %d.%d.%d.%d link0" #else /* others */ #define DEVTAP "/dev/tap0" #define IFCONFIG_ARGS "tap0 inet %d.%d.%d.%d" #endif #define IFNAME0 't' #define IFNAME1 'p' #ifndef TAPIF_DEBUG #define TAPIF_DEBUG LWIP_DBG_OFF #endif struct tapif { struct eth_addr *ethaddr; /* Add whatever per-interface state that is needed here. */ int fd; }; /* Forward declarations. */ static void tapif_input(struct netif *netif); static void tapif_thread(void *data); /*-----------------------------------------------------------------------------------*/ static void low_level_init(struct netif *netif) { struct tapif *tapif; char buf[sizeof(IFCONFIG_ARGS) + sizeof(IFCONFIG_BIN) + 50]; tapif = (struct tapif *)netif->state; /* Obtain MAC address from network interface. */ /* (We just fake an address...) */ tapif->ethaddr->addr[0] = 0x1; tapif->ethaddr->addr[1] = 0x2; tapif->ethaddr->addr[2] = 0x3; tapif->ethaddr->addr[3] = 0x4; tapif->ethaddr->addr[4] = 0x5; tapif->ethaddr->addr[5] = 0x6; /* Do whatever else is needed to initialize interface. */ tapif->fd = open(DEVTAP, O_RDWR); LWIP_DEBUGF(TAPIF_DEBUG, ("tapif_init: fd %d\n", tapif->fd)); if(tapif->fd == -1) { #ifdef linux perror("tapif_init: try running \"modprobe tun\" or rebuilding your kernel with CONFIG_TUN; cannot open "DEVTAP); #else perror("tapif_init: cannot open "DEVTAP); #endif exit(1); } #ifdef linux { struct ifreq ifr; memset(&ifr, 0, sizeof(ifr)); ifr.ifr_flags = IFF_TAP|IFF_NO_PI; if (ioctl(tapif->fd, TUNSETIFF, (void *) &ifr) < 0) { perror("tapif_init: "DEVTAP" ioctl TUNSETIFF"); exit(1); } } #endif /* Linux */ sprintf(buf, IFCONFIG_BIN IFCONFIG_ARGS, ip4_addr1(&(netif->gw)), ip4_addr2(&(netif->gw)), ip4_addr3(&(netif->gw)), ip4_addr4(&(netif->gw))); LWIP_DEBUGF(TAPIF_DEBUG, ("tapif_init: system(\"%s\");\n", buf)); system(buf); sys_thread_new("tapif_thread", tapif_thread, netif, DEFAULT_THREAD_STACKSIZE, DEFAULT_THREAD_PRIO); } /*-----------------------------------------------------------------------------------*/ /* * low_level_output(): * * Should do the actual transmission of the packet. The packet is * contained in the pbuf that is passed to the function. This pbuf * might be chained. * */ /*-----------------------------------------------------------------------------------*/ static err_t low_level_output(struct netif *netif, struct pbuf *p) { struct pbuf *q; char buf[1514]; char *bufptr; struct tapif *tapif; tapif = (struct tapif *)netif->state; #if 0 if(((double)rand()/(double)RAND_MAX) < 0.2) { printf("drop output\n"); return ERR_OK; } #endif /* initiate transfer(); */ bufptr = &buf[0]; for(q = p; q != NULL; q = q->next) { /* Send the data from the pbuf to the interface, one pbuf at a time. The size of the data in each pbuf is kept in the ->len variable. */ /* send data from(q->payload, q->len); */ memcpy(bufptr, q->payload, q->len); bufptr += q->len; } /* signal that packet should be sent(); */ if(write(tapif->fd, buf, p->tot_len) == -1) { perror("tapif: write"); } return ERR_OK; } /*-----------------------------------------------------------------------------------*/ /* * low_level_input(): * * Should allocate a pbuf and transfer the bytes of the incoming * packet from the interface into the pbuf. * */ /*-----------------------------------------------------------------------------------*/ static struct pbuf * low_level_input(struct tapif *tapif) { struct pbuf *p, *q; u16_t len; char buf[1514]; char *bufptr; /* Obtain the size of the packet and put it into the "len" variable. */ len = read(tapif->fd, buf, sizeof(buf)); #if 0 if(((double)rand()/(double)RAND_MAX) < 0.2) { printf("drop\n"); return NULL; } #endif /* We allocate a pbuf chain of pbufs from the pool. */ p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL); if(p != NULL) { /* We iterate over the pbuf chain until we have read the entire packet into the pbuf. */ bufptr = &buf[0]; for(q = p; q != NULL; q = q->next) { /* Read enough bytes to fill this pbuf in the chain. The available data in the pbuf is given by the q->len variable. */ /* read data into(q->payload, q->len); */ memcpy(q->payload, bufptr, q->len); bufptr += q->len; } /* acknowledge that packet has been read(); */ } else { /* drop packet(); */ } return p; } /*-----------------------------------------------------------------------------------*/ static void tapif_thread(void *arg) { struct netif *netif; struct tapif *tapif; fd_set fdset; int ret; netif = (struct netif *)arg; tapif = (struct tapif *)netif->state; while(1) { FD_ZERO(&fdset); FD_SET(tapif->fd, &fdset); /* Wait for a packet to arrive. */ ret = select(tapif->fd + 1, &fdset, NULL, NULL, NULL); if(ret == 1) { /* Handle incoming packet. */ tapif_input(netif); } else if(ret == -1) { perror("tapif_thread: select"); } } } /*-----------------------------------------------------------------------------------*/ /* * tapif_input(): * * This function should be called when a packet is ready to be read * from the interface. It uses the function low_level_input() that * should handle the actual reception of bytes from the network * interface. * */ /*-----------------------------------------------------------------------------------*/ static void tapif_input(struct netif *netif) { struct tapif *tapif; struct eth_hdr *ethhdr; struct pbuf *p; tapif = (struct tapif *)netif->state; p = low_level_input(tapif); if(p == NULL) { LWIP_DEBUGF(TAPIF_DEBUG, ("tapif_input: low_level_input returned NULL\n")); return; } ethhdr = (struct eth_hdr *)p->payload; switch(htons(ethhdr->type)) { /* IP or ARP packet? */ case ETHTYPE_IP: case ETHTYPE_ARP: #if LWIP_IPV6 case ETHTYPE_IPV6: #endif /* LWIP_IPV6 */ #if PPPOE_SUPPORT /* PPPoE packet? */ case ETHTYPE_PPPOEDISC: case ETHTYPE_PPPOE: #endif /* PPPOE_SUPPORT */ /* full packet send to tcpip_thread to process */ if (netif->input(p, netif) != ERR_OK) { LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_input: IP input error\n")); pbuf_free(p); p = NULL; } break; default: pbuf_free(p); break; } } /*-----------------------------------------------------------------------------------*/ /* * tapif_init(): * * Should be called at the beginning of the program to set up the * network interface. It calls the function low_level_init() to do the * actual setup of the hardware. * */ /*-----------------------------------------------------------------------------------*/ err_t tapif_init(struct netif *netif) { struct tapif *tapif; tapif = (struct tapif *)mem_malloc(sizeof(struct tapif)); if (!tapif) { return ERR_MEM; } netif->state = tapif; netif->name[0] = IFNAME0; netif->name[1] = IFNAME1; netif->output = etharp_output; #if LWIP_IPV6 netif->output_ip6 = ethip6_output; #endif /* LWIP_IPV6 */ netif->linkoutput = low_level_output; netif->mtu = 1500; /* hardware address length */ netif->hwaddr_len = 6; tapif->ethaddr = (struct eth_addr *)&(netif->hwaddr[0]); netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_IGMP; low_level_init(netif); return ERR_OK; } /*-----------------------------------------------------------------------------------*/ ocproxy-1.60/contrib/ports/unix/netif/tcpdump.c000066400000000000000000000141151303453231400216620ustar00rootroot00000000000000/* * Copyright (c) 2001-2003 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #include #include "netif/tcpdump.h" #include "lwip/ip.h" #include "lwip/tcp_impl.h" #include "lwip/udp.h" #include "lwip/inet.h" #include "lwip/inet_chksum.h" #ifndef TCPDUMP_DEBUG #define TCPDUMP_DEBUG LWIP_DBG_OFF #endif static FILE *file = NULL; /*-----------------------------------------------------------------------------------*/ void tcpdump_init(void) { #define TCPDUMP_FNAME "/tmp/tcpdump" file = fopen(TCPDUMP_FNAME, "w"); if (file == NULL) { perror("tcpdump_init: cannot open \""TCPDUMP_FNAME"\" for writing"); } LWIP_DEBUGF(TCPDUMP_DEBUG, ("tcpdump: file %s\n", TCPDUMP_FNAME)); } /*-----------------------------------------------------------------------------------*/ void tcpdump(struct pbuf *p) { struct ip_hdr *iphdr; struct tcp_hdr *tcphdr; #if LWIP_UDP struct udp_hdr *udphdr; #endif char flags[5]; int i; int len; int offset; if (file == NULL) { return; } #ifdef IPv4 iphdr = (struct ip_hdr *)p->payload; switch (IPH_PROTO(iphdr)) { #if LWIP_TCP case IP_PROTO_TCP: tcphdr = (struct tcp_hdr *)((char *)iphdr + IP_HLEN); pbuf_header(p, -IP_HLEN); if (inet_chksum_pseudo(p, IP_PROTO_TCP, p->tot_len, (ip_addr_t *)&(iphdr->src), (ip_addr_t *)&(iphdr->dest)) != 0) { LWIP_DEBUGF(TCPDUMP_DEBUG, ("tcpdump: IP checksum failed!\n")); /* fprintf(file, "chksum 0x%lx ", tcphdr->chksum); tcphdr->chksum = 0; fprintf(file, "should be 0x%lx ", inet_chksum_pseudo(p, (ip_addr_t *)&(iphdr->src), (ip_addr_t *)&(iphdr->dest), IP_PROTO_TCP, p->tot_len));*/ fprintf(file, "!chksum "); } i = 0; if (TCPH_FLAGS(tcphdr) & TCP_SYN) { flags[i++] = 'S'; } if (TCPH_FLAGS(tcphdr) & TCP_PSH) { flags[i++] = 'P'; } if (TCPH_FLAGS(tcphdr) & TCP_FIN) { flags[i++] = 'F'; } if (TCPH_FLAGS(tcphdr) & TCP_RST) { flags[i++] = 'R'; } if (i == 0) { flags[i++] = '.'; } flags[i++] = 0; fprintf(file, "%d.%d.%d.%d.%u > %d.%d.%d.%d.%u: ", (int)(ntohl(iphdr->src.addr) >> 24) & 0xff, (int)(ntohl(iphdr->src.addr) >> 16) & 0xff, (int)(ntohl(iphdr->src.addr) >> 8) & 0xff, (int)(ntohl(iphdr->src.addr) >> 0) & 0xff, ntohs(tcphdr->src), (int)(ntohl(iphdr->dest.addr) >> 24) & 0xff, (int)(ntohl(iphdr->dest.addr) >> 16) & 0xff, (int)(ntohl(iphdr->dest.addr) >> 8) & 0xff, (int)(ntohl(iphdr->dest.addr) >> 0) & 0xff, ntohs(tcphdr->dest)); offset = TCPH_HDRLEN(tcphdr); len = ntohs(IPH_LEN(iphdr)) - offset * 4 - IP_HLEN; if (len != 0 || flags[0] != '.') { fprintf(file, "%s %u:%u(%u) ", flags, ntohl(tcphdr->seqno), ntohl(tcphdr->seqno) + len, len); } if (TCPH_FLAGS(tcphdr) & TCP_ACK) { fprintf(file, "ack %u ", ntohl(tcphdr->ackno)); } fprintf(file, "wnd %u\n", ntohs(tcphdr->wnd)); fflush(file); pbuf_header(p, IP_HLEN); break; #endif /* LWIP_TCP */ #if LWIP_UDP case IP_PROTO_UDP: udphdr = (struct udp_hdr *)((char *)iphdr + IP_HLEN); pbuf_header(p, -IP_HLEN); if (inet_chksum_pseudo(p, IP_PROTO_UDP, p->tot_len, (ip_addr_t *)&(iphdr->src), (ip_addr_t *)&(iphdr->dest)) != 0) { LWIP_DEBUGF(TCPDUMP_DEBUG, ("tcpdump: IP checksum failed!\n")); /* fprintf(file, "chksum 0x%lx ", tcphdr->chksum); tcphdr->chksum = 0; fprintf(file, "should be 0x%lx ", inet_chksum_pseudo(p, (ip_addr_t *)&(iphdr->src), (ip_addr_t *)&(iphdr->dest), IP_PROTO_TCP, p->tot_len));*/ fprintf(file, "!chksum "); } fprintf(file, "%d.%d.%d.%d.%u > %d.%d.%d.%d.%u: ", (int)(ntohl(iphdr->src.addr) >> 24) & 0xff, (int)(ntohl(iphdr->src.addr) >> 16) & 0xff, (int)(ntohl(iphdr->src.addr) >> 8) & 0xff, (int)(ntohl(iphdr->src.addr) >> 0) & 0xff, ntohs(udphdr->src), (int)(ntohl(iphdr->dest.addr) >> 24) & 0xff, (int)(ntohl(iphdr->dest.addr) >> 16) & 0xff, (int)(ntohl(iphdr->dest.addr) >> 8) & 0xff, (int)(ntohl(iphdr->dest.addr) >> 0) & 0xff, ntohs(udphdr->dest)); fprintf(file, "U "); len = ntohs(IPH_LEN(iphdr)) - sizeof(struct udp_hdr) - IP_HLEN; fprintf(file, " %d\n", len); fflush(file); pbuf_header(p, IP_HLEN); break; #endif /* LWIP_UDP */ default: LWIP_DEBUGF(TCPDUMP_DEBUG, ("unhandled IP protocol: %d\n", (int)IPH_PROTO(iphdr))); break; } #endif /* IPv4 */ } /*-----------------------------------------------------------------------------------*/ ocproxy-1.60/contrib/ports/unix/netif/tunif.c000066400000000000000000000211341303453231400213320ustar00rootroot00000000000000/* * Copyright (c) 2001-2003 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #include "netif/tunif.h" #include #include #include #include #include #include #include #include #include "lwip/debug.h" #include "lwip/opt.h" #include "lwip/def.h" #include "lwip/ip.h" #include "lwip/mem.h" #include "lwip/netif.h" #include "lwip/pbuf.h" #include "lwip/sys.h" #define IFNAME0 't' #define IFNAME1 'n' #ifndef TUNIF_DEBUG #define TUNIF_DEBUG LWIP_DBG_OFF #endif #define IFCONFIG_CALL "/sbin/ifconfig tun0 inet %d.%d.%d.%d %d.%d.%d.%d" struct tunif { /* Add whatever per-interface state that is needed here. */ int fd; }; /* Forward declarations. */ static void tunif_input(struct netif *netif); static err_t tunif_output(struct netif *netif, struct pbuf *p, ip_addr_t *ipaddr); static void tunif_thread(void *data); /*-----------------------------------------------------------------------------------*/ static void low_level_init(struct netif *netif) { struct tunif *tunif; char buf[sizeof(IFCONFIG_CALL) + 50]; tunif = (struct tunif *)netif->state; /* Obtain MAC address from network interface. */ /* Do whatever else is needed to initialize interface. */ tunif->fd = open("/dev/tun0", O_RDWR); LWIP_DEBUGF(TUNIF_DEBUG, ("tunif_init: fd %d\n", tunif->fd)); if (tunif->fd == -1) { perror("tunif_init"); exit(1); } sprintf(buf, IFCONFIG_CALL, ip4_addr1(&(netif->gw)), ip4_addr2(&(netif->gw)), ip4_addr3(&(netif->gw)), ip4_addr4(&(netif->gw)), ip4_addr1(&(netif->ip_addr)), ip4_addr2(&(netif->ip_addr)), ip4_addr3(&(netif->ip_addr)), ip4_addr4(&(netif->ip_addr))); LWIP_DEBUGF(TUNIF_DEBUG, ("tunif_init: system(\"%s\");\n", buf)); system(buf); sys_thread_new("tunif_thread", tunif_thread, netif, DEFAULT_THREAD_STACKSIZE, DEFAULT_THREAD_PRIO); } /*-----------------------------------------------------------------------------------*/ /* * low_level_output(): * * Should do the actual transmission of the packet. The packet is * contained in the pbuf that is passed to the function. This pbuf * might be chained. * */ /*-----------------------------------------------------------------------------------*/ static err_t low_level_output(struct tunif *tunif, struct pbuf *p) { struct pbuf *q; char buf[1500]; char *bufptr; int rnd_val; /* initiate transfer(); */ rnd_val = rand(); if (((double)rnd_val/(double)RAND_MAX) < 0.4) { printf("drop\n"); return ERR_OK; } bufptr = &buf[0]; for(q = p; q != NULL; q = q->next) { /* Send the data from the pbuf to the interface, one pbuf at a time. The size of the data in each pbuf is kept in the ->len variable. */ /* send data from(q->payload, q->len); */ memcpy(bufptr, q->payload, q->len); bufptr += q->len; } /* signal that packet should be sent(); */ if (write(tunif->fd, buf, p->tot_len) == -1) { perror("tunif: write"); } return ERR_OK; } /*-----------------------------------------------------------------------------------*/ /* * low_level_input(): * * Should allocate a pbuf and transfer the bytes of the incoming * packet from the interface into the pbuf. * */ /*-----------------------------------------------------------------------------------*/ static struct pbuf * low_level_input(struct tunif *tunif) { struct pbuf *p, *q; u16_t len; char buf[1500]; char *bufptr; /* Obtain the size of the packet and put it into the "len" variable. */ len = read(tunif->fd, buf, sizeof(buf)); /* if (((double)rand()/(double)RAND_MAX) < 0.1) { printf("drop\n"); return NULL; }*/ /* We allocate a pbuf chain of pbufs from the pool. */ p = pbuf_alloc(PBUF_LINK, len, PBUF_POOL); if (p != NULL) { /* We iterate over the pbuf chain until we have read the entire packet into the pbuf. */ bufptr = &buf[0]; for(q = p; q != NULL; q = q->next) { /* Read enough bytes to fill this pbuf in the chain. The available data in the pbuf is given by the q->len variable. */ /* read data into(q->payload, q->len); */ memcpy(q->payload, bufptr, q->len); bufptr += q->len; } /* acknowledge that packet has been read(); */ } else { /* drop packet(); */ } return p; } /*-----------------------------------------------------------------------------------*/ static void tunif_thread(void *arg) { struct netif *netif; struct tunif *tunif; fd_set fdset; int ret; netif = (struct netif *)arg; tunif = (struct tunif *)netif->state; while (1) { FD_ZERO(&fdset); FD_SET(tunif->fd, &fdset); /* Wait for a packet to arrive. */ ret = select(tunif->fd + 1, &fdset, NULL, NULL, NULL); if (ret == 1) { /* Handle incoming packet. */ tunif_input(netif); } else if (ret == -1) { perror("tunif_thread: select"); } } } /*-----------------------------------------------------------------------------------*/ /* * tunif_output(): * * This function is called by the TCP/IP stack when an IP packet * should be sent. It calls the function called low_level_output() to * do the actuall transmission of the packet. * */ /*-----------------------------------------------------------------------------------*/ static err_t tunif_output(struct netif *netif, struct pbuf *p, ip_addr_t *ipaddr) { struct tunif *tunif; LWIP_UNUSED_ARG(ipaddr); tunif = (struct tunif *)netif->state; return low_level_output(tunif, p); } /*-----------------------------------------------------------------------------------*/ /* * tunif_input(): * * This function should be called when a packet is ready to be read * from the interface. It uses the function low_level_input() that * should handle the actual reception of bytes from the network * interface. * */ /*-----------------------------------------------------------------------------------*/ static void tunif_input(struct netif *netif) { struct tunif *tunif; struct pbuf *p; tunif = (struct tunif *)netif->state; p = low_level_input(tunif); if (p == NULL) { LWIP_DEBUGF(TUNIF_DEBUG, ("tunif_input: low_level_input returned NULL\n")); return; } #if 0 /* CS: ip_lookup() was removed */ if (ip_lookup(p->payload, netif)) { #endif netif->input(p, netif); #if 0 } #endif } /*-----------------------------------------------------------------------------------*/ /* * tunif_init(): * * Should be called at the beginning of the program to set up the * network interface. It calls the function low_level_init() to do the * actual setup of the hardware. * */ /*-----------------------------------------------------------------------------------*/ err_t tunif_init(struct netif *netif) { struct tunif *tunif; tunif = (struct tunif *)mem_malloc(sizeof(struct tunif)); if (!tunif) { return ERR_MEM; } netif->state = tunif; netif->name[0] = IFNAME0; netif->name[1] = IFNAME1; netif->output = tunif_output; low_level_init(netif); return ERR_OK; } /*-----------------------------------------------------------------------------------*/ ocproxy-1.60/contrib/ports/unix/netif/unixif.c000066400000000000000000000316241303453231400215140ustar00rootroot00000000000000/* * Copyright (c) 2001-2003 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #include "lwip/debug.h" #include #include #include #include #include #include #include #include #include /*#include */ /*#include */ #include "lwip/stats.h" #include "lwip/def.h" #include "lwip/mem.h" #include "lwip/pbuf.h" #include "netif/list.h" #include "netif/unixif.h" #include "lwip/sys.h" #include "lwip/timers.h" #include "netif/tcpdump.h" #define UNIXIF_BPS 512000 #define UNIXIF_QUEUELEN 6 /*#define UNIXIF_DROP_FIRST */ #ifndef UNIXIF_DEBUG #define UNIXIF_DEBUG LWIP_DBG_OFF #endif struct unixif_buf { struct pbuf *p; unsigned short len, tot_len; void *payload; }; struct unixif { int fd; sys_sem_t sem; struct list *q; }; /*-----------------------------------------------------------------------------------*/ static int unix_socket_client(const char *name) { int fd; #if !defined(linux) && !defined(cygwin) && !defined(__CYGWIN__) int len; #endif struct sockaddr_un unix_addr; /* create a Unix domain stream socket */ if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { perror("unixif: unix_socket_client: socket"); return(-1); } /* fill socket address structure w/our address */ memset(&unix_addr, 0, sizeof(unix_addr)); unix_addr.sun_family = AF_UNIX; snprintf(unix_addr.sun_path, sizeof(unix_addr.sun_path), "%s%05d", "/var/tmp/", getpid()); #if !defined(linux) && !defined(cygwin) && !defined(__CYGWIN__) len = sizeof(unix_addr.sun_len) + sizeof(unix_addr.sun_family) + strlen(unix_addr.sun_path) + 1; unix_addr.sun_len = len; #endif /* linux */ unlink(unix_addr.sun_path); /* in case it already exists */ if (bind(fd, (struct sockaddr *) &unix_addr, sizeof(struct sockaddr_un)) < 0) { perror("unixif: unix_socket_client: socket"); return(-1); } if (chmod(unix_addr.sun_path, S_IRWXU | S_IRWXO) < 0) { perror("unixif: unix_socket_client: socket"); return(-1); } /* fill socket address structure w/server's addr */ memset(&unix_addr, 0, sizeof(unix_addr)); unix_addr.sun_family = AF_UNIX; strcpy(unix_addr.sun_path, name); #if !defined(linux) && !defined(cygwin) && !defined(__CYGWIN__) len = sizeof(unix_addr.sun_len) + sizeof(unix_addr.sun_family) + strlen(unix_addr.sun_path) + 1; unix_addr.sun_len = len; #endif /* linux */ if (connect(fd, (struct sockaddr *) &unix_addr, sizeof(struct sockaddr_un)) < 0) { perror("unixif: unix_socket_client: socket"); return(-1); } return(fd); } /*-----------------------------------------------------------------------------------*/ static int unix_socket_server(const char *name) { int fd; #if !defined(linux) && !defined(cygwin) && !defined(__CYGWIN__) int len; #endif struct sockaddr_un unix_addr; /* create a Unix domain stream socket */ if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { perror("unixif: unix_socket_server: socket"); return(-1); } unlink(name); /* in case it already exists */ /* fill in socket address structure */ memset(&unix_addr, 0, sizeof(unix_addr)); unix_addr.sun_family = AF_UNIX; strcpy(unix_addr.sun_path, name); #if !defined(linux) && !defined(cygwin) && !defined(__CYGWIN__) len = sizeof(unix_addr.sun_len) + sizeof(unix_addr.sun_family) + strlen(unix_addr.sun_path) + 1; unix_addr.sun_len = len; #endif /* linux */ /* bind the name to the descriptor */ if (bind(fd, (struct sockaddr *) &unix_addr, sizeof(struct sockaddr_un)) < 0) { perror("unixif: unix_socket_server: bind"); return(-1); } if (chmod(unix_addr.sun_path, S_IRWXU | S_IRWXO) < 0) { perror("unixif: unix_socket_server: chmod"); return(-1); } if (listen(fd, 5) < 0) { /* tell kernel we're a server */ perror("unixif: unix_socket_server: listen"); return(-1); } return(fd); } /*-----------------------------------------------------------------------------------*/ static void unixif_input_handler(void *data) { struct netif *netif; struct unixif *unixif; char buf[1532], *bufptr; int len, plen, rlen; struct pbuf *p, *q; netif = (struct netif *)data; unixif = (struct unixif *)netif->state; len = read(unixif->fd, &plen, sizeof(int)); if (len == -1) { perror("unixif_irq_handler: read"); abort(); } LWIP_DEBUGF(UNIXIF_DEBUG, ("unixif_irq_handler: len == %d plen == %d bytes\n", len, plen)); if (len == sizeof(int)) { if (plen < 20 || plen > 1500) { LWIP_DEBUGF(UNIXIF_DEBUG, ("plen %d!\n", plen)); return; } len = read(unixif->fd, buf, plen); if (len == -1) { perror("unixif_irq_handler: read"); abort(); } LWIP_DEBUGF(UNIXIF_DEBUG, ("unixif_irq_handler: read %d bytes\n", len)); p = pbuf_alloc(PBUF_LINK, len, PBUF_POOL); if (p != NULL) { rlen = len; bufptr = buf; q = p; while (rlen > 0) { memcpy(q->payload, bufptr, rlen > q->len? q->len: rlen); rlen -= q->len; bufptr += q->len; q = q->next; } pbuf_realloc(p, len); LINK_STATS_INC(link.recv); tcpdump(p); netif->input(p, netif); } else { LWIP_DEBUGF(UNIXIF_DEBUG, ("unixif_irq_handler: could not allocate pbuf\n")); } } } /*-----------------------------------------------------------------------------------*/ static void unixif_thread(void *arg) { struct netif *netif; struct unixif *unixif; LWIP_DEBUGF(UNIXIF_DEBUG, ("unixif_thread: started.\n")); netif = (struct netif *)arg; unixif = (struct unixif *)netif->state; while (1) { sys_sem_wait(&unixif->sem); unixif_input_handler(netif); } } /*-----------------------------------------------------------------------------------*/ static void unixif_thread2(void *arg) { struct netif *netif; struct unixif *unixif; fd_set fdset; LWIP_DEBUGF(UNIXIF_DEBUG, ("unixif_thread2: started.\n")); netif = (struct netif *)arg; unixif = (struct unixif *)netif->state; while (1) { FD_ZERO(&fdset); FD_SET(unixif->fd, &fdset); if (select(unixif->fd + 1, &fdset, NULL, NULL, NULL) > 0) { sys_sem_signal(&unixif->sem); } } } /*-----------------------------------------------------------------------------------*/ static void unixif_output_timeout(void *arg); static err_t unixif_output(struct netif *netif, struct pbuf *p, ip_addr_t *ipaddr) { struct unixif *unixif; struct unixif_buf *buf; LWIP_UNUSED_ARG(ipaddr); unixif = (struct unixif *)netif->state; buf = (struct unixif_buf *)malloc(sizeof(struct unixif_buf)); buf->p = p; buf->len = p->len; buf->tot_len = p->tot_len; buf->payload = p->payload; if (list_elems(unixif->q) == 0) { pbuf_ref(p); list_push(unixif->q, buf); sys_timeout((double)p->tot_len * 8000.0 / UNIXIF_BPS, unixif_output_timeout, netif); LWIP_DEBUGF(UNIXIF_DEBUG, ("unixif_output: first on list\n")); } else { pbuf_ref(p); if (list_push(unixif->q, buf) == 0) { #ifdef UNIXIF_DROP_FIRST struct unixif_buf *buf2; buf2 = list_pop(unixif->q); pbuf_free(buf2->p); free(buf2); list_push(unixif->q, buf); #else free(buf); pbuf_free(p); LWIP_DEBUGF(UNIXIF_DEBUG, ("unixif_output: drop\n")); #endif /* UNIXIF_DROP_FIRST */ LINK_STATS_INC(link.drop); } else { LWIP_DEBUGF(UNIXIF_DEBUG, ("unixif_output: on list\n")); } } return ERR_OK; } /*-----------------------------------------------------------------------------------*/ static void unixif_output_timeout(void *arg) { struct pbuf *p, *q; int i, j, len; unsigned short plen, ptot_len; struct unixif_buf *buf; void *payload; struct netif *netif; struct unixif *unixif; char *data; netif = (struct netif *)arg; unixif = (struct unixif *)netif->state; LWIP_DEBUGF(UNIXIF_DEBUG, ("unixif_output_timeout\n")); /* buf = unixif->q[0]; unixif->q[0] = unixif->q[1]; unixif->q[1] = NULL;*/ buf = (struct unixif_buf *)list_pop(unixif->q); p = buf->p; plen = p->len; ptot_len = p->tot_len; payload = p->payload; p->len = buf->len; p->tot_len = buf->tot_len; p->payload = buf->payload; if (p->tot_len == 0) { LWIP_DEBUGF(UNIXIF_DEBUG, ("p->len!\n")); abort(); } data = (char *)malloc(p->tot_len); i = 0; for(q = p; q != NULL; q = q->next) { for(j = 0; j < q->len; j++) { data[i] = ((char *)q->payload)[j]; i++; } } LWIP_DEBUGF(UNIXIF_DEBUG, ("unixif_output: sending %d (%d) bytes\n", p->len, p->tot_len)); len = p->tot_len; if (write(unixif->fd, &len, sizeof(int)) == -1) { perror("unixif_output: write"); abort(); } if (write(unixif->fd, data, p->tot_len) == -1) { perror("unixif_output: write"); abort(); } tcpdump(p); LINK_STATS_INC(link.xmit); free(data); free(buf); p->len = plen; p->tot_len = ptot_len; p->payload = payload; pbuf_free(p); /* if (unixif->q[0] != NULL) { sys_timeout(unixif->q[0]->tot_len * 8000 / UNIXIF_BPS, unixif_output_timeout, netif); }*/ if (list_elems(unixif->q) > 0) { sys_timeout(((struct unixif_buf *)list_first(unixif->q))->tot_len * 8000.0 / UNIXIF_BPS, unixif_output_timeout, netif); } } /*-----------------------------------------------------------------------------------*/ err_t unixif_init_server(struct netif *netif) { int fd, fd2; struct sockaddr_un addr; socklen_t len; struct unixif *unixif; fd = unix_socket_server("/tmp/unixif"); if (fd == -1) { perror("unixif_server"); abort(); } LWIP_DEBUGF(UNIXIF_DEBUG, ("unixif_server: fd %d\n", fd)); unixif = (struct unixif *)malloc(sizeof(struct unixif)); if (!unixif) { return ERR_MEM; } netif->state = unixif; netif->name[0] = 'u'; netif->name[1] = 'n'; netif->output = unixif_output; unixif->q = list_new(UNIXIF_QUEUELEN); printf("Now run ./simnode.\n"); len = sizeof(addr); fd2 = accept(fd, (struct sockaddr *)&addr, &len); if (fd2 == -1) { perror("unixif_accept"); abort(); } LWIP_DEBUGF(UNIXIF_DEBUG, ("unixif_accept: %d\n", fd2)); unixif->fd = fd2; if(sys_sem_new(&unixif->sem, 0) != ERR_OK) { LWIP_ASSERT("Failed to create semaphore", 0); } sys_thread_new("unixif_thread", unixif_thread, netif, DEFAULT_THREAD_STACKSIZE, DEFAULT_THREAD_PRIO); sys_thread_new("unixif_thread2", unixif_thread2, netif, DEFAULT_THREAD_STACKSIZE, DEFAULT_THREAD_PRIO); return ERR_OK; } /*-----------------------------------------------------------------------------------*/ err_t unixif_init_client(struct netif *netif) { struct unixif *unixif; unixif = (struct unixif *)malloc(sizeof(struct unixif)); if (!unixif) { return ERR_MEM; } netif->state = unixif; netif->name[0] = 'u'; netif->name[1] = 'n'; netif->output = unixif_output; unixif->fd = unix_socket_client("/tmp/unixif"); if (unixif->fd == -1) { perror("unixif_init"); abort(); } unixif->q = list_new(UNIXIF_QUEUELEN); if(sys_sem_new(&unixif->sem, 0) != ERR_OK) { LWIP_ASSERT("Failed to create semaphore", 0); } sys_thread_new("unixif_thread", unixif_thread, netif, DEFAULT_THREAD_STACKSIZE, DEFAULT_THREAD_PRIO); sys_thread_new("unixif_thread2", unixif_thread2, netif, DEFAULT_THREAD_STACKSIZE, DEFAULT_THREAD_PRIO); return ERR_OK; } /*-----------------------------------------------------------------------------------*/ ocproxy-1.60/contrib/ports/unix/perf.c000066400000000000000000000042071303453231400200360ustar00rootroot00000000000000/* * Copyright (c) 2001-2003 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #include "arch/perf.h" #include static FILE *f; void perf_print(unsigned long c1l, unsigned long c1h, unsigned long c2l, unsigned long c2h, char *key) { unsigned long sub_ms, sub_ls; sub_ms = c2h - c1h; sub_ls = c2l - c1l; if (c2l < c1l) sub_ms--; fprintf(f, "%s: %.8lu%.8lu\n", key, sub_ms, sub_ls); fflush(NULL); } void perf_print_times(struct tms *start, struct tms *end, char *key) { fprintf(f, "%s: %lu\n", key, end->tms_stime - start->tms_stime); fflush(NULL); } void perf_init(char *fname) { f = fopen(fname, "w"); } ocproxy-1.60/contrib/ports/unix/proj/000077500000000000000000000000001303453231400177055ustar00rootroot00000000000000ocproxy-1.60/contrib/ports/unix/proj/lib/000077500000000000000000000000001303453231400204535ustar00rootroot00000000000000ocproxy-1.60/contrib/ports/unix/proj/lib/Makefile000066400000000000000000000104151303453231400221140ustar00rootroot00000000000000# # Copyright (c) 2001, 2002 Swedish Institute of Computer Science. # All rights reserved. # # Redistribution and use in source and binary forms, with or without modification, # are permitted provided that the following conditions are met: # # 1. Redistributions of source code must retain the above copyright notice, # this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright notice, # this list of conditions and the following disclaimer in the documentation # and/or other materials provided with the distribution. # 3. The name of the author may not be used to endorse or promote products # derived from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED # WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT # SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT # OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING # IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY # OF SUCH DAMAGE. # # This file is part of the lwIP TCP/IP stack. # # Author: Adam Dunkels # CONTRIBDIR=../../../.. LWIPARCH=$(CONTRIBDIR)/ports/unix #Set this to where you have the lwip core module checked out from CVS #default assumes it's a dir named lwip at the same level as the contrib module LWIPDIR=$(CONTRIBDIR)/../lwip/src CCDEP=gcc CC=gcc CFLAGS=-g -Wall -DIPv4 -DLWIP_DEBUG -fPIC -pedantic -Werror \ -Wparentheses -Wsequence-point -Wswitch-default \ -Wextra -Wundef -Wshadow -Wpointer-arith -Wbad-function-cast \ -Wc++-compat -Wwrite-strings -Wold-style-definition \ -Wredundant-decls -Wnested-externs -Wno-address CFLAGS:=$(CFLAGS) \ -I$(LWIPDIR)/include -I$(LWIPARCH)/include -I$(LWIPDIR)/include/ipv4 \ -I$(LWIPDIR)/include/ipv6 -I$(LWIPDIR) -I. # COREFILES, CORE4FILES: The minimum set of files needed for lwIP. COREFILES=$(LWIPDIR)/core/def.c $(LWIPDIR)/core/dhcp.c $(LWIPDIR)/core/dns.c \ $(LWIPDIR)/core/inet_chksum.c $(LWIPDIR)/core/init.c $(LWIPDIR)/core/mem.c \ $(LWIPDIR)/core/memp.c $(LWIPDIR)/core/netif.c $(LWIPDIR)/core/pbuf.c \ $(LWIPDIR)/core/raw.c $(LWIPDIR)/core/stats.c $(LWIPDIR)/core/sys.c \ $(LWIPDIR)/core/tcp.c $(LWIPDIR)/core/tcp_in.c $(LWIPDIR)/core/tcp_in.c \ $(LWIPDIR)/core/tcp_out.c $(LWIPDIR)/core/timers.c $(LWIPDIR)/core/udp.c CORE4FILES=$(LWIPDIR)/core/ipv4/autoip.c $(LWIPDIR)/core/ipv4/icmp.c \ $(LWIPDIR)/core/ipv4/igmp.c $(LWIPDIR)/core/ipv4/ip_frag.c \ $(LWIPDIR)/core/ipv4/ip4.c $(LWIPDIR)/core/ipv4/ip4_addr.c CORE6FILES=$(LWIPDIR)/core/ipv6/dhcp6.c $(LWIPDIR)/core/ipv6/ethip6.c \ $(LWIPDIR)/core/ipv6/icmp6.c $(LWIPDIR)/core/ipv6/ip6.c \ $(LWIPDIR)/core/ipv6/ip6_addr.c $(LWIPDIR)/core/ipv6/ip6_frag.c \ $(LWIPDIR)/core/ipv6/mld6.c $(LWIPDIR)/core/ipv6/nd6.c # APIFILES: The files which implement the sequential and socket APIs. APIFILES=$(LWIPDIR)/api/api_lib.c $(LWIPDIR)/api/api_msg.c $(LWIPDIR)/api/err.c \ $(LWIPDIR)/api/netbuf.c $(LWIPDIR)/api/netdb.c $(LWIPDIR)/api/netifapi.c \ $(LWIPDIR)/api/sockets.c $(LWIPDIR)/api/tcpip.c # NETIFFILES: Files implementing various generic network interface functions.' NETIFFILES=$(LWIPDIR)/netif/etharp.c # ARCHFILES: Architecture specific files. ARCHFILES=$(wildcard $(LWIPARCH)/*.c $(LWIPARCH)/netif/tapif.c $(LWIPARCH)/netif/tunif.c $(LWIPARCH)/netif/unixif.c $(LWIPARCH)/netif/list.c $(LWIPARCH)/netif/tcpdump.c) # LWIPFILES: All the above. LWIPFILES=$(COREFILES) $(CORE4FILES) $(CORE6FILES) $(APIFILES) $(NETIFFILES) $(ARCHFILES) LWIPFILESW=$(wildcard $(LWIPFILES)) LWIPOBJS=$(notdir $(LWIPFILESW:.c=.o)) LWIPLIB=liblwip.so %.o: $(CC) $(CFLAGS) -c $(<:.o=.c) all: $(LWIPLIB) .PHONY: all clean: rm -f *.o $(LWIPLIB) *.s .depend* *.core core depend dep: .depend include .depend $(LWIPLIB): $(LWIPOBJS) unixlib.o $(CC) -g -nostartfiles -shared -o $@ $^ .depend: unixlib.c $(LWIPFILES) $(CCDEP) $(CFLAGS) -MM $^ > .depend || rm -f .depend ocproxy-1.60/contrib/ports/unix/proj/lib/README000066400000000000000000000013101303453231400213260ustar00rootroot00000000000000This directory contains an example of how to compile lwIP as a self initialising shared library on Linux. Some brief instructions: * Compile the code: > make clean all This should produce liblwip4unixlib.so. This is the shared library. * Link an application against the shared library If you're using gcc you can do this by including -llwip4unixlib in your link command. * Run your application Ensure that LD_LIBRARY_PATH includes the directory that contains liblwip4unixlib.so (ie. this directory) If you are unsure about shared libraries and libraries on linux in general, you might find this HOWTO useful: Kieran Mansley, October 2002.ocproxy-1.60/contrib/ports/unix/proj/lib/lwipopts.h000066400000000000000000000270371303453231400225160ustar00rootroot00000000000000/** * @file * * lwIP Options Configuration */ /* * Copyright (c) 2001-2004 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #ifndef LWIP_LWIPOPTS_H #define LWIP_LWIPOPTS_H /* * Include user defined options first. Anything not defined in these files * will be set to standard values. Override anything you dont like! */ #include "lwipopts.h" #include "lwip/debug.h" /* ----------------------------------------------- ---------- Platform specific locking ---------- ----------------------------------------------- */ /** * SYS_LIGHTWEIGHT_PROT==1: if you want inter-task protection for certain * critical regions during buffer allocation, deallocation and memory * allocation and deallocation. */ #define SYS_LIGHTWEIGHT_PROT 0 /** * NO_SYS==1: Provides VERY minimal functionality. Otherwise, * use lwIP facilities. */ #define NO_SYS 0 /* ------------------------------------ ---------- Memory options ---------- ------------------------------------ */ /** * MEM_ALIGNMENT: should be set to the alignment of the CPU * 4 byte alignment -> #define MEM_ALIGNMENT 4 * 2 byte alignment -> #define MEM_ALIGNMENT 2 */ #define MEM_ALIGNMENT 1 /** * MEM_SIZE: the size of the heap memory. If the application will send * a lot of data that needs to be copied, this should be set high. */ #define MEM_SIZE 1600 /* ------------------------------------------------ ---------- Internal Memory Pool Sizes ---------- ------------------------------------------------ */ /** * MEMP_NUM_PBUF: the number of memp struct pbufs (used for PBUF_ROM and PBUF_REF). * If the application sends a lot of data out of ROM (or other static memory), * this should be set high. */ #define MEMP_NUM_PBUF 16 /** * MEMP_NUM_RAW_PCB: Number of raw connection PCBs * (requires the LWIP_RAW option) */ #define MEMP_NUM_RAW_PCB 4 /** * MEMP_NUM_UDP_PCB: the number of UDP protocol control blocks. One * per active UDP "connection". * (requires the LWIP_UDP option) */ #define MEMP_NUM_UDP_PCB 4 /** * MEMP_NUM_TCP_PCB: the number of simulatenously active TCP connections. * (requires the LWIP_TCP option) */ #define MEMP_NUM_TCP_PCB 4 /** * MEMP_NUM_TCP_PCB_LISTEN: the number of listening TCP connections. * (requires the LWIP_TCP option) */ #define MEMP_NUM_TCP_PCB_LISTEN 4 /** * MEMP_NUM_TCP_SEG: the number of simultaneously queued TCP segments. * (requires the LWIP_TCP option) */ #define MEMP_NUM_TCP_SEG 16 /** * MEMP_NUM_REASSDATA: the number of simultaneously IP packets queued for * reassembly (whole packets, not fragments!) */ #define MEMP_NUM_REASSDATA 1 /** * MEMP_NUM_ARP_QUEUE: the number of simulateously queued outgoing * packets (pbufs) that are waiting for an ARP request (to resolve * their destination address) to finish. * (requires the ARP_QUEUEING option) */ #define MEMP_NUM_ARP_QUEUE 2 /** * MEMP_NUM_SYS_TIMEOUT: the number of simulateously active timeouts. * (requires NO_SYS==0) */ #define MEMP_NUM_SYS_TIMEOUT 3 /** * MEMP_NUM_NETBUF: the number of struct netbufs. * (only needed if you use the sequential API, like api_lib.c) */ #define MEMP_NUM_NETBUF 2 /** * MEMP_NUM_NETCONN: the number of struct netconns. * (only needed if you use the sequential API, like api_lib.c) */ #define MEMP_NUM_NETCONN 4 /** * MEMP_NUM_TCPIP_MSG_API: the number of struct tcpip_msg, which are used * for callback/timeout API communication. * (only needed if you use tcpip.c) */ #define MEMP_NUM_TCPIP_MSG_API 8 /** * MEMP_NUM_TCPIP_MSG_INPKT: the number of struct tcpip_msg, which are used * for incoming packets. * (only needed if you use tcpip.c) */ #define MEMP_NUM_TCPIP_MSG_INPKT 8 /** * PBUF_POOL_SIZE: the number of buffers in the pbuf pool. */ #define PBUF_POOL_SIZE 8 /* --------------------------------- ---------- ARP options ---------- --------------------------------- */ /** * LWIP_ARP==1: Enable ARP functionality. */ #define LWIP_ARP 1 /* -------------------------------- ---------- IP options ---------- -------------------------------- */ /** * IP_FORWARD==1: Enables the ability to forward IP packets across network * interfaces. If you are going to run lwIP on a device with only one network * interface, define this to 0. */ #define IP_FORWARD 0 /** * IP_OPTIONS: Defines the behavior for IP options. * IP_OPTIONS_ALLOWED==0: All packets with IP options are dropped. * IP_OPTIONS_ALLOWED==1: IP options are allowed (but not parsed). */ #define IP_OPTIONS_ALLOWED 1 /** * IP_REASSEMBLY==1: Reassemble incoming fragmented IP packets. Note that * this option does not affect outgoing packet sizes, which can be controlled * via IP_FRAG. */ #define IP_REASSEMBLY 1 /** * IP_FRAG==1: Fragment outgoing IP packets if their size exceeds MTU. Note * that this option does not affect incoming packet sizes, which can be * controlled via IP_REASSEMBLY. */ #define IP_FRAG 1 /** * IP_REASS_MAXAGE: Maximum time (in multiples of IP_TMR_INTERVAL - so seconds, normally) * a fragmented IP packet waits for all fragments to arrive. If not all fragments arrived * in this time, the whole packet is discarded. */ #define IP_REASS_MAXAGE 3 /** * IP_REASS_MAX_PBUFS: Total maximum amount of pbufs waiting to be reassembled. * Since the received pbufs are enqueued, be sure to configure * PBUF_POOL_SIZE > IP_REASS_MAX_PBUFS so that the stack is still able to receive * packets even if the maximum amount of fragments is enqueued for reassembly! */ #define IP_REASS_MAX_PBUFS 4 /** * IP_FRAG_USES_STATIC_BUF==1: Use a static MTU-sized buffer for IP * fragmentation. Otherwise pbufs are allocated and reference the original * packet data to be fragmented. */ #define IP_FRAG_USES_STATIC_BUF 0 /** * IP_DEFAULT_TTL: Default value for Time-To-Live used by transport layers. */ #define IP_DEFAULT_TTL 255 /* ---------------------------------- ---------- ICMP options ---------- ---------------------------------- */ /** * LWIP_ICMP==1: Enable ICMP module inside the IP stack. * Be careful, disable that make your product non-compliant to RFC1122 */ #define LWIP_ICMP 1 /* --------------------------------- ---------- RAW options ---------- --------------------------------- */ /** * LWIP_RAW==1: Enable application layer to hook into the IP layer itself. */ #define LWIP_RAW 1 /* ---------------------------------- ---------- DHCP options ---------- ---------------------------------- */ /** * LWIP_DHCP==1: Enable DHCP module. */ #define LWIP_DHCP 0 /* ------------------------------------ ---------- AUTOIP options ---------- ------------------------------------ */ /** * LWIP_AUTOIP==1: Enable AUTOIP module. */ #define LWIP_AUTOIP 0 /* ---------------------------------- ---------- SNMP options ---------- ---------------------------------- */ /** * LWIP_SNMP==1: Turn on SNMP module. UDP must be available for SNMP * transport. */ #define LWIP_SNMP 0 /* ---------------------------------- ---------- IGMP options ---------- ---------------------------------- */ /** * LWIP_IGMP==1: Turn on IGMP module. */ #define LWIP_IGMP 0 /* ---------------------------------- ---------- DNS options ----------- ---------------------------------- */ /** * LWIP_DNS==1: Turn on DNS module. UDP must be available for DNS * transport. */ #define LWIP_DNS 0 /* --------------------------------- ---------- UDP options ---------- --------------------------------- */ /** * LWIP_UDP==1: Turn on UDP. */ #define LWIP_UDP 1 /* --------------------------------- ---------- TCP options ---------- --------------------------------- */ /** * LWIP_TCP==1: Turn on TCP. */ #define LWIP_TCP 1 #define LWIP_LISTEN_BACKLOG 0 /* ---------------------------------- ---------- Pbuf options ---------- ---------------------------------- */ /** * PBUF_LINK_HLEN: the number of bytes that should be allocated for a * link level header. The default is 14, the standard value for * Ethernet. */ #define PBUF_LINK_HLEN 16 /** * PBUF_POOL_BUFSIZE: the size of each pbuf in the pbuf pool. The default is * designed to accomodate single full size TCP frame in one pbuf, including * TCP_MSS, IP header, and link header. * */ #define PBUF_POOL_BUFSIZE LWIP_MEM_ALIGN_SIZE(TCP_MSS+40+PBUF_LINK_HLEN) /* ------------------------------------ ---------- LOOPIF options ---------- ------------------------------------ */ /** * LWIP_HAVE_LOOPIF==1: Support loop interface (127.0.0.1) and loopif.c */ #define LWIP_HAVE_LOOPIF 0 /* ---------------------------------------------- ---------- Sequential layer options ---------- ---------------------------------------------- */ /** * LWIP_NETCONN==1: Enable Netconn API (require to use api_lib.c) */ #define LWIP_NETCONN 1 /* ------------------------------------ ---------- Socket options ---------- ------------------------------------ */ /** * LWIP_SOCKET==1: Enable Socket API (require to use sockets.c) */ #define LWIP_SOCKET 1 /* ---------------------------------------- ---------- Statistics options ---------- ---------------------------------------- */ /** * LWIP_STATS==1: Enable statistics collection in lwip_stats. */ #define LWIP_STATS 0 /* --------------------------------- ---------- PPP options ---------- --------------------------------- */ /** * PPP_SUPPORT==1: Enable PPP. */ #define PPP_SUPPORT 0 /* Misc */ #endif /* LWIP_LWIPOPTS_H */ ocproxy-1.60/contrib/ports/unix/proj/lib/unixlib.c000066400000000000000000000061541303453231400222770ustar00rootroot00000000000000/* * Copyright (c) 2001-2003 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * Author: Kieran Mansley * * $Id: unixlib.c,v 1.10 2010/02/17 16:52:30 goldsimon Exp $ */ /*-----------------------------------------------------------------------------------*/ /* unixlib.c * * The initialisation functions for a shared library * * You may need to configure this file to your own needs - it is only an example * of how lwIP can be used as a self initialising shared library. * * In particular, you should change the gateway, ipaddr, and netmask to be the values * you would like the stack to use. */ /*-----------------------------------------------------------------------------------*/ #include "lwip/init.h" #include "lwip/sys.h" #include "lwip/mem.h" #include "lwip/memp.h" #include "lwip/pbuf.h" #include "lwip/tcp.h" #include "lwip/tcpip.h" #include "lwip/netif.h" #include "lwip/stats.h" #include "lwip/sockets.h" #include "netif/tapif.h" struct netif netif; static void tcpip_init_done(void *arg) { ip_addr_t ipaddr, netmask, gateway; sys_sem_t *sem; sem = (sys_sem_t *)arg; /* CHANGE THESE to suit your own network configuration: */ IP4_ADDR(&gateway, 192,168,1,1); IP4_ADDR(&ipaddr, 192,168,1,2); IP4_ADDR(&netmask, 255,255,255,0); netif_set_default(netif_add(&netif, &ipaddr, &netmask, &gateway, NULL, tapif_init, tcpip_input)); #if LWIP_IPV6 netif_create_ip6_linklocal_address(&netif, 1); #endif sys_sem_signal(sem); } void _init(void){ sys_sem_t sem; if(sys_sem_new(&sem, 0) != ERR_OK) { LWIP_ASSERT("failed to create semaphore", 0); } tcpip_init(tcpip_init_done, &sem); sys_sem_wait(&sem); sys_sem_free(&sem); } void _fini(void){ } ocproxy-1.60/contrib/ports/unix/proj/minimal/000077500000000000000000000000001303453231400213335ustar00rootroot00000000000000ocproxy-1.60/contrib/ports/unix/proj/minimal/Makefile000066400000000000000000000112711303453231400227750ustar00rootroot00000000000000# # Copyright (c) 2001, 2002 Swedish Institute of Computer Science. # All rights reserved. # # Redistribution and use in source and binary forms, with or without modification, # are permitted provided that the following conditions are met: # # 1. Redistributions of source code must retain the above copyright notice, # this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright notice, # this list of conditions and the following disclaimer in the documentation # and/or other materials provided with the distribution. # 3. The name of the author may not be used to endorse or promote products # derived from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED # WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT # SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT # OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING # IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY # OF SUCH DAMAGE. # # This file is part of the lwIP TCP/IP stack. # # Author: Adam Dunkels # CCDEP=gcc CC=gcc #To compile for linux: make ARCH=linux #To compile for cygwin: make ARCH=cygwin #To compile for openbsd: make ARCH=openbsd ARCH=openbsd CFLAGS=-g -Wall -D$(ARCH) -DIPv4 -Os -DLWIP_DEBUG -pedantic -Werror \ -Wparentheses -Wsequence-point -Wswitch-default \ -Wextra -Wundef -Wshadow -Wpointer-arith -Wbad-function-cast \ -Wc++-compat -Wwrite-strings -Wold-style-definition \ -Wmissing-prototypes -Wredundant-decls -Wnested-externs -Wno-address ARFLAGS=rs CONTRIBDIR=../../../.. LWIPARCH=$(CONTRIBDIR)/ports/unix #Set this to where you have the lwip core module checked out from CVS #default assumes it's a dir named lwip at the same level as the contrib module LWIPDIR=$(CONTRIBDIR)/../lwip/src CFLAGS:=$(CFLAGS) \ -I$(LWIPDIR)/include -I$(LWIPARCH)/include -I$(LWIPDIR)/include/ipv4 \ -I$(LWIPDIR)/include/ipv6 -I. -I$(CONTRIBDIR)/apps/snmp_private_mib \ -I$(CONTRIBDIR)/apps/tcpecho_raw # COREFILES, CORE4FILES: The minimum set of files needed for lwIP. COREFILES=$(LWIPDIR)/core/def.c $(LWIPDIR)/core/dhcp.c $(LWIPDIR)/core/dns.c \ $(LWIPDIR)/core/inet_chksum.c $(LWIPDIR)/core/init.c $(LWIPDIR)/core/mem.c \ $(LWIPDIR)/core/memp.c $(LWIPDIR)/core/netif.c $(LWIPDIR)/core/pbuf.c \ $(LWIPDIR)/core/raw.c $(LWIPDIR)/core/stats.c $(LWIPDIR)/core/sys.c \ $(LWIPDIR)/core/tcp.c $(LWIPDIR)/core/tcp_in.c $(LWIPDIR)/core/tcp_in.c \ $(LWIPDIR)/core/tcp_out.c $(LWIPDIR)/core/timers.c $(LWIPDIR)/core/udp.c CORE4FILES=$(LWIPDIR)/core/ipv4/autoip.c $(LWIPDIR)/core/ipv4/icmp.c \ $(LWIPDIR)/core/ipv4/igmp.c $(LWIPDIR)/core/ipv4/ip_frag.c \ $(LWIPDIR)/core/ipv4/ip4.c $(LWIPDIR)/core/ipv4/ip4_addr.c CORE6FILES=$(LWIPDIR)/core/ipv6/dhcp6.c $(LWIPDIR)/core/ipv6/ethip6.c \ $(LWIPDIR)/core/ipv6/icmp6.c $(LWIPDIR)/core/ipv6/ip6.c \ $(LWIPDIR)/core/ipv6/ip6_addr.c $(LWIPDIR)/core/ipv6/ip6_frag.c \ $(LWIPDIR)/core/ipv6/mld6.c $(LWIPDIR)/core/ipv6/nd6.c # SNMPFILES: Extra SNMPv1 agent SNMPFILES=$(LWIPDIR)/core/snmp/asn1_dec.c $(LWIPDIR)/core/snmp/asn1_enc.c \ $(LWIPDIR)/core/snmp/mib2.c $(LWIPDIR)/core/snmp/mib_structs.c \ $(LWIPDIR)/core/snmp/msg_in.c $(LWIPDIR)/core/snmp/msg_out.c \ ../../../../apps/snmp_private_mib/lwip_prvmib.c # NETIFFILES: Files implementing various generic network interface functions.' NETIFFILES=$(LWIPDIR)/netif/etharp.c mintapif.c # ARCHFILES: Architecture specific files ARCHFILES=$(LWIPARCH)/sys_arch.c # LWIPFILES: All the above. LWIPFILES=$(COREFILES) $(CORE4FILES) $(CORE6FILES) $(SNMPFILES) $(NETIFFILES) $(ARCHFILES) LWIPFILESW=$(wildcard $(LWIPFILES)) LWIPOBJS=$(notdir $(LWIPFILESW:.c=.o)) # APPFILES APPFILES=../../../../apps/tcpecho_raw/echo.c timer.c LWIPLIB=liblwip4.a APPLIB=liblwipapps.a APPOBJS=$(notdir $(APPFILES:.c=.o)) %.o: $(CC) $(CFLAGS) -c $(<:.o=.c) all ipv4 compile: echop .PHONY: all clean: rm -f *.o $(LWIPLIB) $(APPLIB) echop .depend* *.core core depend dep: .depend include .depend $(APPLIB): $(APPOBJS) $(AR) $(ARFLAGS) $(APPLIB) $? $(LWIPLIB): $(LWIPOBJS) $(AR) $(ARFLAGS) $(LWIPLIB) $? .depend: main.c $(LWIPFILES) $(APPFILES) $(CCDEP) $(CFLAGS) -MM $^ > .depend || rm -f .depend echop: .depend $(LWIPLIB) $(APPLIB) main.o $(APPFILES) $(CC) $(CFLAGS) $(LDFLAGS) -o echop main.o $(APPLIB) $(LWIPLIB) ocproxy-1.60/contrib/ports/unix/proj/minimal/README000066400000000000000000000004201303453231400222070ustar00rootroot00000000000000This is an example of a very minimal lwIP project. It runs in a single thread and runs a single example application - an echo server. The echo application is implemented using the raw API. Additionally this raw API example hosts the SNMPv1 agent for development purposes. ocproxy-1.60/contrib/ports/unix/proj/minimal/lwipopts.h000066400000000000000000000254451303453231400233770ustar00rootroot00000000000000/** * @file * * lwIP Options Configuration */ /* * Copyright (c) 2001-2004 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #ifndef LWIP_LWIPOPTS_H #define LWIP_LWIPOPTS_H /* ----------------------------------------------- ---------- Platform specific locking ---------- ----------------------------------------------- */ /** * NO_SYS==1: Provides VERY minimal functionality. Otherwise, * use lwIP facilities. */ #define NO_SYS 1 /* ------------------------------------ ---------- Memory options ---------- ------------------------------------ */ /** * MEM_ALIGNMENT: should be set to the alignment of the CPU * 4 byte alignment -> #define MEM_ALIGNMENT 4 * 2 byte alignment -> #define MEM_ALIGNMENT 2 */ #define MEM_ALIGNMENT 1 /** * MEM_SIZE: the size of the heap memory. If the application will send * a lot of data that needs to be copied, this should be set high. */ #define MEM_SIZE 16000 /* ------------------------------------------------ ---------- Internal Memory Pool Sizes ---------- ------------------------------------------------ */ /** * MEMP_NUM_PBUF: the number of memp struct pbufs (used for PBUF_ROM and PBUF_REF). * If the application sends a lot of data out of ROM (or other static memory), * this should be set high. */ #define MEMP_NUM_PBUF 30 /** * MEMP_NUM_RAW_PCB: Number of raw connection PCBs * (requires the LWIP_RAW option) */ #define MEMP_NUM_RAW_PCB 4 /** * MEMP_NUM_UDP_PCB: the number of UDP protocol control blocks. One * per active UDP "connection". * (requires the LWIP_UDP option) */ #define MEMP_NUM_UDP_PCB 4 /** * MEMP_NUM_TCP_PCB: the number of simulatenously active TCP connections. * (requires the LWIP_TCP option) */ #define MEMP_NUM_TCP_PCB 2 /** * MEMP_NUM_TCP_PCB_LISTEN: the number of listening TCP connections. * (requires the LWIP_TCP option) */ #define MEMP_NUM_TCP_PCB_LISTEN 8 /** * MEMP_NUM_TCP_SEG: the number of simultaneously queued TCP segments. * (requires the LWIP_TCP option) */ #define MEMP_NUM_TCP_SEG 16 /** * MEMP_NUM_ARP_QUEUE: the number of simulateously queued outgoing * packets (pbufs) that are waiting for an ARP request (to resolve * their destination address) to finish. * (requires the ARP_QUEUEING option) */ #define MEMP_NUM_ARP_QUEUE 2 /** * MEMP_NUM_SYS_TIMEOUT: the number of simulateously active timeouts. */ #define MEMP_NUM_SYS_TIMEOUT 3 /** * MEMP_NUM_NETBUF: the number of struct netbufs. * (only needed if you use the sequential API, like api_lib.c) */ #define MEMP_NUM_NETBUF 0 /** * MEMP_NUM_NETCONN: the number of struct netconns. * (only needed if you use the sequential API, like api_lib.c) */ #define MEMP_NUM_NETCONN 0 /** * MEMP_NUM_TCPIP_MSG_API: the number of struct tcpip_msg, which are used * for callback/timeout API communication. * (only needed if you use tcpip.c) */ #define MEMP_NUM_TCPIP_MSG_API 0 /** * MEMP_NUM_TCPIP_MSG_INPKT: the number of struct tcpip_msg, which are used * for incoming packets. * (only needed if you use tcpip.c) */ #define MEMP_NUM_TCPIP_MSG_INPKT 0 /** * PBUF_POOL_SIZE: the number of buffers in the pbuf pool. */ #define PBUF_POOL_SIZE 32 /* --------------------------------- ---------- ARP options ---------- --------------------------------- */ /** * LWIP_ARP==1: Enable ARP functionality. */ #define LWIP_ARP 1 /* -------------------------------- ---------- IP options ---------- -------------------------------- */ /** * IP_FORWARD==1: Enables the ability to forward IP packets across network * interfaces. If you are going to run lwIP on a device with only one network * interface, define this to 0. */ #define IP_FORWARD 0 /** * IP_OPTIONS: Defines the behavior for IP options. * IP_OPTIONS==0_ALLOWED: All packets with IP options are dropped. * IP_OPTIONS==1_ALLOWED: IP options are allowed (but not parsed). */ #define IP_OPTIONS_ALLOWED 1 /** * IP_REASSEMBLY==1: Reassemble incoming fragmented IP packets. Note that * this option does not affect outgoing packet sizes, which can be controlled * via IP_FRAG. */ #define IP_REASSEMBLY 1 /** * IP_FRAG==1: Fragment outgoing IP packets if their size exceeds MTU. Note * that this option does not affect incoming packet sizes, which can be * controlled via IP_REASSEMBLY. */ #define IP_FRAG 1 /** * IP_REASS_MAXAGE: Maximum time (in multiples of IP_TMR_INTERVAL - so seconds, normally) * a fragmented IP packet waits for all fragments to arrive. If not all fragments arrived * in this time, the whole packet is discarded. */ #define IP_REASS_MAXAGE 3 /** * IP_REASS_MAX_PBUFS: Total maximum amount of pbufs waiting to be reassembled. * Since the received pbufs are enqueued, be sure to configure * PBUF_POOL_SIZE > IP_REASS_MAX_PBUFS so that the stack is still able to receive * packets even if the maximum amount of fragments is enqueued for reassembly! */ #define IP_REASS_MAX_PBUFS 10 /** * IP_FRAG_USES_STATIC_BUF==1: Use a static MTU-sized buffer for IP * fragmentation. Otherwise pbufs are allocated and reference the original * packet data to be fragmented. */ #define IP_FRAG_USES_STATIC_BUF 0 /** * IP_DEFAULT_TTL: Default value for Time-To-Live used by transport layers. */ #define IP_DEFAULT_TTL 255 /* ---------------------------------- ---------- ICMP options ---------- ---------------------------------- */ /** * LWIP_ICMP==1: Enable ICMP module inside the IP stack. * Be careful, disable that make your product non-compliant to RFC1122 */ #define LWIP_ICMP 1 /** * ICMP_TTL: Default value for Time-To-Live used by ICMP packets. */ #define ICMP_TTL (IP_DEFAULT_TTL) /* --------------------------------- ---------- RAW options ---------- --------------------------------- */ /** * LWIP_RAW==1: Enable application layer to hook into the IP layer itself. */ #define LWIP_RAW 0 /* ---------------------------------- ---------- DHCP options ---------- ---------------------------------- */ /** * LWIP_DHCP==1: Enable DHCP module. */ #define LWIP_DHCP 0 /* ------------------------------------ ---------- AUTOIP options ---------- ------------------------------------ */ /** * LWIP_AUTOIP==1: Enable AUTOIP module. */ #define LWIP_AUTOIP 0 /* ---------------------------------- ---------- SNMP options ---------- ---------------------------------- */ /** * LWIP_SNMP==1: Turn on SNMP module. UDP must be available for SNMP * transport. */ #define LWIP_SNMP 1 #define SNMP_PRIVATE_MIB 1 /* ---------------------------------- ---------- IGMP options ---------- ---------------------------------- */ /** * LWIP_IGMP==1: Turn on IGMP module. */ #define LWIP_IGMP 0 /* ---------------------------------- ---------- DNS options ----------- ---------------------------------- */ /** * LWIP_DNS==1: Turn on DNS module. UDP must be available for DNS * transport. */ #define LWIP_DNS 0 /* --------------------------------- ---------- UDP options ---------- --------------------------------- */ /** * LWIP_UDP==1: Turn on UDP. */ #define LWIP_UDP 1 /** * LWIP_UDPLITE==1: Turn on UDP-Lite. (Requires LWIP_UDP) */ #define LWIP_UDPLITE 0 /** * UDP_TTL: Default Time-To-Live value. */ #define UDP_TTL (IP_DEFAULT_TTL) /* --------------------------------- ---------- TCP options ---------- --------------------------------- */ /** * LWIP_TCP==1: Turn on TCP. */ #define LWIP_TCP 1 /* ---------------------------------- ---------- Pbuf options ---------- ---------------------------------- */ /** * PBUF_LINK_HLEN: the number of bytes that should be allocated for a * link level header. The default is 14, the standard value for * Ethernet. */ #define PBUF_LINK_HLEN 16 /* ------------------------------------ ---------- LOOPIF options ---------- ------------------------------------ */ /** * LWIP_HAVE_LOOPIF==1: Support loop interface (127.0.0.1) and loopif.c */ #define LWIP_HAVE_LOOPIF 0 /* ---------------------------------------------- ---------- Sequential layer options ---------- ---------------------------------------------- */ /** * LWIP_NETCONN==1: Enable Netconn API (require to use api_lib.c) */ #define LWIP_NETCONN 0 /* ------------------------------------ ---------- Socket options ---------- ------------------------------------ */ /** * LWIP_SOCKET==1: Enable Socket API (require to use sockets.c) */ #define LWIP_SOCKET 0 /* ---------------------------------------- ---------- Statistics options ---------- ---------------------------------------- */ /** * LWIP_STATS==1: Enable statistics collection in lwip_stats. */ #define LWIP_STATS 0 /* Misc */ #endif /* LWIP_LWIPOPTS_H */ ocproxy-1.60/contrib/ports/unix/proj/minimal/main.c000066400000000000000000000155451303453231400224350ustar00rootroot00000000000000/* * Copyright (c) 2001-2003 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * RT timer modifications by Christiaan Simons */ #include #include #include "lwip/init.h" #include "lwip/debug.h" #include "lwip/mem.h" #include "lwip/memp.h" #include "lwip/sys.h" #include "lwip/stats.h" #include "lwip/ip.h" #include "lwip/ip_frag.h" #include "lwip/udp.h" #include "lwip/snmp_msg.h" #include "lwip/tcp_impl.h" #include "mintapif.h" #include "netif/etharp.h" #include "timer.h" #include #include "echo.h" #include "private_mib.h" /* (manual) host IP configuration */ static ip_addr_t ipaddr, netmask, gw; /* SNMP trap destination cmd option */ static unsigned char trap_flag; static ip_addr_t trap_addr; /* nonstatic debug cmd option, exported in lwipopts.h */ unsigned char debug_flags; /* 'non-volatile' SNMP settings @todo: make these truly non-volatile */ u8_t syscontact_str[255]; u8_t syscontact_len = 0; u8_t syslocation_str[255]; u8_t syslocation_len = 0; /* enable == 1, disable == 2 */ u8_t snmpauthentraps_set = 2; static struct option longopts[] = { /* turn on debugging output (if build with LWIP_DEBUG) */ {"debug", no_argument, NULL, 'd'}, /* help */ {"help", no_argument, NULL, 'h'}, /* gateway address */ {"gateway", required_argument, NULL, 'g'}, /* ip address */ {"ipaddr", required_argument, NULL, 'i'}, /* netmask */ {"netmask", required_argument, NULL, 'm'}, /* ping destination */ {"trap_destination", required_argument, NULL, 't'}, /* new command line options go here! */ {NULL, 0, NULL, 0} }; #define NUM_OPTS ((sizeof(longopts) / sizeof(struct option)) - 1) static void usage(void) { unsigned char i; printf("options:\n"); for (i = 0; i < NUM_OPTS; i++) { printf("-%c --%s\n",longopts[i].val, longopts[i].name); } } int main(int argc, char **argv) { struct netif netif; sigset_t mask, oldmask, empty; int ch; char ip_str[16] = {0}, nm_str[16] = {0}, gw_str[16] = {0}; /* startup defaults (may be overridden by one or more opts) */ IP4_ADDR(&gw, 192,168,0,1); IP4_ADDR(&ipaddr, 192,168,0,2); IP4_ADDR(&netmask, 255,255,255,0); trap_flag = 0; /* use debug flags defined by debug.h */ debug_flags = LWIP_DBG_OFF; while ((ch = getopt_long(argc, argv, "dhg:i:m:t:", longopts, NULL)) != -1) { switch (ch) { case 'd': debug_flags |= (LWIP_DBG_ON|LWIP_DBG_TRACE|LWIP_DBG_STATE|LWIP_DBG_FRESH|LWIP_DBG_HALT); break; case 'h': usage(); exit(0); break; case 'g': ipaddr_aton(optarg, &gw); break; case 'i': ipaddr_aton(optarg, &ipaddr); break; case 'm': ipaddr_aton(optarg, &netmask); break; case 't': trap_flag = !0; /* @todo: remove this authentraps tweak when we have proper SET & non-volatile mem */ snmpauthentraps_set = 1; ipaddr_aton(optarg, &trap_addr); strncpy(ip_str, ipaddr_ntoa(&trap_addr),sizeof(ip_str)); printf("SNMP trap destination %s\n", ip_str); break; default: usage(); break; } } argc -= optind; argv += optind; strncpy(ip_str, ipaddr_ntoa(&ipaddr), sizeof(ip_str)); strncpy(nm_str, ipaddr_ntoa(&netmask), sizeof(nm_str)); strncpy(gw_str, ipaddr_ntoa(&gw), sizeof(gw_str)); printf("Host at %s mask %s gateway %s\n", ip_str, nm_str, gw_str); #ifdef PERF perf_init("/tmp/minimal.perf"); #endif /* PERF */ lwip_init(); printf("TCP/IP initialized.\n"); netif_add(&netif, &ipaddr, &netmask, &gw, NULL, mintapif_init, ethernet_input); netif_set_default(&netif); netif_set_up(&netif); #if LWIP_IPV6 netif_create_ip6_linklocal_address(&netif, 1); #endif #if SNMP_PRIVATE_MIB != 0 /* initialize our private example MIB */ lwip_privmib_init(); #endif snmp_trap_dst_ip_set(0,&trap_addr); snmp_trap_dst_enable(0,trap_flag); snmp_set_syscontact(syscontact_str,&syscontact_len); snmp_set_syslocation(syslocation_str,&syslocation_len); snmp_set_snmpenableauthentraps(&snmpauthentraps_set); snmp_init(); echo_init(); timer_init(); timer_set_interval(TIMER_EVT_ETHARPTMR, ARP_TMR_INTERVAL / 10); timer_set_interval(TIMER_EVT_TCPTMR, TCP_TMR_INTERVAL / 10); #if IP_REASSEMBLY timer_set_interval(TIMER_EVT_IPREASSTMR, IP_TMR_INTERVAL / 10); #endif printf("Applications started.\n"); while (1) { /* poll for input packet and ensure select() or read() arn't interrupted */ sigemptyset(&mask); sigaddset(&mask, SIGALRM); sigprocmask(SIG_BLOCK, &mask, &oldmask); /* start of critical section, poll netif, pass packet to lwIP */ if (mintapif_select(&netif) > 0) { /* work, immediatly end critical section hoping lwIP ended quickly ... */ sigprocmask(SIG_SETMASK, &oldmask, NULL); } else { /* no work, wait a little (10 msec) for SIGALRM */ sigemptyset(&empty); sigsuspend(&empty); /* ... end critical section */ sigprocmask(SIG_SETMASK, &oldmask, NULL); } if(timer_testclr_evt(TIMER_EVT_TCPTMR)) { tcp_tmr(); } #if IP_REASSEMBLY if(timer_testclr_evt(TIMER_EVT_IPREASSTMR)) { ip_reass_tmr(); } #endif if(timer_testclr_evt(TIMER_EVT_ETHARPTMR)) { etharp_tmr(); } } return 0; } ocproxy-1.60/contrib/ports/unix/proj/minimal/mintapif.c000066400000000000000000000242171303453231400233140ustar00rootroot00000000000000/*-----------------------------------------------------------------------------------*/ /* * Copyright (c) 2001-2003 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #include #include #include #include #include #include #include #include #include #include #include #if defined(linux) #include #include #include #define DEVTAP "/dev/net/tun" #define IFCONFIG_ARGS "tap0 inet %d.%d.%d.%d" #elif defined(openbsd) #define DEVTAP "/dev/tun0" #define IFCONFIG_ARGS "tun0 inet %d.%d.%d.%d link0" #else /* freebsd, cygwin? */ #define DEVTAP "/dev/tap0" #define IFCONFIG_ARGS "tap0 inet %d.%d.%d.%d" #endif #include "lwip/stats.h" #include "lwip/snmp.h" #include "lwip/mem.h" #include "netif/etharp.h" #include "mintapif.h" /* Define those to better describe your network interface. */ #define IFNAME0 'e' #define IFNAME1 't' struct mintapif { struct eth_addr *ethaddr; /* Add whatever per-interface state that is needed here. */ u32_t lasttime; int fd; }; /* Forward declarations. */ static void mintapif_input(struct netif *netif); /*-----------------------------------------------------------------------------------*/ static void low_level_init(struct netif *netif) { struct mintapif *mintapif; char buf[1024]; int ret; mintapif = (struct mintapif *)netif->state; /* Obtain MAC address from network interface. */ mintapif->ethaddr->addr[0] = 1; mintapif->ethaddr->addr[1] = 2; mintapif->ethaddr->addr[2] = 3; mintapif->ethaddr->addr[3] = 4; mintapif->ethaddr->addr[4] = 5; mintapif->ethaddr->addr[5] = 6; /* device capabilities */ /* don't set NETIF_FLAG_ETHARP if this device is not an ethernet one */ netif->flags |= NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP; /* Do whatever else is needed to initialize interface. */ mintapif->fd = open(DEVTAP, O_RDWR); if (mintapif->fd == -1) { perror("tapif: tapif_init: open"); exit(1); } #ifdef linux { struct ifreq ifr; memset(&ifr, 0, sizeof(ifr)); ifr.ifr_flags = IFF_TAP|IFF_NO_PI; if (ioctl(mintapif->fd, TUNSETIFF, (void *) &ifr) < 0) { perror(buf); exit(1); } } #endif /* Linux */ snprintf(buf, sizeof(buf), "/sbin/ifconfig " IFCONFIG_ARGS, ip4_addr1(&(netif->gw)), ip4_addr2(&(netif->gw)), ip4_addr3(&(netif->gw)), ip4_addr4(&(netif->gw))); ret = system(buf); if (ret < 0) { perror("ifconfig failed"); exit(1); } if (ret != 0) { printf("ifconfig returned %d\n", ret); } mintapif->lasttime = 0; } /*-----------------------------------------------------------------------------------*/ /* * low_level_output(): * * Should do the actual transmission of the packet. The packet is * contained in the pbuf that is passed to the function. This pbuf * might be chained. * */ /*-----------------------------------------------------------------------------------*/ static err_t low_level_output(struct netif *netif, struct pbuf *p) { struct mintapif *mintapif; struct pbuf *q; char buf[1514]; char *bufptr; int written; mintapif = (struct mintapif *)netif->state; /* initiate transfer(); */ bufptr = &buf[0]; for(q = p; q != NULL; q = q->next) { /* Send the data from the pbuf to the interface, one pbuf at a time. The size of the data in each pbuf is kept in the ->len variable. */ /* send data from(q->payload, q->len); */ memcpy(bufptr, q->payload, q->len); bufptr += q->len; } /* signal that packet should be sent(); */ written = write(mintapif->fd, buf, p->tot_len); if (written == -1) { snmp_inc_ifoutdiscards(netif); perror("tapif: write"); } else { snmp_add_ifoutoctets(netif, written); } return ERR_OK; } /*-----------------------------------------------------------------------------------*/ /* * low_level_input(): * * Should allocate a pbuf and transfer the bytes of the incoming * packet from the interface into the pbuf. * */ /*-----------------------------------------------------------------------------------*/ static struct pbuf * low_level_input(struct netif *netif) { struct pbuf *p, *q; u16_t len; char buf[1514]; char *bufptr; struct mintapif *mintapif; mintapif = (struct mintapif *)netif->state; /* Obtain the size of the packet and put it into the "len" variable. */ len = read(mintapif->fd, buf, sizeof(buf)); snmp_add_ifinoctets(netif,len); /* if (((double)rand()/(double)RAND_MAX) < 0.1) { printf("drop\n"); return NULL; }*/ /* We allocate a pbuf chain of pbufs from the pool. */ p = pbuf_alloc(PBUF_LINK, len, PBUF_POOL); if (p != NULL) { /* We iterate over the pbuf chain until we have read the entire packet into the pbuf. */ bufptr = &buf[0]; for(q = p; q != NULL; q = q->next) { /* Read enough bytes to fill this pbuf in the chain. The available data in the pbuf is given by the q->len variable. */ /* read data into(q->payload, q->len); */ memcpy(q->payload, bufptr, q->len); bufptr += q->len; } /* acknowledge that packet has been read(); */ } else { /* drop packet(); */ snmp_inc_ifindiscards(netif); printf("Could not allocate pbufs\n"); } return p; } /*-----------------------------------------------------------------------------------*/ /* * mintapif_input(): * * This function should be called when a packet is ready to be read * from the interface. It uses the function low_level_input() that * should handle the actual reception of bytes from the network * interface. * */ /*-----------------------------------------------------------------------------------*/ static void mintapif_input(struct netif *netif) { struct pbuf *p; p = low_level_input(netif); if (p != NULL) { #if LINK_STATS lwip_stats.link.recv++; #endif /* LINK_STATS */ netif->input(p, netif); } } /*-----------------------------------------------------------------------------------*/ /* * mintapif_init(): * * Should be called at the beginning of the program to set up the * network interface. It calls the function low_level_init() to do the * actual setup of the hardware. * */ /*-----------------------------------------------------------------------------------*/ err_t mintapif_init(struct netif *netif) { struct mintapif *mintapif; mintapif = (struct mintapif *)mem_malloc(sizeof(struct mintapif)); if (mintapif == NULL) { LWIP_DEBUGF(NETIF_DEBUG, ("cs8900_init: out of memory for mintapif\n")); return ERR_MEM; } netif->state = mintapif; #if LWIP_SNMP /* ifType is other(1), there doesn't seem to be a proper type for the tunnel if */ netif->link_type = 1; /* @todo get this from struct tunif? */ netif->link_speed = 0; netif->ts = 0; netif->ifinoctets = 0; netif->ifinucastpkts = 0; netif->ifinnucastpkts = 0; netif->ifindiscards = 0; netif->ifoutoctets = 0; netif->ifoutucastpkts = 0; netif->ifoutnucastpkts = 0; netif->ifoutdiscards = 0; #endif netif->hwaddr_len = 6; netif->name[0] = IFNAME0; netif->name[1] = IFNAME1; netif->output = etharp_output; netif->linkoutput = low_level_output; netif->mtu = 1500; mintapif->ethaddr = (struct eth_addr *)&(netif->hwaddr[0]); low_level_init(netif); return ERR_OK; } /*-----------------------------------------------------------------------------------*/ enum mintapif_signal mintapif_wait(struct netif *netif, u16_t time) { fd_set fdset; struct timeval tv, now; struct timezone tz; int ret; struct mintapif *mintapif; mintapif = (struct mintapif *)netif->state; while (1) { if (mintapif->lasttime >= (u32_t)time * 1000) { mintapif->lasttime = 0; return MINTAPIF_TIMEOUT; } tv.tv_sec = 0; tv.tv_usec = (u32_t)time * 1000 - mintapif->lasttime; FD_ZERO(&fdset); FD_SET(mintapif->fd, &fdset); gettimeofday(&now, &tz); ret = select(mintapif->fd + 1, &fdset, NULL, NULL, &tv); if (ret == 0) { mintapif->lasttime = 0; return MINTAPIF_TIMEOUT; } gettimeofday(&tv, &tz); mintapif->lasttime += (tv.tv_sec - now.tv_sec) * 1000000 + (tv.tv_usec - now.tv_usec); mintapif_input(netif); } return MINTAPIF_PACKET; } int mintapif_select(struct netif *netif) { fd_set fdset; int ret; struct timeval tv; struct mintapif *mintapif; mintapif = (struct mintapif *)netif->state; tv.tv_sec = 0; tv.tv_usec = 0; /* usec_to; */ FD_ZERO(&fdset); FD_SET(mintapif->fd, &fdset); ret = select(mintapif->fd + 1, &fdset, NULL, NULL, &tv); if (ret > 0) { mintapif_input(netif); } return ret; } ocproxy-1.60/contrib/ports/unix/proj/minimal/mintapif.h000066400000000000000000000036121303453231400233150ustar00rootroot00000000000000/* * Copyright (c) 2001-2003 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #ifndef LWIP_MINTAPIF_H #define LWIP_MINTAPIF_H #include "lwip/netif.h" enum mintapif_signal { MINTAPIF_TIMEOUT, MINTAPIF_PACKET }; err_t mintapif_init(struct netif *netif); int mintapif_select(struct netif *netif); enum mintapif_signal mintapif_wait(struct netif *netif, u16_t time); #endif /* LWIP_MINTAPIF_H */ ocproxy-1.60/contrib/ports/unix/proj/minimal/timer.c000066400000000000000000000071631303453231400226260ustar00rootroot00000000000000/* * Copyright (c) 2006 Christiaan Simons. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of and a contribution to the lwIP TCP/IP stack. * * Author: Christiaan Simons */ /** * @file * Simple pre-allocated interval (reload) timers. * @see timer.h */ #include #include #include #include "timer.h" #include "lwip/snmp.h" static struct itimerval tmr; struct itmr { volatile unsigned int interval; volatile unsigned int cnt; volatile unsigned char event; }; static struct itmr timers[TIMER_NUM]; void sigalarm_handler(int sig); /** * Initializes interval timers. */ void timer_init(void) { unsigned char i; struct itmr *tp; tp = &timers[TIMER_NUM-1]; for(i = TIMER_NUM; i > 0; i--) { tp->event = 0; tp->interval = 0; tp->cnt = 0; tp--; } signal(SIGALRM,sigalarm_handler); /* timer reload is in 10msec steps */ tmr.it_interval.tv_sec = 0; tmr.it_interval.tv_usec = 10000; /* set to half period (enables timer) */ tmr.it_value.tv_sec = 0; tmr.it_value.tv_usec = 5000; setitimer(ITIMER_REAL,&tmr,NULL); } /** * Configures timer. * * @param tmr the timer number from timer.h * @param interval when > 0 enables this timer, 0 disables. */ void timer_set_interval(unsigned char tmr_num, unsigned int interval) { if (tmr_num < TIMER_NUM) { timers[tmr_num].interval = interval; } } /** * Returns timer event and restarts timer. */ unsigned char timer_testclr_evt(unsigned char tmr_num) { if (tmr_num < TIMER_NUM) { unsigned char evt; struct itmr *tp; tp = &timers[tmr_num]; evt = tp->event; if (tp->event != 0) { tp->event = 0; tp->cnt = tp->interval; } return evt; } else { return 0; } } /** * interrupting (!) sigalarm handler */ void sigalarm_handler(int sig) { unsigned char i; struct itmr *tp; LWIP_UNUSED_ARG(sig); snmp_inc_sysuptime(); tp = &timers[TIMER_NUM-1]; for(i = TIMER_NUM; i > 0; i--) { if (tp->interval != 0) { /* timer is running */ if (tp->cnt == 0) { /* timer expired */ tp->event |= 1; } else { /* timer ticking */ tp->cnt--; } } tp--; } } ocproxy-1.60/contrib/ports/unix/proj/minimal/timer.h000066400000000000000000000004601303453231400226240ustar00rootroot00000000000000#ifndef LWIP_TIMER_H_ #define LWIP_TIMER_H_ #define TIMER_EVT_ETHARPTMR 0 #define TIMER_EVT_TCPTMR 1 #define TIMER_EVT_IPREASSTMR 2 #define TIMER_NUM 3 void timer_init(void); void timer_set_interval(unsigned char tmr, unsigned int interval); unsigned char timer_testclr_evt(unsigned char tmr); #endif ocproxy-1.60/contrib/ports/unix/proj/unixsim/000077500000000000000000000000001303453231400214015ustar00rootroot00000000000000ocproxy-1.60/contrib/ports/unix/proj/unixsim/Makefile000066400000000000000000000140701303453231400230430ustar00rootroot00000000000000# # Copyright (c) 2001, 2002 Swedish Institute of Computer Science. # All rights reserved. # # Redistribution and use in source and binary forms, with or without modification, # are permitted provided that the following conditions are met: # # 1. Redistributions of source code must retain the above copyright notice, # this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright notice, # this list of conditions and the following disclaimer in the documentation # and/or other materials provided with the distribution. # 3. The name of the author may not be used to endorse or promote products # derived from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED # WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT # SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT # OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING # IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY # OF SUCH DAMAGE. # # This file is part of the lwIP TCP/IP stack. # # Author: Adam Dunkels # CCDEP=gcc CC=gcc #To compile for linux: make ARCH=linux #To compile for cygwin: make ARCH=cygwin ARCH=unix CFLAGS=-g -Wall -D$(ARCH) -DIPv4 -DLWIP_DEBUG -pedantic -Werror \ -Wparentheses -Wsequence-point -Wswitch-default \ -Wextra -Wundef -Wshadow -Wpointer-arith -Wbad-function-cast \ -Wc++-compat -Wwrite-strings -Wold-style-definition \ -Wmissing-prototypes -Wredundant-decls -Wnested-externs -Wno-address # not used for now but interesting: # -Wpacked # -Wunreachable-code # -ansi # -std=c89 LDFLAGS=-pthread -lutil CONTRIBDIR=../../../.. LWIPARCH=$(CONTRIBDIR)/ports/unix ARFLAGS=rs #Set this to where you have the lwip core module checked out from CVS #default assumes it's a dir named lwip at the same level as the contrib module LWIPDIR=$(CONTRIBDIR)/../lwip/src CFLAGS:=$(CFLAGS) \ -I. -I$(CONTRIBDIR)/apps/httpserver_raw -I$(CONTRIBDIR)/apps/shell \ -I$(CONTRIBDIR)/apps/tcpecho -I$(CONTRIBDIR)/apps/udpecho \ -I$(LWIPDIR)/include -I$(LWIPARCH)/include -I$(LWIPDIR)/include/ipv4 \ -I$(LWIPDIR)/include/ipv6 -I$(LWIPDIR) # COREFILES, CORE4FILES: The minimum set of files needed for lwIP. COREFILES=$(LWIPDIR)/core/def.c $(LWIPDIR)/core/dhcp.c $(LWIPDIR)/core/dns.c \ $(LWIPDIR)/core/inet_chksum.c $(LWIPDIR)/core/init.c $(LWIPDIR)/core/mem.c \ $(LWIPDIR)/core/memp.c $(LWIPDIR)/core/netif.c $(LWIPDIR)/core/pbuf.c \ $(LWIPDIR)/core/raw.c $(LWIPDIR)/core/stats.c $(LWIPDIR)/core/sys.c \ $(LWIPDIR)/core/tcp.c $(LWIPDIR)/core/tcp_in.c $(LWIPDIR)/core/tcp_in.c \ $(LWIPDIR)/core/tcp_out.c $(LWIPDIR)/core/timers.c $(LWIPDIR)/core/udp.c CORE4FILES=$(LWIPDIR)/core/ipv4/autoip.c $(LWIPDIR)/core/ipv4/icmp.c \ $(LWIPDIR)/core/ipv4/igmp.c $(LWIPDIR)/core/ipv4/ip_frag.c \ $(LWIPDIR)/core/ipv4/ip4.c $(LWIPDIR)/core/ipv4/ip4_addr.c CORE6FILES=$(LWIPDIR)/core/ipv6/dhcp6.c $(LWIPDIR)/core/ipv6/ethip6.c \ $(LWIPDIR)/core/ipv6/icmp6.c $(LWIPDIR)/core/ipv6/ip6.c \ $(LWIPDIR)/core/ipv6/ip6_addr.c $(LWIPDIR)/core/ipv6/ip6_frag.c \ $(LWIPDIR)/core/ipv6/mld6.c $(LWIPDIR)/core/ipv6/nd6.c # SNMPFILES: Extra SNMPv1 agent SNMPFILES=$(LWIPDIR)/core/snmp/asn1_dec.c $(LWIPDIR)/core/snmp/asn1_enc.c \ $(LWIPDIR)/core/snmp/mib2.c $(LWIPDIR)/core/snmp/mib_structs.c \ $(LWIPDIR)/core/snmp/msg_in.c $(LWIPDIR)/core/snmp/msg_out.c # APIFILES: The files which implement the sequential and socket APIs. APIFILES=$(LWIPDIR)/api/api_lib.c $(LWIPDIR)/api/api_msg.c $(LWIPDIR)/api/err.c \ $(LWIPDIR)/api/netbuf.c $(LWIPDIR)/api/netdb.c $(LWIPDIR)/api/netifapi.c \ $(LWIPDIR)/api/sockets.c $(LWIPDIR)/api/tcpip.c # NETIFFILES: Files implementing various generic network interface functions.' NETIFFILES=$(LWIPDIR)/netif/etharp.c $(LWIPDIR)/netif/slipif.c # NETIFFILES: Add PPP netif NETIFFILES+=$(LWIPDIR)/netif/ppp/auth.c $(LWIPDIR)/netif/ppp/chap.c \ $(LWIPDIR)/netif/ppp/chpms.c $(LWIPDIR)/netif/ppp/fsm.c \ $(LWIPDIR)/netif/ppp/ipcp.c $(LWIPDIR)/netif/ppp/lcp.c \ $(LWIPDIR)/netif/ppp/magic.c $(LWIPDIR)/netif/ppp/md5.c \ $(LWIPDIR)/netif/ppp/pap.c $(LWIPDIR)/netif/ppp/ppp.c \ $(LWIPDIR)/netif/ppp/randm.c $(LWIPDIR)/netif/ppp/vj.c \ $(LWIPARCH)/netif/sio.c # ARCHFILES: Architecture specific files. ARCHFILES=$(wildcard $(LWIPARCH)/*.c $(LWIPARCH)/netif/tapif.c $(LWIPARCH)/netif/tunif.c $(LWIPARCH)/netif/unixif.c $(LWIPARCH)/netif/list.c $(LWIPARCH)/netif/tcpdump.c) # APPFILES: Applications. APPFILES=$(CONTRIBDIR)/apps/httpserver_raw/fs.c $(CONTRIBDIR)/apps/httpserver_raw/httpd.c \ $(CONTRIBDIR)/apps/udpecho/udpecho.c $(CONTRIBDIR)/apps/tcpecho/tcpecho.c \ $(CONTRIBDIR)/apps/shell/shell.c # LWIPFILES: All the above. LWIPFILES=$(COREFILES) $(CORE4FILES) $(CORE6FILES) $(SNMPFILES) $(APIFILES) $(NETIFFILES) $(ARCHFILES) LWIPFILESW=$(wildcard $(LWIPFILES)) LWIPOBJS=$(notdir $(LWIPFILESW:.c=.o)) LWIPLIB=liblwip4.a APPLIB=liblwipapps.a APPOBJS=$(notdir $(APPFILES:.c=.o)) %.o: $(CC) $(CFLAGS) -c $(<:.o=.c) all ipv4 compile: simhost .PHONY: all clean: rm -f *.o $(LWIPLIB) $(APPLIB) simhost simnode simrouter *.s .depend* *.core core depend dep: .depend include .depend $(APPLIB): $(APPOBJS) $(AR) $(ARFLAGS) $(APPLIB) $? $(LWIPLIB): $(LWIPOBJS) $(AR) $(ARFLAGS) $(LWIPLIB) $? .depend: simhost.c simnode.c simrouter.c $(LWIPFILES) $(APPFILES) $(CCDEP) $(CFLAGS) -MM $^ > .depend || rm -f .depend simhost: .depend $(LWIPLIB) $(APPLIB) simhost.o $(APPFILES) $(CC) $(CFLAGS) $(LDFLAGS) -o simhost simhost.o $(APPLIB) $(LWIPLIB) simrouter: .depend $(LWIPLIB) $(APPLIB) simrouter.o $(CC) $(CFLAGS) $(LDFLAGS) -o simrouter simrouter.o $(APPLIB) $(LWIPLIB) simnode: .depend $(LWIPLIB) $(APPLIB) simnode.o $(CC) $(CFLAGS) $(LDFLAGS) -o simnode simnode.o $(APPLIB) $(LWIPLIB) ocproxy-1.60/contrib/ports/unix/proj/unixsim/README000066400000000000000000000035471303453231400222720ustar00rootroot00000000000000This directory contains an example of how a project using lwIP might look. It is also the development platform of lwIP, since it can be run as a user process under FreeBSD or Linux. There are also a number of example applications (including a simple web server) in the apps/ directory. Some short instructions on how to build and run lwIP on a FreeBSD or Linux host. For FreeBSD, the tap interface must be enabled in the kernel configuration and the kernel must be recompiled. The tap interface is enabled by adding the line "pseudo-device tap" in the kernel configuration. See Chapter 9 in the FreeBSD handbook for instructions on how to build a custom FreeBSD kernel. For Linux you might need to create a device node with > mknod /dev/net/tun c 10 200 * Compile the code. This must be done by using GNU Make. Under FreeBSD, GNU Make can be found in the ports collection under /usr/ports/devel/gmake (type "make install distclean" to install). Under Linux, GNU Make is the default "make". > gmake (FreeBSD) > make (Linux) * The compilation process produces the executable file "simhost". To run this, you have to be root. > su (Type password for the root account) # ./simhost * The lwIP TCP/IP stack is now running with IP address 192.168.0.2. Some things that you can try: To see the packets that are going to and from the lwIP stack, run tcpdump: # tcpdump -l -n -i tap0 You can ping lwIP: > ping 192.168.0.2 For a telnet shell, run: > telnet 192.168.0.2 Finally, "simhost" also includes a simple web server; the URL is of course http://192.168.0.2/. * Simhost has some extra features that can be selected with command line options. To enable runtime debug output (project must be build with -DLWIP_DEBUG): # ./simhost -d To ping any host, e.g. the gateway: # ./simhost -p 192.168.0.1 ocproxy-1.60/contrib/ports/unix/proj/unixsim/lwipopts.h000066400000000000000000000255441303453231400234450ustar00rootroot00000000000000/* * Copyright (c) 2001-2003 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #ifndef LWIP_LWIPOPTS_H #define LWIP_LWIPOPTS_H #define LWIP_DBG_MIN_LEVEL 0 #define LWIP_COMPAT_SOCKETS 1 #define TAPIF_DEBUG LWIP_DBG_ON #define TUNIF_DEBUG LWIP_DBG_OFF #define UNIXIF_DEBUG LWIP_DBG_OFF #define DELIF_DEBUG LWIP_DBG_OFF #define SIO_FIFO_DEBUG LWIP_DBG_OFF #define TCPDUMP_DEBUG LWIP_DBG_ON #define PPP_DEBUG LWIP_DBG_OFF #define MEM_DEBUG LWIP_DBG_OFF #define MEMP_DEBUG LWIP_DBG_OFF #define PBUF_DEBUG LWIP_DBG_OFF #define API_LIB_DEBUG LWIP_DBG_ON #define API_MSG_DEBUG LWIP_DBG_ON #define TCPIP_DEBUG LWIP_DBG_ON #define NETIF_DEBUG LWIP_DBG_ON #define SOCKETS_DEBUG LWIP_DBG_ON #define DEMO_DEBUG LWIP_DBG_ON #define IP_DEBUG LWIP_DBG_ON #define IP_REASS_DEBUG LWIP_DBG_ON #define RAW_DEBUG LWIP_DBG_ON #define ICMP_DEBUG LWIP_DBG_ON #define UDP_DEBUG LWIP_DBG_ON #define TCP_DEBUG LWIP_DBG_ON #define TCP_INPUT_DEBUG LWIP_DBG_ON #define TCP_OUTPUT_DEBUG LWIP_DBG_ON #define TCP_RTO_DEBUG LWIP_DBG_ON #define TCP_CWND_DEBUG LWIP_DBG_ON #define TCP_WND_DEBUG LWIP_DBG_ON #define TCP_FR_DEBUG LWIP_DBG_ON #define TCP_QLEN_DEBUG LWIP_DBG_ON #define TCP_RST_DEBUG LWIP_DBG_ON extern unsigned char debug_flags; #define LWIP_DBG_TYPES_ON debug_flags #define NO_SYS 0 #define LWIP_SOCKET (NO_SYS==0) #define LWIP_NETCONN (NO_SYS==0) /* ---------- Memory options ---------- */ /* MEM_ALIGNMENT: should be set to the alignment of the CPU for which lwIP is compiled. 4 byte alignment -> define MEM_ALIGNMENT to 4, 2 byte alignment -> define MEM_ALIGNMENT to 2. */ /* MSVC port: intel processors don't need 4-byte alignment, but are faster that way! */ #define MEM_ALIGNMENT 4 /* MEM_SIZE: the size of the heap memory. If the application will send a lot of data that needs to be copied, this should be set high. */ #define MEM_SIZE 10240 /* MEMP_NUM_PBUF: the number of memp struct pbufs. If the application sends a lot of data out of ROM (or other static memory), this should be set high. */ #define MEMP_NUM_PBUF 16 /* MEMP_NUM_RAW_PCB: the number of UDP protocol control blocks. One per active RAW "connection". */ #define MEMP_NUM_RAW_PCB 3 /* MEMP_NUM_UDP_PCB: the number of UDP protocol control blocks. One per active UDP "connection". */ #define MEMP_NUM_UDP_PCB 4 /* MEMP_NUM_TCP_PCB: the number of simulatenously active TCP connections. */ #define MEMP_NUM_TCP_PCB 5 /* MEMP_NUM_TCP_PCB_LISTEN: the number of listening TCP connections. */ #define MEMP_NUM_TCP_PCB_LISTEN 8 /* MEMP_NUM_TCP_SEG: the number of simultaneously queued TCP segments. */ #define MEMP_NUM_TCP_SEG 16 /* MEMP_NUM_SYS_TIMEOUT: the number of simulateously active timeouts. */ #define MEMP_NUM_SYS_TIMEOUT 3 /* The following four are used only with the sequential API and can be set to 0 if the application only will use the raw API. */ /* MEMP_NUM_NETBUF: the number of struct netbufs. */ #define MEMP_NUM_NETBUF 2 /* MEMP_NUM_NETCONN: the number of struct netconns. */ #define MEMP_NUM_NETCONN 10 /* MEMP_NUM_TCPIP_MSG_*: the number of struct tcpip_msg, which is used for sequential API communication and incoming packets. Used in src/api/tcpip.c. */ #define MEMP_NUM_TCPIP_MSG_API 16 #define MEMP_NUM_TCPIP_MSG_INPKT 16 /* ---------- Pbuf options ---------- */ /* PBUF_POOL_SIZE: the number of buffers in the pbuf pool. */ #define PBUF_POOL_SIZE 120 /* PBUF_POOL_BUFSIZE: the size of each pbuf in the pbuf pool. */ #define PBUF_POOL_BUFSIZE 128 /* PBUF_LINK_HLEN: the number of bytes that should be allocated for a link level header. */ #define PBUF_LINK_HLEN 16 /** SYS_LIGHTWEIGHT_PROT * define SYS_LIGHTWEIGHT_PROT in lwipopts.h if you want inter-task protection * for certain critical regions during buffer allocation, deallocation and memory * allocation and deallocation. */ #define SYS_LIGHTWEIGHT_PROT 1 /* ---------- TCP options ---------- */ #define LWIP_TCP 1 #define TCP_TTL 255 /* Controls if TCP should queue segments that arrive out of order. Define to 0 if your device is low on memory. */ #define TCP_QUEUE_OOSEQ 1 /* TCP Maximum segment size. */ #define TCP_MSS 1024 /* TCP sender buffer space (bytes). */ #define TCP_SND_BUF 2048 /* TCP sender buffer space (pbufs). This must be at least = 2 * TCP_SND_BUF/TCP_MSS for things to work. */ #define TCP_SND_QUEUELEN (4 * TCP_SND_BUF/TCP_MSS) /* TCP writable space (bytes). This must be less than or equal to TCP_SND_BUF. It is the amount of space which must be available in the tcp snd_buf for select to return writable */ #define TCP_SNDLOWAT (TCP_SND_BUF/2) /* TCP receive window. */ #define TCP_WND 8096 /* Maximum number of retransmissions of data segments. */ #define TCP_MAXRTX 12 /* Maximum number of retransmissions of SYN segments. */ #define TCP_SYNMAXRTX 4 /* ---------- ARP options ---------- */ #define LWIP_ARP 1 #define ARP_TABLE_SIZE 10 #define ARP_QUEUEING 1 /* ---------- IP options ---------- */ /* Define IP_FORWARD to 1 if you wish to have the ability to forward IP packets across network interfaces. If you are going to run lwIP on a device with only one network interface, define this to 0. */ #define IP_FORWARD 1 /* IP reassembly and segmentation.These are orthogonal even * if they both deal with IP fragments */ #define IP_REASSEMBLY 1 #define IP_REASS_MAX_PBUFS 10 #define MEMP_NUM_REASSDATA 10 #define IP_FRAG 1 /* ---------- ICMP options ---------- */ #define ICMP_TTL 255 /* ---------- DHCP options ---------- */ /* Define LWIP_DHCP to 1 if you want DHCP configuration of interfaces. */ #define LWIP_DHCP 0 /* 1 if you want to do an ARP check on the offered address (recommended if using DHCP). */ #define DHCP_DOES_ARP_CHECK (LWIP_DHCP) /* ---------- AUTOIP options ------- */ #define LWIP_AUTOIP 0 /* ---------- SNMP options ---------- */ /** @todo SNMP is experimental for now @note UDP must be available for SNMP transport */ #ifndef LWIP_SNMP #define LWIP_SNMP 0 #endif #ifndef SNMP_PRIVATE_MIB #define SNMP_PRIVATE_MIB 0 #endif /* ---------- UDP options ---------- */ #define LWIP_UDP 1 #define UDP_TTL 255 /* ---------- RAW options ---------- */ #define LWIP_RAW 1 #define RAW_TTL 255 /* ---------- Statistics options ---------- */ /* individual STATS options can be turned off by defining them to 0 * (e.g #define TCP_STATS 0). All of them are turned off if LWIP_STATS * is 0 * */ #define LWIP_STATS 1 /* ---------- PPP options ---------- */ #define PPP_SUPPORT 0 /* Set > 0 for PPP */ #if PPP_SUPPORT > 0 #define NUM_PPP 1 /* Max PPP sessions. */ /* Select modules to enable. Ideally these would be set in the makefile but * we're limited by the command line length so you need to modify the settings * in this file. */ #define PAP_SUPPORT 1 /* Set > 0 for PAP. */ #define CHAP_SUPPORT 1 /* Set > 0 for CHAP. */ #define MSCHAP_SUPPORT 0 /* Set > 0 for MSCHAP (NOT FUNCTIONAL!) */ #define CBCP_SUPPORT 0 /* Set > 0 for CBCP (NOT FUNCTIONAL!) */ #define CCP_SUPPORT 0 /* Set > 0 for CCP (NOT FUNCTIONAL!) */ #define VJ_SUPPORT 1 /* Set > 0 for VJ header compression. */ #define MD5_SUPPORT 1 /* Set > 0 for MD5 (see also CHAP) */ /* * Timeouts. */ #define FSM_DEFTIMEOUT 6 /* Timeout time in seconds */ #define FSM_DEFMAXTERMREQS 2 /* Maximum Terminate-Request transmissions */ #define FSM_DEFMAXCONFREQS 10 /* Maximum Configure-Request transmissions */ #define FSM_DEFMAXNAKLOOPS 5 /* Maximum number of nak loops */ #define UPAP_DEFTIMEOUT 6 /* Timeout (seconds) for retransmitting req */ #define UPAP_DEFREQTIME 30 /* Time to wait for auth-req from peer */ #define CHAP_DEFTIMEOUT 6 /* Timeout time in seconds */ #define CHAP_DEFTRANSMITS 10 /* max # times to send challenge */ /* Interval in seconds between keepalive echo requests, 0 to disable. */ #if 1 #define LCP_ECHOINTERVAL 0 #else #define LCP_ECHOINTERVAL 10 #endif /* Number of unanswered echo requests before failure. */ #define LCP_MAXECHOFAILS 3 /* Max Xmit idle time (in jiffies) before resend flag char. */ #define PPP_MAXIDLEFLAG 100 /* * Packet sizes * * Note - lcp shouldn't be allowed to negotiate stuff outside these * limits. See lcp.h in the pppd directory. * (XXX - these constants should simply be shared by lcp.c instead * of living in lcp.h) */ #define PPP_MTU 1500 /* Default MTU (size of Info field) */ #if 0 #define PPP_MAXMTU 65535 - (PPP_HDRLEN + PPP_FCSLEN) #else #define PPP_MAXMTU 1500 /* Largest MTU we allow */ #endif #define PPP_MINMTU 64 #define PPP_MRU 1500 /* default MRU = max length of info field */ #define PPP_MAXMRU 1500 /* Largest MRU we allow */ #define PPP_DEFMRU 296 /* Try for this */ #define PPP_MINMRU 128 /* No MRUs below this */ #define MAXNAMELEN 256 /* max length of hostname or name for auth */ #define MAXSECRETLEN 256 /* max length of password or secret */ #endif /* PPP_SUPPORT > 0 */ #endif /* LWIP_LWIPOPTS_H */ ocproxy-1.60/contrib/ports/unix/proj/unixsim/simhost.c000066400000000000000000000273741303453231400232500ustar00rootroot00000000000000/* * Copyright (c) 2001-2003 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #include #include #include #include "lwip/opt.h" #include "lwip/init.h" #include "lwip/mem.h" #include "lwip/memp.h" #include "lwip/sys.h" #include "lwip/stats.h" #include "lwip/tcp_impl.h" #include "lwip/inet_chksum.h" #include "lwip/tcpip.h" #include "lwip/sockets.h" #include "netif/tapif.h" #include "netif/tunif.h" #include "netif/unixif.h" #include "netif/dropif.h" #include "netif/pcapif.h" #include "netif/tcpdump.h" #if PPP_SUPPORT #include "netif/ppp/ppp.h" #define PPP_PTY_TEST 1 #include #endif #include "lwip/ip_addr.h" #include "arch/perf.h" #include "httpd.h" #include "udpecho.h" #include "tcpecho.h" #include "shell.h" #if LWIP_RAW #include "lwip/icmp.h" #include "lwip/raw.h" #endif /* (manual) host IP configuration */ static ip_addr_t ipaddr, netmask, gw; /* ping out destination cmd option */ static unsigned char ping_flag; static ip_addr_t ping_addr; /* nonstatic debug cmd option, exported in lwipopts.h */ unsigned char debug_flags; /** @todo add options for selecting netif, starting DHCP client etc */ static struct option longopts[] = { /* turn on debugging output (if build with LWIP_DEBUG) */ {"debug", no_argument, NULL, 'd'}, /* help */ {"help", no_argument, NULL, 'h'}, /* gateway address */ {"gateway", required_argument, NULL, 'g'}, /* ip address */ {"ipaddr", required_argument, NULL, 'i'}, /* netmask */ {"netmask", required_argument, NULL, 'm'}, /* ping destination */ {"ping", required_argument, NULL, 'p'}, /* new command line options go here! */ {NULL, 0, NULL, 0} }; #define NUM_OPTS ((sizeof(longopts) / sizeof(struct option)) - 1) static void init_netifs(void); static void usage(void) { unsigned char i; printf("options:\n"); for (i = 0; i < NUM_OPTS; i++) { printf("-%c --%s\n",longopts[i].val, longopts[i].name); } } #if 0 static void tcp_debug_timeout(void *data) { LWIP_UNUSED_ARG(data); #if TCP_DEBUG tcp_debug_print_pcbs(); #endif /* TCP_DEBUG */ sys_timeout(5000, tcp_debug_timeout, NULL); } #endif static void tcpip_init_done(void *arg) { sys_sem_t *sem; sem = (sys_sem_t *)arg; init_netifs(); sys_sem_signal(sem); } #if PPP_SUPPORT void pppLinkStatusCallback(void *ctx, int errCode, void *arg) { switch(errCode) { case PPPERR_NONE: /* No error. */ { struct ppp_addrs *ppp_addrs = arg; printf("pppLinkStatusCallback: PPPERR_NONE"); printf(" our_ipaddr=%s", _inet_ntoa(ppp_addrs->our_ipaddr.addr)); printf(" his_ipaddr=%s", _inet_ntoa(ppp_addrs->his_ipaddr.addr)); printf(" netmask=%s", _inet_ntoa(ppp_addrs->netmask.addr)); printf(" dns1=%s", _inet_ntoa(ppp_addrs->dns1.addr)); printf(" dns2=%s\n", _inet_ntoa(ppp_addrs->dns2.addr)); } break; case PPPERR_PARAM: /* Invalid parameter. */ printf("pppLinkStatusCallback: PPPERR_PARAM\n"); break; case PPPERR_OPEN: /* Unable to open PPP session. */ printf("pppLinkStatusCallback: PPPERR_OPEN\n"); break; case PPPERR_DEVICE: /* Invalid I/O device for PPP. */ printf("pppLinkStatusCallback: PPPERR_DEVICE\n"); break; case PPPERR_ALLOC: /* Unable to allocate resources. */ printf("pppLinkStatusCallback: PPPERR_ALLOC\n"); break; case PPPERR_USER: /* User interrupt. */ printf("pppLinkStatusCallback: PPPERR_USER\n"); break; case PPPERR_CONNECT: /* Connection lost. */ printf("pppLinkStatusCallback: PPPERR_CONNECT\n"); break; case PPPERR_AUTHFAIL: /* Failed authentication challenge. */ printf("pppLinkStatusCallback: PPPERR_AUTHFAIL\n"); break; case PPPERR_PROTOCOL: /* Failed to meet protocol. */ printf("pppLinkStatusCallback: PPPERR_PROTOCOL\n"); break; default: printf("pppLinkStatusCallback: unknown errCode %d\n", errCode); break; } } #endif /*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/ #if LWIP_RAW static int seq_num; #if 0 /* Ping using the raw api */ static int ping_recv(void *arg, struct raw_pcb *pcb, struct pbuf *p, ip_addr_t *addr) { printf("ping recv\n"); return 1; /* eat the event */ } static void ping_send(struct raw_pcb *raw, ip_addr_t *addr) { struct pbuf *p; struct icmp_echo_hdr *iecho; p = pbuf_alloc(PBUF_IP,sizeof(struct icmp_echo_hdr),PBUF_RAM); if (!p) return; iecho = p->payload; ICMPH_TYPE_SET(iecho,ICMP_ECHO); iecho->chksum = 0; iecho->seqno = htons(seq_num); iecho->chksum = inet_chksum(iecho, p->len); raw_send_to(raw,p,addr); pbuf_free(p); seq_num++; } static void ping_thread(void *arg) { struct raw_pcb *raw; if (!(raw = raw_new(IP_PROTO_ICMP))) return; raw_recv(raw,ping_recv,NULL); while (1) { printf("ping send\n"); ping_send(raw,&ping_addr); sleep(1); } /* Never reaches this */ raw_remove(raw); } #else /* Ping using the socket api */ static void ping_send(int s, ip_addr_t *addr) { struct icmp_echo_hdr *iecho; struct sockaddr_in to; if (!(iecho = (struct icmp_echo_hdr *)malloc(sizeof(struct icmp_echo_hdr)))) return; ICMPH_TYPE_SET(iecho,ICMP_ECHO); iecho->chksum = 0; iecho->seqno = htons(seq_num); iecho->chksum = inet_chksum(iecho, sizeof(*iecho)); to.sin_len = sizeof(to); to.sin_family = AF_INET; to.sin_addr.s_addr = addr->addr; lwip_sendto(s,iecho,sizeof(*iecho),0,(struct sockaddr*)&to,sizeof(to)); free(iecho); seq_num++; } static void ping_recv(int s, ip_addr_t *addr) { char buf[200]; socklen_t fromlen; int len; struct sockaddr_in from; LWIP_UNUSED_ARG(addr); len = lwip_recvfrom(s, buf,sizeof(buf),0,(struct sockaddr*)&from,&fromlen); printf("Received %d bytes from %x\n",len,ntohl(from.sin_addr.s_addr)); } static void ping_thread(void *arg) { int s; LWIP_UNUSED_ARG(arg); if ((s = lwip_socket(AF_INET, SOCK_RAW, IP_PROTO_ICMP)) < 0) { return; } while (1) { printf("sending ping\n"); ping_send(s,&ping_addr); ping_recv(s,&ping_addr); sleep(1); } } #endif #endif struct netif netif; static void init_netifs(void) { #if PPP_SUPPORT pppInit(); #if PPP_PTY_TEST ppp_sio = sio_open(2); #else ppp_sio = sio_open(0); #endif if(!ppp_sio) { perror("Error opening device: "); exit(1); } #ifdef LWIP_PPP_CHAP_TEST pppSetAuth(PPPAUTHTYPE_CHAP, "lwip", "mysecret"); #endif pppOpen(ppp_sio, pppLinkStatusCallback, NULL); #endif /* PPP_SUPPORT */ #if LWIP_DHCP { IP4_ADDR(&gw, 0,0,0,0); IP4_ADDR(&ipaddr, 0,0,0,0); IP4_ADDR(&netmask, 0,0,0,0); netif_add(&netif, &ipaddr, &netmask, &gw, NULL, tapif_init, tcpip_input); netif_set_default(&netif); dhcp_start(&netif); } #else netif_set_default(netif_add(&netif,&ipaddr, &netmask, &gw, NULL, tapif_init, tcpip_input)); netif_set_up(&netif); #endif #if LWIP_IPV6 netif_create_ip6_linklocal_address(&netif, 1); #endif #if 0 /* Only used for testing purposes: */ netif_add(&ipaddr, &netmask, &gw, NULL, pcapif_init, tcpip_input); #endif #if LWIP_TCP tcpecho_init(); shell_init(); httpd_init(); #endif #if LWIP_UDP udpecho_init(); #endif /* sys_timeout(5000, tcp_debug_timeout, NULL);*/ } /*-----------------------------------------------------------------------------------*/ static void main_thread(void *arg) { sys_sem_t sem; #if PPP_SUPPORT sio_fd_t ppp_sio; #endif LWIP_UNUSED_ARG(arg); if(sys_sem_new(&sem, 0) != ERR_OK) { LWIP_ASSERT("Failed to create semaphore", 0); } tcpip_init(tcpip_init_done, &sem); sys_sem_wait(&sem); printf("TCP/IP initialized.\n"); #if LWIP_RAW /** @todo remove dependency on RAW PCB support */ if(ping_flag) { sys_thread_new("ping_thread", ping_thread, NULL, DEFAULT_THREAD_STACKSIZE, DEFAULT_THREAD_PRIO); } #endif printf("Applications started.\n"); #ifdef MEM_PERF mem_perf_init("/tmp/memstats.client"); #endif /* MEM_PERF */ #if 0 stats_display(); #endif /* Block forever. */ sys_sem_wait(&sem); } /*-----------------------------------------------------------------------------------*/ int main(int argc, char **argv) { struct in_addr inaddr; int ch; char ip_str[16] = {0}, nm_str[16] = {0}, gw_str[16] = {0}; /* startup defaults (may be overridden by one or more opts) */ IP4_ADDR(&gw, 192,168,0,1); IP4_ADDR(&netmask, 255,255,255,0); IP4_ADDR(&ipaddr, 192,168,0,2); ping_flag = 0; /* use debug flags defined by debug.h */ debug_flags = LWIP_DBG_OFF; while ((ch = getopt_long(argc, argv, "dhg:i:m:p:", longopts, NULL)) != -1) { switch (ch) { case 'd': debug_flags |= (LWIP_DBG_ON|LWIP_DBG_TRACE|LWIP_DBG_STATE|LWIP_DBG_FRESH|LWIP_DBG_HALT); break; case 'h': usage(); exit(0); break; case 'g': inet_aton(optarg, &inaddr); gw.addr = inaddr.s_addr; break; case 'i': inet_aton(optarg, &inaddr); ipaddr.addr = inaddr.s_addr; break; case 'm': inet_aton(optarg, &inaddr); netmask.addr = inaddr.s_addr; break; case 'p': ping_flag = !0; inet_aton(optarg, &inaddr); /* lwip inet.h oddity workaround */ ping_addr.addr = inaddr.s_addr; strncpy(ip_str,inet_ntoa(inaddr),sizeof(ip_str)); printf("Using %s to ping\n", ip_str); break; default: usage(); break; } } argc -= optind; argv += optind; inaddr.s_addr = ipaddr.addr; strncpy(ip_str,inet_ntoa(inaddr),sizeof(ip_str)); inaddr.s_addr = netmask.addr; strncpy(nm_str,inet_ntoa(inaddr),sizeof(nm_str)); inaddr.s_addr = gw.addr; strncpy(gw_str,inet_ntoa(inaddr),sizeof(gw_str)); printf("Host at %s mask %s gateway %s\n", ip_str, nm_str, gw_str); #ifdef PERF perf_init("/tmp/simhost.perf"); #endif /* PERF */ printf("System initialized.\n"); sys_thread_new("main_thread", main_thread, NULL, DEFAULT_THREAD_STACKSIZE, DEFAULT_THREAD_PRIO); pause(); return 0; } /*-----------------------------------------------------------------------------------*/ ocproxy-1.60/contrib/ports/unix/proj/unixsim/simnode.c000066400000000000000000000101241303453231400232010ustar00rootroot00000000000000/* * Copyright (c) 2001-2003 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #include "lwip/debug.h" #include #include "lwip/mem.h" #include "lwip/memp.h" #include "lwip/sys.h" #include "lwip/tcp_impl.h" #include "lwip/stats.h" #include "lwip/tcpip.h" #include "netif/unixif.h" #include "netif/dropif.h" #include "netif/tcpdump.h" #include "lwip/ip_addr.h" #include "arch/perf.h" #include "httpd.h" #include "udpecho.h" #include "tcpecho.h" #include "shell.h" /* nonstatic debug cmd option, exported in lwipopts.h */ unsigned char debug_flags; /*-----------------------------------------------------------------------------------*/ static void tcp_timeout(void *data) { LWIP_UNUSED_ARG(data); #if TCP_DEBUG tcp_debug_print_pcbs(); #endif /* TCP_DEBUG */ sys_timeout(5000, tcp_timeout, NULL); } /*-----------------------------------------------------------------------------------*/ struct netif netif_unix; /*-----------------------------------------------------------------------------------*/ static void tcpip_init_done(void *arg) { ip_addr_t ipaddr, netmask, gw; sys_sem_t *sem; sem = (sys_sem_t *)arg; IP4_ADDR(&gw, 192,168,1,1); IP4_ADDR(&ipaddr, 192,168,1,2); IP4_ADDR(&netmask, 255,255,255,0); netif_set_default(netif_add(&netif_unix, &ipaddr, &netmask, &gw, NULL, unixif_init_client, tcpip_input)); #if LWIP_IPV6 netif_create_ip6_linklocal_address(&netif_unix, 1); #endif /* netif_set_default(netif_add(&ipaddr, &netmask, &gw, NULL, sioslipif_init1, tcpip_input)); */ tcpecho_init(); shell_init(); httpd_init(); udpecho_init(); printf("Applications started.\n"); sys_timeout(5000, tcp_timeout, NULL); sys_sem_signal(sem); } /*-----------------------------------------------------------------------------------*/ static void main_thread(void *arg) { sys_sem_t sem; LWIP_UNUSED_ARG(arg); if(sys_sem_new(&sem, 0) != ERR_OK) { LWIP_ASSERT("Failed to create semaphore", 0); } tcpip_init(tcpip_init_done, &sem); sys_sem_wait(&sem); printf("TCP/IP initialized.\n"); #ifdef MEM_PERF mem_perf_init("/tmp/memstats.client"); #endif /* MEM_PERF */ /* Block forever. */ sys_sem_wait(&sem); } /*-----------------------------------------------------------------------------------*/ int main(void) { #ifdef PERF perf_init("/tmp/client.perf"); #endif /* PERF */ tcpdump_init(); printf("System initialized.\n"); sys_thread_new("main_thread", main_thread, NULL, DEFAULT_THREAD_STACKSIZE, DEFAULT_THREAD_PRIO); pause(); return 0; } /*-----------------------------------------------------------------------------------*/ ocproxy-1.60/contrib/ports/unix/proj/unixsim/simrouter.c000066400000000000000000000106631303453231400236040ustar00rootroot00000000000000/* * Copyright (c) 2001-2003 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #include "lwip/debug.h" #include #include "lwip/mem.h" #include "lwip/memp.h" #include "lwip/sys.h" #include "lwip/tcp_impl.h" #include "lwip/stats.h" #include "lwip/tcpip.h" #include "netif/tapif.h" #include "netif/unixif.h" #include "netif/dropif.h" #include "netif/tcpdump.h" #include "lwip/ip_addr.h" #include "arch/perf.h" #include "httpd.h" #include "udpecho.h" #include "tcpecho.h" #include "shell.h" /* nonstatic debug cmd option, exported in lwipopts.h */ unsigned char debug_flags; /*-----------------------------------------------------------------------------------*/ static void tcp_timeout(void *data) { LWIP_UNUSED_ARG(data); #if TCP_DEBUG tcp_debug_print_pcbs(); #endif /* TCP_DEBUG */ sys_timeout(5000, tcp_timeout, NULL); } /*-----------------------------------------------------------------------------------*/ struct netif netif_tap, netif_unix; /*-----------------------------------------------------------------------------------*/ static void tcpip_init_done(void *arg) { ip_addr_t ipaddr, netmask, gw; sys_sem_t *sem; sem = (sys_sem_t *)arg; IP4_ADDR(&gw, 192,168,0,1); IP4_ADDR(&ipaddr, 192,168,0,2); IP4_ADDR(&netmask, 255,255,255,0); netif_set_default(netif_add(&netif_tap, &ipaddr, &netmask, &gw, NULL, tapif_init, tcpip_input)); #if LWIP_IPV6 netif_create_ip6_linklocal_address(&netif_tap, 1); #endif IP4_ADDR(&gw, 192,168,1,1); IP4_ADDR(&ipaddr, 192,168,1,1); IP4_ADDR(&netmask, 255,255,255,0); netif_set_default(netif_add(&netif_unix, &ipaddr, &netmask, &gw, NULL, unixif_init_server, tcpip_input)); #if LWIP_IPV6 netif_create_ip6_linklocal_address(&netif_unix, 1); #endif system("route add 192.168.1.1 192.168.0.2"); system("route add 192.168.1.2 192.168.0.2"); /*netif_set_default(netif_add(&ipaddr, &netmask, &gw, NULL, sioslipif_init1, tcpip_input)); */ tcpecho_init(); shell_init(); httpd_init(); udpecho_init(); printf("Applications started.\n"); sys_timeout(5000, tcp_timeout, NULL); sys_sem_signal(sem); } static void main_thread(void *arg) { sys_sem_t sem; LWIP_UNUSED_ARG(arg); if(sys_sem_new(&sem, 0) != ERR_OK) { LWIP_ASSERT("Failed to create semaphore", 0); } tcpip_init(tcpip_init_done, &sem); sys_sem_wait(&sem); printf("TCP/IP initialized.\n"); #ifdef MEM_PERF mem_perf_init("/tmp/memstats.client"); #endif /* MEM_PERF */ /* Block forever. */ sys_sem_wait(&sem); } /*-----------------------------------------------------------------------------------*/ int main(void) { #ifdef PERF perf_init("/tmp/client.perf"); #endif /* PERF */ tcpdump_init(); printf("System initialized.\n"); sys_thread_new("main_thread", main_thread, NULL, DEFAULT_THREAD_STACKSIZE, DEFAULT_THREAD_PRIO); pause(); return 0; } /*-----------------------------------------------------------------------------------*/ ocproxy-1.60/contrib/ports/unix/sys_arch.c000066400000000000000000000375321303453231400207240ustar00rootroot00000000000000/* * Copyright (c) 2001-2003 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ /* * Wed Apr 17 16:05:29 EDT 2002 (James Roth) * * - Fixed an unlikely sys_thread_new() race condition. * * - Made current_thread() work with threads which where * not created with sys_thread_new(). This includes * the main thread and threads made with pthread_create(). * * - Catch overflows where more than SYS_MBOX_SIZE messages * are waiting to be read. The sys_mbox_post() routine * will block until there is more room instead of just * leaking messages. */ #include "lwip/debug.h" #include #include #include #include #include #include #include "lwip/sys.h" #include "lwip/opt.h" #include "lwip/stats.h" #define UMAX(a, b) ((a) > (b) ? (a) : (b)) static struct timeval starttime; #if !NO_SYS static struct sys_thread *threads = NULL; static pthread_mutex_t threads_mutex = PTHREAD_MUTEX_INITIALIZER; struct sys_mbox_msg { struct sys_mbox_msg *next; void *msg; }; #define SYS_MBOX_SIZE 128 struct sys_mbox { int first, last; void *msgs[SYS_MBOX_SIZE]; struct sys_sem *not_empty; struct sys_sem *not_full; struct sys_sem *mutex; int wait_send; }; struct sys_sem { unsigned int c; pthread_cond_t cond; pthread_mutex_t mutex; }; struct sys_thread { struct sys_thread *next; pthread_t pthread; }; #if SYS_LIGHTWEIGHT_PROT static pthread_mutex_t lwprot_mutex = PTHREAD_MUTEX_INITIALIZER; static pthread_t lwprot_thread = (pthread_t)0xDEAD; static int lwprot_count = 0; #endif /* SYS_LIGHTWEIGHT_PROT */ static struct sys_sem *sys_sem_new_internal(u8_t count); static void sys_sem_free_internal(struct sys_sem *sem); static u32_t cond_wait(pthread_cond_t * cond, pthread_mutex_t * mutex, u32_t timeout); /*-----------------------------------------------------------------------------------*/ static struct sys_thread * introduce_thread(pthread_t id) { struct sys_thread *thread; thread = (struct sys_thread *)malloc(sizeof(struct sys_thread)); if (thread != NULL) { pthread_mutex_lock(&threads_mutex); thread->next = threads; thread->pthread = id; threads = thread; pthread_mutex_unlock(&threads_mutex); } return thread; } /*-----------------------------------------------------------------------------------*/ sys_thread_t sys_thread_new(const char *name, lwip_thread_fn function, void *arg, int stacksize, int prio) { int code; pthread_t tmp; struct sys_thread *st = NULL; LWIP_UNUSED_ARG(name); LWIP_UNUSED_ARG(stacksize); LWIP_UNUSED_ARG(prio); code = pthread_create(&tmp, NULL, (void *(*)(void *)) function, arg); if (0 == code) { st = introduce_thread(tmp); } if (NULL == st) { LWIP_DEBUGF(SYS_DEBUG, ("sys_thread_new: pthread_create %d, st = 0x%lx", code, (unsigned long)st)); abort(); } return st; } /*-----------------------------------------------------------------------------------*/ err_t sys_mbox_new(struct sys_mbox **mb, int size) { struct sys_mbox *mbox; LWIP_UNUSED_ARG(size); mbox = (struct sys_mbox *)malloc(sizeof(struct sys_mbox)); if (mbox == NULL) { return ERR_MEM; } mbox->first = mbox->last = 0; mbox->not_empty = sys_sem_new_internal(0); mbox->not_full = sys_sem_new_internal(0); mbox->mutex = sys_sem_new_internal(1); mbox->wait_send = 0; SYS_STATS_INC_USED(mbox); *mb = mbox; return ERR_OK; } /*-----------------------------------------------------------------------------------*/ void sys_mbox_free(struct sys_mbox **mb) { if ((mb != NULL) && (*mb != SYS_MBOX_NULL)) { struct sys_mbox *mbox = *mb; SYS_STATS_DEC(mbox.used); sys_arch_sem_wait(&mbox->mutex, 0); sys_sem_free_internal(mbox->not_empty); sys_sem_free_internal(mbox->not_full); sys_sem_free_internal(mbox->mutex); mbox->not_empty = mbox->not_full = mbox->mutex = NULL; /* LWIP_DEBUGF("sys_mbox_free: mbox 0x%lx\n", mbox); */ free(mbox); } } /*-----------------------------------------------------------------------------------*/ err_t sys_mbox_trypost(struct sys_mbox **mb, void *msg) { u8_t first; struct sys_mbox *mbox; LWIP_ASSERT("invalid mbox", (mb != NULL) && (*mb != NULL)); mbox = *mb; sys_arch_sem_wait(&mbox->mutex, 0); LWIP_DEBUGF(SYS_DEBUG, ("sys_mbox_trypost: mbox %p msg %p\n", (void *)mbox, (void *)msg)); if ((mbox->last + 1) >= (mbox->first + SYS_MBOX_SIZE)) { sys_sem_signal(&mbox->mutex); return ERR_MEM; } mbox->msgs[mbox->last % SYS_MBOX_SIZE] = msg; if (mbox->last == mbox->first) { first = 1; } else { first = 0; } mbox->last++; if (first) { sys_sem_signal(&mbox->not_empty); } sys_sem_signal(&mbox->mutex); return ERR_OK; } /*-----------------------------------------------------------------------------------*/ void sys_mbox_post(struct sys_mbox **mb, void *msg) { u8_t first; struct sys_mbox *mbox; LWIP_ASSERT("invalid mbox", (mb != NULL) && (*mb != NULL)); mbox = *mb; sys_arch_sem_wait(&mbox->mutex, 0); LWIP_DEBUGF(SYS_DEBUG, ("sys_mbox_post: mbox %p msg %p\n", (void *)mbox, (void *)msg)); while ((mbox->last + 1) >= (mbox->first + SYS_MBOX_SIZE)) { mbox->wait_send++; sys_sem_signal(&mbox->mutex); sys_arch_sem_wait(&mbox->not_full, 0); sys_arch_sem_wait(&mbox->mutex, 0); mbox->wait_send--; } mbox->msgs[mbox->last % SYS_MBOX_SIZE] = msg; if (mbox->last == mbox->first) { first = 1; } else { first = 0; } mbox->last++; if (first) { sys_sem_signal(&mbox->not_empty); } sys_sem_signal(&mbox->mutex); } /*-----------------------------------------------------------------------------------*/ u32_t sys_arch_mbox_tryfetch(struct sys_mbox **mb, void **msg) { struct sys_mbox *mbox; LWIP_ASSERT("invalid mbox", (mb != NULL) && (*mb != NULL)); mbox = *mb; sys_arch_sem_wait(&mbox->mutex, 0); if (mbox->first == mbox->last) { sys_sem_signal(&mbox->mutex); return SYS_MBOX_EMPTY; } if (msg != NULL) { LWIP_DEBUGF(SYS_DEBUG, ("sys_mbox_tryfetch: mbox %p msg %p\n", (void *)mbox, *msg)); *msg = mbox->msgs[mbox->first % SYS_MBOX_SIZE]; } else{ LWIP_DEBUGF(SYS_DEBUG, ("sys_mbox_tryfetch: mbox %p, null msg\n", (void *)mbox)); } mbox->first++; if (mbox->wait_send) { sys_sem_signal(&mbox->not_full); } sys_sem_signal(&mbox->mutex); return 0; } /*-----------------------------------------------------------------------------------*/ u32_t sys_arch_mbox_fetch(struct sys_mbox **mb, void **msg, u32_t timeout) { u32_t time_needed = 0; struct sys_mbox *mbox; LWIP_ASSERT("invalid mbox", (mb != NULL) && (*mb != NULL)); mbox = *mb; /* The mutex lock is quick so we don't bother with the timeout stuff here. */ sys_arch_sem_wait(&mbox->mutex, 0); while (mbox->first == mbox->last) { sys_sem_signal(&mbox->mutex); /* We block while waiting for a mail to arrive in the mailbox. We must be prepared to timeout. */ if (timeout != 0) { time_needed = sys_arch_sem_wait(&mbox->not_empty, timeout); if (time_needed == SYS_ARCH_TIMEOUT) { return SYS_ARCH_TIMEOUT; } } else { sys_arch_sem_wait(&mbox->not_empty, 0); } sys_arch_sem_wait(&mbox->mutex, 0); } if (msg != NULL) { LWIP_DEBUGF(SYS_DEBUG, ("sys_mbox_fetch: mbox %p msg %p\n", (void *)mbox, *msg)); *msg = mbox->msgs[mbox->first % SYS_MBOX_SIZE]; } else{ LWIP_DEBUGF(SYS_DEBUG, ("sys_mbox_fetch: mbox %p, null msg\n", (void *)mbox)); } mbox->first++; if (mbox->wait_send) { sys_sem_signal(&mbox->not_full); } sys_sem_signal(&mbox->mutex); return time_needed; } /*-----------------------------------------------------------------------------------*/ static struct sys_sem * sys_sem_new_internal(u8_t count) { struct sys_sem *sem; sem = (struct sys_sem *)malloc(sizeof(struct sys_sem)); if (sem != NULL) { sem->c = count; pthread_cond_init(&(sem->cond), NULL); pthread_mutex_init(&(sem->mutex), NULL); } return sem; } /*-----------------------------------------------------------------------------------*/ err_t sys_sem_new(struct sys_sem **sem, u8_t count) { SYS_STATS_INC_USED(sem); *sem = sys_sem_new_internal(count); if (*sem == NULL) { return ERR_MEM; } return ERR_OK; } /*-----------------------------------------------------------------------------------*/ static u32_t cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex, u32_t timeout) { time_t tdiff; time_t sec, usec; struct timeval rtime1, rtime2; struct timespec ts; int retval; if (timeout > 0) { /* Get a timestamp and add the timeout value. */ gettimeofday(&rtime1, NULL); sec = rtime1.tv_sec; usec = rtime1.tv_usec; usec += timeout % 1000 * 1000; sec += (int)(timeout / 1000) + (int)(usec / 1000000); usec = usec % 1000000; ts.tv_nsec = usec * 1000; ts.tv_sec = sec; retval = pthread_cond_timedwait(cond, mutex, &ts); if (retval == ETIMEDOUT) { return SYS_ARCH_TIMEOUT; } else { /* Calculate for how long we waited for the cond. */ gettimeofday(&rtime2, NULL); tdiff = (rtime2.tv_sec - rtime1.tv_sec) * 1000 + (rtime2.tv_usec - rtime1.tv_usec) / 1000; if (tdiff <= 0) { return 0; } return (u32_t)tdiff; } } else { pthread_cond_wait(cond, mutex); return 0; } } /*-----------------------------------------------------------------------------------*/ u32_t sys_arch_sem_wait(struct sys_sem **s, u32_t timeout) { u32_t time_needed = 0; struct sys_sem *sem; LWIP_ASSERT("invalid sem", (s != NULL) && (*s != NULL)); sem = *s; pthread_mutex_lock(&(sem->mutex)); while (sem->c <= 0) { if (timeout > 0) { time_needed = cond_wait(&(sem->cond), &(sem->mutex), timeout); if (time_needed == SYS_ARCH_TIMEOUT) { pthread_mutex_unlock(&(sem->mutex)); return SYS_ARCH_TIMEOUT; } /* pthread_mutex_unlock(&(sem->mutex)); return time_needed; */ } else { cond_wait(&(sem->cond), &(sem->mutex), 0); } } sem->c--; pthread_mutex_unlock(&(sem->mutex)); return (u32_t)time_needed; } /*-----------------------------------------------------------------------------------*/ void sys_sem_signal(struct sys_sem **s) { struct sys_sem *sem; LWIP_ASSERT("invalid sem", (s != NULL) && (*s != NULL)); sem = *s; pthread_mutex_lock(&(sem->mutex)); sem->c++; if (sem->c > 1) { sem->c = 1; } pthread_cond_broadcast(&(sem->cond)); pthread_mutex_unlock(&(sem->mutex)); } /*-----------------------------------------------------------------------------------*/ static void sys_sem_free_internal(struct sys_sem *sem) { pthread_cond_destroy(&(sem->cond)); pthread_mutex_destroy(&(sem->mutex)); free(sem); } /*-----------------------------------------------------------------------------------*/ void sys_sem_free(struct sys_sem **sem) { if ((sem != NULL) && (*sem != SYS_SEM_NULL)) { SYS_STATS_DEC(sem.used); sys_sem_free_internal(*sem); } } #endif /* !NO_SYS */ /*-----------------------------------------------------------------------------------*/ u32_t sys_now(void) { struct timeval tv; u32_t sec, usec, msec; gettimeofday(&tv, NULL); sec = (u32_t)(tv.tv_sec - starttime.tv_sec); usec = (u32_t)(tv.tv_usec - starttime.tv_usec); msec = sec * 1000 + usec / 1000; return msec; } /*-----------------------------------------------------------------------------------*/ void sys_init(void) { gettimeofday(&starttime, NULL); } /*-----------------------------------------------------------------------------------*/ #if SYS_LIGHTWEIGHT_PROT /** sys_prot_t sys_arch_protect(void) This optional function does a "fast" critical region protection and returns the previous protection level. This function is only called during very short critical regions. An embedded system which supports ISR-based drivers might want to implement this function by disabling interrupts. Task-based systems might want to implement this by using a mutex or disabling tasking. This function should support recursive calls from the same task or interrupt. In other words, sys_arch_protect() could be called while already protected. In that case the return value indicates that it is already protected. sys_arch_protect() is only required if your port is supporting an operating system. */ sys_prot_t sys_arch_protect(void) { /* Note that for the UNIX port, we are using a lightweight mutex, and our * own counter (which is locked by the mutex). The return code is not actually * used. */ if (lwprot_thread != pthread_self()) { /* We are locking the mutex where it has not been locked before * * or is being locked by another thread */ pthread_mutex_lock(&lwprot_mutex); lwprot_thread = pthread_self(); lwprot_count = 1; } else /* It is already locked by THIS thread */ lwprot_count++; return 0; } /*-----------------------------------------------------------------------------------*/ /** void sys_arch_unprotect(sys_prot_t pval) This optional function does a "fast" set of critical region protection to the value specified by pval. See the documentation for sys_arch_protect() for more information. This function is only required if your port is supporting an operating system. */ void sys_arch_unprotect(sys_prot_t pval) { LWIP_UNUSED_ARG(pval); if (lwprot_thread == pthread_self()) { if (--lwprot_count == 0) { lwprot_thread = (pthread_t) 0xDEAD; pthread_mutex_unlock(&lwprot_mutex); } } } #endif /* SYS_LIGHTWEIGHT_PROT */ /*-----------------------------------------------------------------------------------*/ #ifndef MAX_JIFFY_OFFSET #define MAX_JIFFY_OFFSET ((~0U >> 1)-1) #endif #ifndef HZ #define HZ 100 #endif u32_t sys_jiffies(void) { struct timeval tv; unsigned long sec; long usec; gettimeofday(&tv,NULL); sec = tv.tv_sec - starttime.tv_sec; usec = tv.tv_usec; if (sec >= (MAX_JIFFY_OFFSET / HZ)) return MAX_JIFFY_OFFSET; usec += 1000000L / HZ - 1; usec /= 1000000L / HZ; return HZ * sec + usec; } #if PPP_DEBUG #include void ppp_trace(int level, const char *format, ...) { va_list args; (void)level; va_start(args, format); vprintf(format, args); va_end(args); } #endif ocproxy-1.60/contrib/ports/win32/000077500000000000000000000000001303453231400167125ustar00rootroot00000000000000ocproxy-1.60/contrib/ports/win32/.cvsignore000066400000000000000000000000161303453231400207070ustar00rootroot00000000000000lwipcfg_msvc.hocproxy-1.60/contrib/ports/win32/check/000077500000000000000000000000001303453231400177675ustar00rootroot00000000000000ocproxy-1.60/contrib/ports/win32/check/config.h000066400000000000000000000010171303453231400214040ustar00rootroot00000000000000/* config.h for check-0.9.8 on win32 under MSVC/MinGW */ #ifdef _MSC_VER typedef unsigned int pid_t; typedef unsigned int uint32_t; #define ssize_t size_t #define snprintf _snprintf #define HAVE_DECL_STRDUP 1 #define HAVE_DECL_FILENO 1 #define HAVE_DECL_PUTENV 1 #define _CRT_SECURE_NO_WARNINGS /* disable some warnings */ #pragma warning (disable: 4090) /* const assigned to non-const */ #pragma warning (disable: 4996) /* fileno is deprecated */ #endif /* _ MSC_VER */ #define LWIP_UNITTESTS_NOFORK #include ocproxy-1.60/contrib/ports/win32/check/sys/000077500000000000000000000000001303453231400206055ustar00rootroot00000000000000ocproxy-1.60/contrib/ports/win32/check/sys/time.h000066400000000000000000000003751303453231400217210ustar00rootroot00000000000000#ifndef LWIP_SYS__TIME_H #define LWIP_SYS__TIME_H #include /* time_t */ struct timeval { time_t tv_sec; /* seconds */ long tv_usec; /* and microseconds */ }; int gettimeofday(struct timeval* tp, void* tzp); #endif ocproxy-1.60/contrib/ports/win32/check/time.c000066400000000000000000000024451303453231400210760ustar00rootroot00000000000000#include #include #if defined(_MSC_VER) || defined(_MSC_EXTENSIONS) #define DELTA_EPOCH_IN_MICROSECS 11644473600000000Ui64 #else #define DELTA_EPOCH_IN_MICROSECS 11644473600000000ULL #endif #include "config.h" struct timezone { int tz_minuteswest; /* minutes W of Greenwich */ int tz_dsttime; /* type of dst correction */ }; int gettimeofday(struct timeval *tv, struct timezone *tz) { FILETIME ft; unsigned __int64 tmpres = 0; static int tzflag; if (NULL != tv) { GetSystemTimeAsFileTime(&ft); tmpres |= ft.dwHighDateTime; tmpres <<= 32; tmpres |= ft.dwLowDateTime; /*converting file time to unix epoch*/ tmpres -= DELTA_EPOCH_IN_MICROSECS; tmpres /= 10; /*convert into microseconds*/ tv->tv_sec = (long)(tmpres / 1000000UL); tv->tv_usec = (long)(tmpres % 1000000UL); } if (NULL != tz) { if (!tzflag) { _tzset(); tzflag++; } tz->tz_minuteswest = _timezone / 60; tz->tz_dsttime = _daylight; } return 0; } struct tm * localtime_r(const time_t *timer, struct tm *result) { struct tm *local_result; local_result = localtime (timer); if (local_result == NULL || result == NULL) return NULL; memcpy (result, local_result, sizeof (result)); return result; } ocproxy-1.60/contrib/ports/win32/check/unistd.h000066400000000000000000000001571303453231400214510ustar00rootroot00000000000000#ifndef LWIP_UNISTD_H #define LWIP_UNISTD_H /* include io.h for read() and write() */ #include #endif ocproxy-1.60/contrib/ports/win32/include/000077500000000000000000000000001303453231400203355ustar00rootroot00000000000000ocproxy-1.60/contrib/ports/win32/include/arch/000077500000000000000000000000001303453231400212525ustar00rootroot00000000000000ocproxy-1.60/contrib/ports/win32/include/arch/bpstruct.h000066400000000000000000000000251303453231400232660ustar00rootroot00000000000000#pragma pack(push,1) ocproxy-1.60/contrib/ports/win32/include/arch/cc.h000066400000000000000000000071131303453231400220120ustar00rootroot00000000000000/* * Copyright (c) 2001-2003 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #ifndef LWIP_ARCH_CC_H #define LWIP_ARCH_CC_H #include /* printf, fflush, FILE */ #include /* abort */ #include #ifdef _MSC_VER #pragma warning (disable: 4244) /* disable conversion warning (implicit integer promotion!) */ #pragma warning (disable: 4127) /* conditional expression is constant */ #pragma warning (disable: 4996) /* 'strncpy' was declared deprecated */ #pragma warning (disable: 4103) /* structure packing changed by including file */ #endif #define LWIP_PROVIDE_ERRNO /* Define platform endianness (might already be defined) */ #ifndef BYTE_ORDER #define BYTE_ORDER LITTLE_ENDIAN #endif /* BYTE_ORDER */ /* Define generic types used in lwIP */ typedef unsigned char u8_t; typedef signed char s8_t; typedef unsigned short u16_t; typedef signed short s16_t; typedef unsigned long u32_t; typedef signed long s32_t; typedef size_t mem_ptr_t; typedef u32_t sys_prot_t; /* Define (sn)printf formatters for these lwIP types */ #define X8_F "02x" #define U16_F "hu" #define U32_F "lu" #define S32_F "ld" #define X32_F "lx" #ifdef __GNUC__ #define S16_F "d" #define X16_F "uX" #define SZT_F "u" #else #define S16_F "hd" #define X16_F "hx" #define SZT_F "lu" #endif /* Compiler hints for packing structures */ #define PACK_STRUCT_STRUCT #define PACK_STRUCT_USE_INCLUDES /* Plaform specific diagnostic output */ #define LWIP_PLATFORM_DIAG(x) do { printf x; } while(0) #define LWIP_PLATFORM_ASSERT(x) do { printf("Assertion \"%s\" failed at line %d in %s\n", \ x, __LINE__, __FILE__); fflush(NULL); abort(); } while(0) #define LWIP_ERROR(message, expression, handler) do { if (!(expression)) { \ printf("Assertion \"%s\" failed at line %d in %s\n", message, __LINE__, __FILE__); \ fflush(NULL);handler;} } while(0) #ifdef _MSC_VER /* C runtime functions redefined */ #define snprintf _snprintf #endif u32_t dns_lookup_external_hosts_file(const char *name); #define LWIP_RAND() ((u32_t)rand()) #endif /* LWIP_ARCH_CC_H */ ocproxy-1.60/contrib/ports/win32/include/arch/epstruct.h000066400000000000000000000000221303453231400232660ustar00rootroot00000000000000#pragma pack(pop) ocproxy-1.60/contrib/ports/win32/include/arch/perf.h000066400000000000000000000035031303453231400223600ustar00rootroot00000000000000/* * Copyright (c) 2001, Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the Institute nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #ifndef LWIP_PERF_H #define LWIP_PERF_H #define PERF_START /* null definition */ #define PERF_STOP(x) /* null definition */ #endif /* LWIP_PERF_H */ ocproxy-1.60/contrib/ports/win32/include/arch/sys_arch.h000066400000000000000000000050311303453231400232350ustar00rootroot00000000000000/* * Copyright (c) 2001-2003 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #ifndef LWIP_ARCH_SYS_ARCH_H #define LWIP_ARCH_SYS_ARCH_H /* HANDLE is used for sys_sem_t but we won't include windows.h */ struct _sys_sem { void *sem; }; typedef struct _sys_sem sys_sem_t; #define SYS_SEM_NULL NULL #define sys_sem_valid(sema) (((sema) != NULL) && ((sema)->sem != NULL) && ((sema)->sem != (void*)-1)) #define sys_sem_set_invalid(sema) ((sema)->sem = NULL) /* let sys.h use binary semaphores for mutexes */ #define LWIP_COMPAT_MUTEX 1 #ifndef MAX_QUEUE_ENTRIES #define MAX_QUEUE_ENTRIES 100 #endif struct lwip_mbox { void* sem; void* q_mem[MAX_QUEUE_ENTRIES]; u32_t head, tail; }; typedef struct lwip_mbox sys_mbox_t; #define SYS_MBOX_NULL NULL #define sys_mbox_valid(mbox) ((mbox != NULL) && ((mbox)->sem != NULL) && ((mbox)->sem != (void*)-1)) #define sys_mbox_set_invalid(mbox) ((mbox)->sem = NULL) /* DWORD (thread id) is used for sys_thread_t but we won't include windows.h */ typedef u32_t sys_thread_t; #endif /* LWIP_ARCH_SYS_ARCH_H */ ocproxy-1.60/contrib/ports/win32/include/lwipopts.h000066400000000000000000000240541303453231400223740ustar00rootroot00000000000000/* * Copyright (c) 2001-2003 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #ifndef LWIP_LWIPOPTS_H #define LWIP_LWIPOPTS_H #define NO_SYS 0 #define LWIP_SOCKET (NO_SYS==0) #define LWIP_NETCONN (NO_SYS==0) #define LWIP_IGMP 1 #define LWIP_ICMP 1 #define LWIP_SNMP 1 #define LWIP_DNS 1 #define LWIP_HAVE_LOOPIF 1 #define LWIP_NETIF_LOOPBACK 1 #define LWIP_LOOPBACK_MAX_PBUFS 10 #define TCP_LISTEN_BACKLOG 0 #define LWIP_COMPAT_SOCKETS 1 #define LWIP_SO_RCVTIMEO 1 #define LWIP_SO_RCVBUF 1 #define LWIP_TCPIP_CORE_LOCKING 0 #define LWIP_NETIF_LINK_CALLBACK 1 #define LWIP_NETIF_STATUS_CALLBACK 1 #ifdef LWIP_DEBUG #define LWIP_DBG_MIN_LEVEL 0 #define PPP_DEBUG LWIP_DBG_OFF #define MEM_DEBUG LWIP_DBG_OFF #define MEMP_DEBUG LWIP_DBG_OFF #define PBUF_DEBUG LWIP_DBG_OFF #define API_LIB_DEBUG LWIP_DBG_OFF #define API_MSG_DEBUG LWIP_DBG_OFF #define TCPIP_DEBUG LWIP_DBG_OFF #define NETIF_DEBUG LWIP_DBG_OFF #define SOCKETS_DEBUG LWIP_DBG_OFF #define DNS_DEBUG LWIP_DBG_OFF #define AUTOIP_DEBUG LWIP_DBG_OFF #define DHCP_DEBUG LWIP_DBG_OFF #define IP_DEBUG LWIP_DBG_OFF #define IP_REASS_DEBUG LWIP_DBG_OFF #define ICMP_DEBUG LWIP_DBG_OFF #define IGMP_DEBUG LWIP_DBG_OFF #define UDP_DEBUG LWIP_DBG_OFF #define TCP_DEBUG LWIP_DBG_OFF #define TCP_INPUT_DEBUG LWIP_DBG_OFF #define TCP_OUTPUT_DEBUG LWIP_DBG_OFF #define TCP_RTO_DEBUG LWIP_DBG_OFF #define TCP_CWND_DEBUG LWIP_DBG_OFF #define TCP_WND_DEBUG LWIP_DBG_OFF #define TCP_FR_DEBUG LWIP_DBG_OFF #define TCP_QLEN_DEBUG LWIP_DBG_OFF #define TCP_RST_DEBUG LWIP_DBG_OFF #endif #define LWIP_DBG_TYPES_ON (LWIP_DBG_ON|LWIP_DBG_TRACE|LWIP_DBG_STATE|LWIP_DBG_FRESH|LWIP_DBG_HALT) /* ---------- Memory options ---------- */ /* MEM_ALIGNMENT: should be set to the alignment of the CPU for which lwIP is compiled. 4 byte alignment -> define MEM_ALIGNMENT to 4, 2 byte alignment -> define MEM_ALIGNMENT to 2. */ /* MSVC port: intel processors don't need 4-byte alignment, but are faster that way! */ #define MEM_ALIGNMENT 4 /* MEM_SIZE: the size of the heap memory. If the application will send a lot of data that needs to be copied, this should be set high. */ #define MEM_SIZE 10240 /* MEMP_NUM_PBUF: the number of memp struct pbufs. If the application sends a lot of data out of ROM (or other static memory), this should be set high. */ #define MEMP_NUM_PBUF 16 /* MEMP_NUM_RAW_PCB: the number of UDP protocol control blocks. One per active RAW "connection". */ #define MEMP_NUM_RAW_PCB 3 /* MEMP_NUM_UDP_PCB: the number of UDP protocol control blocks. One per active UDP "connection". */ #define MEMP_NUM_UDP_PCB 4 /* MEMP_NUM_TCP_PCB: the number of simulatenously active TCP connections. */ #define MEMP_NUM_TCP_PCB 5 /* MEMP_NUM_TCP_PCB_LISTEN: the number of listening TCP connections. */ #define MEMP_NUM_TCP_PCB_LISTEN 8 /* MEMP_NUM_TCP_SEG: the number of simultaneously queued TCP segments. */ #define MEMP_NUM_TCP_SEG 16 /* MEMP_NUM_SYS_TIMEOUT: the number of simulateously active timeouts. */ #define MEMP_NUM_SYS_TIMEOUT 15 /* The following four are used only with the sequential API and can be set to 0 if the application only will use the raw API. */ /* MEMP_NUM_NETBUF: the number of struct netbufs. */ #define MEMP_NUM_NETBUF 2 /* MEMP_NUM_NETCONN: the number of struct netconns. */ #define MEMP_NUM_NETCONN 10 /* MEMP_NUM_TCPIP_MSG_*: the number of struct tcpip_msg, which is used for sequential API communication and incoming packets. Used in src/api/tcpip.c. */ #define MEMP_NUM_TCPIP_MSG_API 16 #define MEMP_NUM_TCPIP_MSG_INPKT 16 /* ---------- Pbuf options ---------- */ /* PBUF_POOL_SIZE: the number of buffers in the pbuf pool. */ #define PBUF_POOL_SIZE 120 /* PBUF_POOL_BUFSIZE: the size of each pbuf in the pbuf pool. */ #define PBUF_POOL_BUFSIZE 128 /* PBUF_LINK_HLEN: the number of bytes that should be allocated for a link level header. */ #define PBUF_LINK_HLEN 16 /** SYS_LIGHTWEIGHT_PROT * define SYS_LIGHTWEIGHT_PROT in lwipopts.h if you want inter-task protection * for certain critical regions during buffer allocation, deallocation and memory * allocation and deallocation. */ #define SYS_LIGHTWEIGHT_PROT (NO_SYS==0) /* ---------- TCP options ---------- */ #define LWIP_TCP 1 #define TCP_TTL 255 /* Controls if TCP should queue segments that arrive out of order. Define to 0 if your device is low on memory. */ #define TCP_QUEUE_OOSEQ 1 /* TCP Maximum segment size. */ #define TCP_MSS 1024 /* TCP sender buffer space (bytes). */ #define TCP_SND_BUF 2048 /* TCP sender buffer space (pbufs). This must be at least = 2 * TCP_SND_BUF/TCP_MSS for things to work. */ #define TCP_SND_QUEUELEN (4 * TCP_SND_BUF/TCP_MSS) /* TCP writable space (bytes). This must be less than or equal to TCP_SND_BUF. It is the amount of space which must be available in the tcp snd_buf for select to return writable */ #define TCP_SNDLOWAT (TCP_SND_BUF/2) /* TCP receive window. */ #define TCP_WND 8096 /* Maximum number of retransmissions of data segments. */ #define TCP_MAXRTX 12 /* Maximum number of retransmissions of SYN segments. */ #define TCP_SYNMAXRTX 4 /* ---------- ARP options ---------- */ #define LWIP_ARP 1 #define ARP_TABLE_SIZE 10 #define ARP_QUEUEING 1 /* ---------- IP options ---------- */ /* Define IP_FORWARD to 1 if you wish to have the ability to forward IP packets across network interfaces. If you are going to run lwIP on a device with only one network interface, define this to 0. */ #define IP_FORWARD 1 /* IP reassembly and segmentation.These are orthogonal even * if they both deal with IP fragments */ #define IP_REASSEMBLY 1 #define IP_REASS_MAX_PBUFS 10 #define MEMP_NUM_REASSDATA 10 #define IP_FRAG 1 /* ---------- ICMP options ---------- */ #define ICMP_TTL 255 /* ---------- DHCP options ---------- */ /* Define LWIP_DHCP to 1 if you want DHCP configuration of interfaces. */ #define LWIP_DHCP 0 /* 1 if you want to do an ARP check on the offered address (recommended). */ #define DHCP_DOES_ARP_CHECK (LWIP_DHCP) /* ---------- AUTOIP options ------- */ #define LWIP_AUTOIP 0 #define LWIP_DHCP_AUTOIP_COOP (LWIP_DHCP && LWIP_AUTOIP) /* ---------- UDP options ---------- */ #define LWIP_UDP 1 #define LWIP_UDPLITE 1 #define UDP_TTL 255 /* ---------- Statistics options ---------- */ #define LWIP_STATS 1 #define LWIP_STATS_DISPLAY 1 #if LWIP_STATS #define LINK_STATS 1 #define IP_STATS 1 #define ICMP_STATS 1 #define IGMP_STATS 1 #define IPFRAG_STATS 1 #define UDP_STATS 1 #define TCP_STATS 1 #define MEM_STATS 1 #define MEMP_STATS 1 #define PBUF_STATS 1 #define SYS_STATS 1 #endif /* LWIP_STATS */ /* ---------- PPP options ---------- */ #define PPP_SUPPORT 0 /* Set > 0 for PPP */ #if PPP_SUPPORT #define NUM_PPP 1 /* Max PPP sessions. */ /* Select modules to enable. Ideally these would be set in the makefile but * we're limited by the command line length so you need to modify the settings * in this file. */ #define PPPOE_SUPPORT 1 #define PPPOS_SUPPORT 1 #define PAP_SUPPORT 1 /* Set > 0 for PAP. */ #define CHAP_SUPPORT 1 /* Set > 0 for CHAP. */ #define MSCHAP_SUPPORT 0 /* Set > 0 for MSCHAP (NOT FUNCTIONAL!) */ #define CBCP_SUPPORT 0 /* Set > 0 for CBCP (NOT FUNCTIONAL!) */ #define CCP_SUPPORT 0 /* Set > 0 for CCP (NOT FUNCTIONAL!) */ #define VJ_SUPPORT 1 /* Set > 0 for VJ header compression. */ #define MD5_SUPPORT 1 /* Set > 0 for MD5 (see also CHAP) */ #endif /* PPP_SUPPORT */ #endif /* LWIP_LWIPOPTS_H */ ocproxy-1.60/contrib/ports/win32/lwipcfg_msvc.h.example000066400000000000000000000053401303453231400232020ustar00rootroot00000000000000/** * Additional settings for the win32 port. * Copy this to lwipcfg_msvc.h and make the config changes you need. */ /* configuration for this port */ #define PPP_USERNAME "Admin" #define PPP_PASSWORD "pass" /** Define this to the index of the windows network adapter to use */ #define PACKET_LIB_ADAPTER_NR 1 /** Define this to the GUID of the windows network adapter to use * or NOT define this if you want PACKET_LIB_ADAPTER_NR to be used */ /*#define PACKET_LIB_ADAPTER_GUID "00000000-0000-0000-0000-000000000000"*/ /*#define PACKET_LIB_GET_ADAPTER_NETADDRESS(addr) IP4_ADDR((addr), 192,168,1,0)*/ /*#define PACKET_LIB_QUIET*/ /* If these 2 are not defined, the corresponding config setting is used */ /* #define USE_DHCP 0 */ /* #define USE_AUTOIP 0 */ /* #define USE_PCAPIF 1 */ #define LWIP_PORT_INIT_IPADDR(addr) IP4_ADDR((addr), 192,168,1,200) #define LWIP_PORT_INIT_GW(addr) IP4_ADDR((addr), 192,168,1,1) #define LWIP_PORT_INIT_NETMASK(addr) IP4_ADDR((addr), 255,255,255,0) /* remember to change this MAC address to suit your needs! the last octet will be increased by netif->num for each netif */ #define LWIP_MAC_ADDR_BASE {0x00,0x01,0x02,0x03,0x04,0x05} /* #define USE_SLIPIF 0 */ /* #define SIO_USE_COMPORT 0 */ #ifdef USE_SLIPIF #if USE_SLIPIF #define LWIP_PORT_INIT_SLIP1_IPADDR(addr) IP4_ADDR((addr), 192, 168, 2, 2) #define LWIP_PORT_INIT_SLIP1_GW(addr) IP4_ADDR((addr), 192, 168, 2, 1) #define LWIP_PORT_INIT_SLIP1_NETMASK(addr) IP4_ADDR((addr), 255, 255, 255, 0) #if USE_SLIPIF > 1 #define LWIP_PORT_INIT_SLIP2_IPADDR(addr) IP4_ADDR((addr), 192, 168, 2, 1) #define LWIP_PORT_INIT_SLIP2_GW(addr) IP4_ADDR((addr), 0, 0, 0, 0) #define LWIP_PORT_INIT_SLIP2_NETMASK(addr) IP4_ADDR((addr), 255, 255, 255, 0)*/ #endif /* USE_SLIPIF > 1 */ #endif /* USE_SLIPIF */ #endif /* USE_SLIPIF */ /* configuration for applications */ #define LWIP_CHARGEN_APP 0 #define LWIP_DNS_APP 0 #define LWIP_HTTPD_APP 0 /* Set this to 1 to use the netconn http server, * otherwise the raw api server will be used. */ /*#define LWIP_HTTPD_APP_NETCONN */ #define LWIP_NETBIOS_APP 0 #define LWIP_NETIO_APP 0 #define LWIP_PING_APP 0 #define LWIP_RTP_APP 0 #define LWIP_SHELL_APP 0 #define LWIP_SNTP_APP 0 #define LWIP_SOCKET_EXAMPLES_APP 0 #define LWIP_TCPECHO_APP 0 /* Set this to 1 to use the netconn tcpecho server, * otherwise the raw api server will be used. */ /*#define LWIP_TCPECHO_APP_NETCONN */ #define LWIP_UDPECHO_APP 0 /* define this to your custom application-init function */ /* #define LWIP_APP_INIT my_app_init() */ ocproxy-1.60/contrib/ports/win32/lwippools.h000066400000000000000000000012071303453231400211130ustar00rootroot00000000000000/* OPTIONAL: Pools to replace heap allocation * Optional: Pools can be used instead of the heap for mem_malloc. If * so, these should be defined here, in increasing order according to * the pool element size. * * LWIP_MALLOC_MEMPOOL(number_elements, element_size) */ #if MEM_USE_POOLS LWIP_MALLOC_MEMPOOL_START LWIP_MALLOC_MEMPOOL(100, 256) LWIP_MALLOC_MEMPOOL(50, 512) LWIP_MALLOC_MEMPOOL(20, 1024) LWIP_MALLOC_MEMPOOL(20, 1536) LWIP_MALLOC_MEMPOOL_END #endif /* MEM_USE_POOLS */ /* Optional: Your custom pools can go here if you would like to use * lwIP's memory pools for anything else. */ LWIP_MEMPOOL(SYS_MBOX, 22, 100, "SYS_MBOX") ocproxy-1.60/contrib/ports/win32/msvc8/000077500000000000000000000000001303453231400177525ustar00rootroot00000000000000ocproxy-1.60/contrib/ports/win32/msvc8/libcheck.vcproj000066400000000000000000000110651303453231400227460ustar00rootroot00000000000000 ocproxy-1.60/contrib/ports/win32/msvc8/lwIP.vcproj000066400000000000000000000640451303453231400220630ustar00rootroot00000000000000 ocproxy-1.60/contrib/ports/win32/msvc8/lwIP_Test.sln000066400000000000000000000050401303453231400223410ustar00rootroot00000000000000Microsoft Visual Studio Solution File, Format Version 9.00 # Visual C++ Express 2005 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lwIP_test", "lwIP_Test.vcproj", "{8CC0CE51-32CF-4585-BFAF-A9343BC5A96D}" ProjectSection(ProjectDependencies) = postProject {6F44E49E-9F21-4144-91EC-53B92AEF62CE} = {6F44E49E-9F21-4144-91EC-53B92AEF62CE} {2CC276FA-B226-49C9-8F82-7FCD5A228E28} = {2CC276FA-B226-49C9-8F82-7FCD5A228E28} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lwIP pcapif", "lwIP_pcapif.vcproj", "{6F44E49E-9F21-4144-91EC-53B92AEF62CE}" ProjectSection(ProjectDependencies) = postProject {2CC276FA-B226-49C9-8F82-7FCD5A228E28} = {2CC276FA-B226-49C9-8F82-7FCD5A228E28} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lwIP", "lwIP.vcproj", "{2CC276FA-B226-49C9-8F82-7FCD5A228E28}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "makefsdata", "makefsdata.vcproj", "{0BFC0F21-8E84-4E68-A9E1-CE2A09B72F6D}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 Release|Win32 = Release|Win32 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {8CC0CE51-32CF-4585-BFAF-A9343BC5A96D}.Debug|Win32.ActiveCfg = Debug|Win32 {8CC0CE51-32CF-4585-BFAF-A9343BC5A96D}.Debug|Win32.Build.0 = Debug|Win32 {8CC0CE51-32CF-4585-BFAF-A9343BC5A96D}.Release|Win32.ActiveCfg = Release|Win32 {8CC0CE51-32CF-4585-BFAF-A9343BC5A96D}.Release|Win32.Build.0 = Release|Win32 {6F44E49E-9F21-4144-91EC-53B92AEF62CE}.Debug|Win32.ActiveCfg = Debug|Win32 {6F44E49E-9F21-4144-91EC-53B92AEF62CE}.Debug|Win32.Build.0 = Debug|Win32 {6F44E49E-9F21-4144-91EC-53B92AEF62CE}.Release|Win32.ActiveCfg = Release|Win32 {6F44E49E-9F21-4144-91EC-53B92AEF62CE}.Release|Win32.Build.0 = Release|Win32 {2CC276FA-B226-49C9-8F82-7FCD5A228E28}.Debug|Win32.ActiveCfg = Debug|Win32 {2CC276FA-B226-49C9-8F82-7FCD5A228E28}.Debug|Win32.Build.0 = Debug|Win32 {2CC276FA-B226-49C9-8F82-7FCD5A228E28}.Release|Win32.ActiveCfg = Release|Win32 {2CC276FA-B226-49C9-8F82-7FCD5A228E28}.Release|Win32.Build.0 = Release|Win32 {0BFC0F21-8E84-4E68-A9E1-CE2A09B72F6D}.Debug|Win32.ActiveCfg = Debug|Win32 {0BFC0F21-8E84-4E68-A9E1-CE2A09B72F6D}.Debug|Win32.Build.0 = Debug|Win32 {0BFC0F21-8E84-4E68-A9E1-CE2A09B72F6D}.Release|Win32.ActiveCfg = Release|Win32 {0BFC0F21-8E84-4E68-A9E1-CE2A09B72F6D}.Release|Win32.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection EndGlobal ocproxy-1.60/contrib/ports/win32/msvc8/lwIP_Test.vcproj000066400000000000000000000205461303453231400230600ustar00rootroot00000000000000 ocproxy-1.60/contrib/ports/win32/msvc8/lwIP_pcapif.vcproj000066400000000000000000000102131303453231400233710ustar00rootroot00000000000000 ocproxy-1.60/contrib/ports/win32/msvc8/lwIP_unittests.sln000066400000000000000000000037541303453231400234760ustar00rootroot00000000000000Microsoft Visual Studio Solution File, Format Version 9.00 # Visual Studio 2005 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lwip_unittests", "lwip_unittests.vcproj", "{6CCABAA4-F86F-4119-AFF8-43C9A4A234C2}" ProjectSection(ProjectDependencies) = postProject {EBB156DC-01BF-47B2-B69C-1A750B6B5F09} = {EBB156DC-01BF-47B2-B69C-1A750B6B5F09} {2CC276FA-B226-49C9-8F82-7FCD5A228E28} = {2CC276FA-B226-49C9-8F82-7FCD5A228E28} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lwIP", "lwIP.vcproj", "{2CC276FA-B226-49C9-8F82-7FCD5A228E28}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libcheck", "libcheck.vcproj", "{EBB156DC-01BF-47B2-B69C-1A750B6B5F09}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 Release|Win32 = Release|Win32 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {2CC276FA-B226-49C9-8F82-7FCD5A228E28}.Debug|Win32.ActiveCfg = Debug unittests|Win32 {2CC276FA-B226-49C9-8F82-7FCD5A228E28}.Debug|Win32.Build.0 = Debug unittests|Win32 {2CC276FA-B226-49C9-8F82-7FCD5A228E28}.Release|Win32.ActiveCfg = Release unittests|Win32 {2CC276FA-B226-49C9-8F82-7FCD5A228E28}.Release|Win32.Build.0 = Release unittests|Win32 {EBB156DC-01BF-47B2-B69C-1A750B6B5F09}.Debug|Win32.ActiveCfg = Debug|Win32 {EBB156DC-01BF-47B2-B69C-1A750B6B5F09}.Debug|Win32.Build.0 = Debug|Win32 {EBB156DC-01BF-47B2-B69C-1A750B6B5F09}.Release|Win32.ActiveCfg = Release|Win32 {EBB156DC-01BF-47B2-B69C-1A750B6B5F09}.Release|Win32.Build.0 = Release|Win32 {6CCABAA4-F86F-4119-AFF8-43C9A4A234C2}.Debug|Win32.ActiveCfg = Debug|Win32 {6CCABAA4-F86F-4119-AFF8-43C9A4A234C2}.Debug|Win32.Build.0 = Debug|Win32 {6CCABAA4-F86F-4119-AFF8-43C9A4A234C2}.Release|Win32.ActiveCfg = Release|Win32 {6CCABAA4-F86F-4119-AFF8-43C9A4A234C2}.Release|Win32.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection EndGlobal ocproxy-1.60/contrib/ports/win32/msvc8/lwip_unittests.vcproj000066400000000000000000000127461303453231400243060ustar00rootroot00000000000000 ocproxy-1.60/contrib/ports/win32/msvc8/makefsdata.vcproj000066400000000000000000000073751303453231400233130ustar00rootroot00000000000000 ocproxy-1.60/contrib/ports/win32/msvc8/readme.txt000066400000000000000000000022771303453231400217600ustar00rootroot00000000000000lwIP for Win32 This is a quickly hacked port and example project of the lwIP library to Win32/MSVC9. It doesn't (yet?) include support for dhcp, autoip, slipif, ppp or pppoe. This is simply because none of the active developers using this port are using these interfaces right now. To get this compiling, you have to set a couple of environment variables: - LWIP_DIR: points to the main lwip tree (the folder where is the CHANGELOG file). - PCAP_DIR: points to the WinPcap Developer's Packs (containing 'include' and 'lib') You also will have to copy the file 'lwipcfg_msvc.h.example' to 'lwipcfg_msvc.h' and modify to suit your needs (WinPcap adapter number, IP configuration, applications...). Note that you also have to set the PCAP_DIR environment variable to point to the WinPcap Developer's Packs (containing 'include' and 'lib'). Included in the contrib\ports\win32 directory is the network interface driver using the winpcap library. lwIP: http://savannah.nongnu.org/projects/lwip/ WinPCap: http://netgroup-serv.polito.it/winpcap/ To compile the unittests, download check (tested with v0.9.8) from http://sourceforge.net/projects/check/ and place it in a folder "check" next to the "contrib" folder.ocproxy-1.60/contrib/ports/win32/pcapif.c000066400000000000000000000602141303453231400203230ustar00rootroot00000000000000/** * pcapif.c - This file is part of lwIP pcapif * **************************************************************************** * * This file is derived from an example in lwIP with the following license: * * Copyright (c) 2001, Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the Institute nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #include #include #include "pcap.h" #include "lwip/opt.h" #if LWIP_ETHERNET /* @todo: once moved to the correct place, this should be unconditional! */ #ifdef _MSC_VER #include "pcapif.h" #else #include "netif/pcapif.h" #endif #include #include #include #include "lwip/debug.h" #include "lwip/def.h" #include "lwip/mem.h" #include "lwip/pbuf.h" #include "lwip/stats.h" #include "lwip/sys.h" #include "lwip/ip.h" #include "lwip/snmp.h" #include "lwip/tcpip.h" #include "lwip/timers.h" #include "lwip/ethip6.h" #include "netif/etharp.h" /* include the port-dependent configuration */ #include "lwipcfg_msvc.h" /* For compatibility with old pcap */ #ifndef PCAP_OPENFLAG_PROMISCUOUS #define PCAP_OPENFLAG_PROMISCUOUS 1 #endif /* Define those to better describe your network interface. For now, we use 'e0', 'e1', 'e2' and so on */ #define IFNAME0 'e' #define IFNAME1 '0' /** index of the network adapter to use for lwIP */ #ifndef PACKET_LIB_ADAPTER_NR #define PACKET_LIB_ADAPTER_NR 0 #endif /** If 1, check link state and report it to lwIP. * If 0, don't check link state (lwIP link state is always UP). */ #ifndef PCAPIF_HANDLE_LINKSTATE #define PCAPIF_HANDLE_LINKSTATE 1 #endif #if PCAPIF_HANDLE_LINKSTATE #include "pcapif_helper.h" /* Define "PHY" delay when "link up" */ #ifndef PCAPIF_LINKUP_DELAY #define PCAPIF_LINKUP_DELAY 0 #endif #define PCAPIF_LINKCHECK_INTERVAL_MS 500 /* link state notification macro */ #if PCAPIF_LINKUP_DELAY #define PCAPIF_NOTIFY_LINKSTATE(netif, linkfunc) sys_timeout(PCAPIF_LINKUP_DELAY, (sys_timeout_handler)linkfunc, netif) #else /* PHY_LINKUP_DELAY */ #define PCAPIF_NOTIFY_LINKSTATE(netif, linkfunc) linkfunc(netif) #endif /* PHY_LINKUP_DELAY */ #endif /* PCAPIF_HANDLE_LINKSTATE */ #define ADAPTER_NAME_LEN 128 #define ADAPTER_DESC_LEN 128 /* Packet Adapter informations */ struct pcapif_private { void *input_fn_arg; pcap_t *adapter; char name[ADAPTER_NAME_LEN]; char description[ADAPTER_DESC_LEN]; int shutdown_called; #if PCAPIF_RX_USE_THREAD volatile int rx_run; volatile int rx_running; #endif /* PCAPIF_RX_USE_THREAD */ #if PCAPIF_HANDLE_LINKSTATE struct pcapifh_linkstate *link_state; enum pcapifh_link_event last_link_event; #endif /* PCAPIF_HANDLE_LINKSTATE */ }; /* Forward declarations. */ static void pcapif_input(u_char *user, const struct pcap_pkthdr *pkt_header, const u_char *packet); #ifdef PACKET_LIB_GET_ADAPTER_NETADDRESS /** Get the index of an adapter by its network address * * @param netaddr network address of the adapter (e.g. 192.168.1.0) * @return index of the adapter or negative on error */ static int get_adapter_index_from_addr(struct in_addr *netaddr, char *guid, size_t guid_len) { pcap_if_t *alldevs; pcap_if_t *d; char errbuf[PCAP_ERRBUF_SIZE+1]; int index = 0; memset(guid, 0, guid_len); /* Retrieve the interfaces list */ if (pcap_findalldevs(&alldevs, errbuf) == -1) { printf("Error in pcap_findalldevs: %s\n", errbuf); return -1; } /* Scan the list printing every entry */ for (d = alldevs; d != NULL; d = d->next, index++) { pcap_addr_t *a; for(a = d->addresses; a != NULL; a = a->next) { if (a->addr->sa_family == AF_INET) { ULONG a_addr = ((struct sockaddr_in *)a->addr)->sin_addr.s_addr; ULONG a_netmask = ((struct sockaddr_in *)a->netmask)->sin_addr.s_addr; ULONG a_netaddr = a_addr & a_netmask; ULONG addr = (*netaddr).s_addr; if (a_netaddr == addr) { int ret = -1; char name[128]; char *start, *end; size_t len = strlen(d->name); if(len > 127) { len = 127; } memcpy(name, d->name, len); name[len] = 0; start = strstr(name, "{"); if (start != NULL) { end = strstr(start, "}"); if (end != NULL) { size_t len = end - start + 1; memcpy(guid, start, len); ret = index; } } pcap_freealldevs(alldevs); return ret; } } } } printf("Network address not found.\n"); pcap_freealldevs(alldevs); return -1; } #endif /* PACKET_LIB_GET_ADAPTER_NETADDRESS */ #if defined(PACKET_LIB_GET_ADAPTER_NETADDRESS) || defined(PACKET_LIB_ADAPTER_GUID) /** Get the index of an adapter by its GUID * * @param adapter_guid GUID of the adapter * @return index of the adapter or negative on error */ static int get_adapter_index(const char* adapter_guid) { pcap_if_t *alldevs; pcap_if_t *d; char errbuf[PCAP_ERRBUF_SIZE+1]; int idx = 0; /* Retrieve the interfaces list */ if (pcap_findalldevs(&alldevs, errbuf) == -1) { printf("Error in pcap_findalldevs: %s\n", errbuf); return -1; } /* Scan the list and compare name vs. adapter_guid */ for (d = alldevs; d != NULL; d = d->next, idx++) { if(strstr(d->name, adapter_guid)) { pcap_freealldevs(alldevs); return idx; } } /* not found, dump all adapters */ printf("%d available adapters:\n", idx); for (d = alldevs, idx = 0; d != NULL; d = d->next, idx++) { printf("- %d: %s\n", idx, d->name); } pcap_freealldevs(alldevs); return -1; } #endif /* defined(PACKET_LIB_GET_ADAPTER_NETADDRESS) || defined(PACKET_LIB_ADAPTER_GUID) */ /** * Open a network adapter and set it up for packet input * * @param adapter_num the index of the adapter to use * @param arg argument to pass to input * @return an adapter handle on success, NULL on failure */ static struct pcapif_private* pcapif_init_adapter(int adapter_num, void *arg) { int i; int number_of_adapters; struct pcapif_private *pa; char errbuf[PCAP_ERRBUF_SIZE+1]; pcap_if_t *alldevs; pcap_if_t *d; pcap_if_t *used_adapter = NULL; pa = (struct pcapif_private *)malloc(sizeof(struct pcapif_private)); if (!pa) { printf("Unable to alloc the adapter!\n"); return NULL; } memset(pa, 0, sizeof(struct pcapif_private)); pa->input_fn_arg = arg; /* Retrieve the interfaces list */ if (pcap_findalldevs(&alldevs, errbuf) == -1) { free(pa); return NULL; /* no adapters found */ } /* get number of adatpers and adapter pointer */ for (d = alldevs, number_of_adapters = 0; d != NULL; d = d->next, number_of_adapters++) { if (number_of_adapters == adapter_num) { char *desc = d->description; size_t len; len = strlen(d->name); LWIP_ASSERT("len < ADAPTER_NAME_LEN", len < ADAPTER_NAME_LEN); strcpy(pa->name, d->name); used_adapter = d; /* format vendor description */ if (desc != NULL) { len = strlen(desc); if (strstr(desc, " ' on local host") != NULL) { len -= 16; } else if (strstr(desc, "' on local host") != NULL) { len -= 15; } if (strstr(desc, "Network adapter '") == desc) { len -= 17; desc += 17; } len = LWIP_MIN(len, ADAPTER_DESC_LEN-1); while ((desc[len-1] == ' ') || (desc[len-1] == '\t')) { /* don't copy trailing whitespace */ len--; } strncpy(pa->description, desc, len); pa->description[len] = 0; } else { strcpy(pa->description, ""); } } } #ifndef PCAPIF_LIB_QUIET /* Scan the list printing every entry */ for (d = alldevs, i = 0; d != NULL; d = d->next, i++) { char *desc = d->description; char descBuf[128]; size_t len; const char* devname = d->name; if (d->name == NULL) { devname = ""; } else { if (strstr(devname, "\\Device\\") == devname) { /* windows: strip the first part */ devname += 8; } } printf("%2i: %s\n", i, devname); if (desc != NULL) { /* format vendor description */ len = strlen(desc); if (strstr(desc, " ' on local host") != NULL) { len -= 16; } else if (strstr(desc, "' on local host") != NULL) { len -= 15; } if (strstr(desc, "Network adapter '") == desc) { len -= 17; desc += 17; } len = LWIP_MIN(len, 127); while ((desc[len-1] == ' ') || (desc[len-1] == '\t')) { /* don't copy trailing whitespace */ len--; } strncpy(descBuf, desc, len); descBuf[len] = 0; printf(" Desc: \"%s\"\n", descBuf); } } #endif /* PCAPIF_LIB_QUIET */ /* invalid adapter index -> check this after printing the adapters */ if (adapter_num < 0) { printf("Invalid adapter_num: %d\n", adapter_num); free(pa); pcap_freealldevs(alldevs); return NULL; } /* adapter index out of range */ if (adapter_num >= number_of_adapters) { printf("Invalid adapter_num: %d\n", adapter_num); free(pa); pcap_freealldevs(alldevs); return NULL; } #ifndef PCAPIF_LIB_QUIET printf("Using adapter_num: %d\n", adapter_num); #endif /* PCAPIF_LIB_QUIET */ /* set up the selected adapter */ LWIP_ASSERT("used_adapter != NULL", used_adapter != NULL); /* Open the device */ pa->adapter = pcap_open_live(used_adapter->name,/* name of the device */ 65536, /* portion of the packet to capture */ /* 65536 guarantees that the whole packet will be captured on all the link layers */ PCAP_OPENFLAG_PROMISCUOUS,/* promiscuous mode */ #if PCAPIF_RX_USE_THREAD /*-*/1, /* don't wait at all for lower latency */ #else 1, /* wait 1 ms in ethernetif_poll */ #endif errbuf); /* error buffer */ if (pa->adapter == NULL) { printf("\nUnable to open the adapter. %s is not supported by WinPcap\n", used_adapter->name); /* Free the device list */ pcap_freealldevs(alldevs); free(pa); return NULL; } printf("Using adapter: \"%s\"\n", pa->description); pcap_freealldevs(alldevs); #if PCAPIF_HANDLE_LINKSTATE pa->link_state = pcapifh_linkstate_init(pa->name); pa->last_link_event = PCAPIF_LINKEVENT_UNKNOWN; #endif /* PCAPIF_HANDLE_LINKSTATE */ return pa; } #if PCAPIF_HANDLE_LINKSTATE void pcapif_check_linkstate(void *netif_ptr) { struct netif *netif = (struct netif*)netif_ptr; struct pcapif_private *pa = (struct pcapif_private*)netif->state; enum pcapifh_link_event le; le = pcapifh_linkstate_get(pa->link_state); if (pa->last_link_event != le) { pa->last_link_event = le; switch (le) { case PCAPIF_LINKEVENT_UP: { PCAPIF_NOTIFY_LINKSTATE(netif, netif_set_link_up); break; } case PCAPIF_LINKEVENT_DOWN: { PCAPIF_NOTIFY_LINKSTATE(netif, netif_set_link_down); break; } } } sys_timeout(PCAPIF_LINKCHECK_INTERVAL_MS, pcapif_check_linkstate, netif); } #endif /* PCAPIF_HANDLE_LINKSTATE */ /** * Close the adapter (no more packets can be sent or received) * * @param netif netif to shutdown */ void pcapif_shutdown(struct netif *netif) { struct pcapif_private *pa = (struct pcapif_private*)netif->state; if (pa) { #if PCAPIF_RX_USE_THREAD pa->rx_run = 0; #endif /* PCAPIF_RX_USE_THREAD */ if (pa->adapter) { pcap_breakloop(pa->adapter); pcap_close(pa->adapter); } #if PCAPIF_RX_USE_THREAD /* wait for rxthread to end */ while(pa->rx_running); #endif /* PCAPIF_RX_USE_THREAD */ #if PCAPIF_HANDLE_LINKSTATE pcapifh_linkstate_close(pa->link_state); #endif /* PCAPIF_HANDLE_LINKSTATE */ free(pa); } } #if PCAPIF_RX_USE_THREAD /** RX running in its own thread */ static void pcapif_input_thread(void *arg) { struct netif *netif = (struct netif *)arg; struct pcapif_private *pa = (struct pcapif_private*)netif->state; do { struct pcap_pkthdr pkt_header; const u_char *packet = pcap_next(pa->adapter, &pkt_header); if(packet != NULL) { pcapif_input((u_char*)pa, &pkt_header, packet); } } while (pa->rx_run); pa->rx_running = 0; } #endif /* PCAPIF_RX_USE_THREAD */ /** Low-level initialization: find the correct adapter and initialize it. */ static void pcapif_low_level_init(struct netif *netif) { u8_t my_mac_addr[ETHARP_HWADDR_LEN] = LWIP_MAC_ADDR_BASE; int adapter_num = PACKET_LIB_ADAPTER_NR; struct pcapif_private *pa; /* If 'state' is != NULL at this point, we assume it is an 'int' giving the index of the adapter to use (+ 1 because 0==NULL is invalid). This can be used to instantiate multiple PCAP drivers. */ if (netif->state != NULL) { adapter_num = ((int)netif->state) - 1; if (adapter_num < 0) { printf("ERROR: invalid adapter index \"%d\"!\n", adapter_num); LWIP_ASSERT("ERROR initializing network adapter!\n", 0); return; } } #ifdef PACKET_LIB_GET_ADAPTER_NETADDRESS ip_addr_t netaddr; #define GUID_LEN 128 char guid[GUID_LEN + 1]; memset(&guid, 0, sizeof(guid)); PACKET_LIB_GET_ADAPTER_NETADDRESS(&netaddr); if (get_adapter_index_from_addr((struct in_addr *)&netaddr, guid, GUID_LEN) < 0) { printf("ERROR initializing network adapter, failed to get GUID for network address %s\n", ip_ntoa(&netaddr)); LWIP_ASSERT("ERROR initializing network adapter, failed to get GUID for network address!", 0); return; } adapter_num = get_adapter_index(guid); if (adapter_num < 0) { printf("ERROR finding network adapter with GUID \"%s\"!\n", guid); LWIP_ASSERT("ERROR finding network adapter with expected GUID!", 0); return; } #else /* PACKET_LIB_GET_ADAPTER_NETADDRESS */ #ifdef PACKET_LIB_ADAPTER_GUID /* get adapter index for guid string */ adapter_num = get_adapter_index(PACKET_LIB_ADAPTER_GUID); if (adapter_num < 0) { printf("ERROR finding network adapter with GUID \"%s\"!\n", PACKET_LIB_ADAPTER_GUID); LWIP_ASSERT("ERROR initializing network adapter!\n", 0); return; } #endif /* PACKET_LIB_ADAPTER_GUID */ #endif /* PACKET_LIB_GET_ADAPTER_NETADDRESS */ /* Do whatever else is needed to initialize interface. */ pa = pcapif_init_adapter(adapter_num, netif); if (pa == NULL) { printf("ERROR initializing network adapter %d!\n", adapter_num); LWIP_ASSERT("ERROR initializing network adapter!", 0); return; } netif->state = pa; /* change the MAC address to a unique value so that multiple ethernetifs are supported */ /* @todo: this does NOT support multiple processes using this adapter! */ my_mac_addr[ETHARP_HWADDR_LEN - 1] += netif->num; /* Copy MAC addr */ memcpy(&netif->hwaddr, my_mac_addr, ETHARP_HWADDR_LEN); /* get the initial link state of the selected interface */ #if PCAPIF_HANDLE_LINKSTATE pa->last_link_event = pcapifh_linkstate_get(pa->link_state); if (pa->last_link_event == PCAPIF_LINKEVENT_DOWN) { netif_set_link_down(netif); } else { netif_set_link_up(netif); } sys_timeout(PCAPIF_LINKCHECK_INTERVAL_MS, pcapif_check_linkstate, netif); #endif /* PCAPIF_HANDLE_LINKSTATE */ #if PCAPIF_RX_USE_THREAD pa->rx_run = 1; pa->rx_running = 1; sys_thread_new("pcapif_rxthread", pcapif_input_thread, netif, 0, 0); #endif LWIP_DEBUGF(NETIF_DEBUG, ("pcapif: eth_addr %02X%02X%02X%02X%02X%02X\n",netif->hwaddr[0],netif->hwaddr[1],netif->hwaddr[2],netif->hwaddr[3],netif->hwaddr[4],netif->hwaddr[5])); } /** low_level_output(): * Transmit a packet. The packet is contained in the pbuf that is passed to * the function. This pbuf might be chained. */ static err_t pcapif_low_level_output(struct netif *netif, struct pbuf *p) { struct pbuf *q; unsigned char buffer[1520]; unsigned char *buf = buffer; unsigned char *ptr; struct eth_hdr *ethhdr; u16_t tot_len = p->tot_len - ETH_PAD_SIZE; struct pcapif_private *pa = (struct pcapif_private*)netif->state; #if defined(LWIP_DEBUG) && LWIP_NETIF_TX_SINGLE_PBUF LWIP_ASSERT("p->next == NULL && p->len == p->tot_len", p->next == NULL && p->len == p->tot_len); #endif /* initiate transfer */ if (p->len == p->tot_len) { /* no pbuf chain, don't have to copy -> faster */ buf = &((unsigned char*)p->payload)[ETH_PAD_SIZE]; } else { /* pbuf chain, copy into contiguous buffer */ if (p->tot_len >= sizeof(buffer)) { LINK_STATS_INC(link.lenerr); LINK_STATS_INC(link.drop); snmp_inc_ifoutdiscards(netif); return ERR_BUF; } ptr = buffer; for(q = p; q != NULL; q = q->next) { /* Send the data from the pbuf to the interface, one pbuf at a time. The size of the data in each pbuf is kept in the ->len variable. */ /* send data from(q->payload, q->len); */ LWIP_DEBUGF(NETIF_DEBUG, ("netif: send ptr %p q->payload %p q->len %i q->next %p\n", ptr, q->payload, (int)q->len, (void*)q->next)); if (q == p) { memcpy(ptr, &((char*)q->payload)[ETH_PAD_SIZE], q->len - ETH_PAD_SIZE); ptr += q->len - ETH_PAD_SIZE; } else { memcpy(ptr, q->payload, q->len); ptr += q->len; } } } /* signal that packet should be sent */ if (pcap_sendpacket(pa->adapter, buf, tot_len) < 0) { LINK_STATS_INC(link.memerr); LINK_STATS_INC(link.drop); snmp_inc_ifoutdiscards(netif); return ERR_BUF; } LINK_STATS_INC(link.xmit); snmp_add_ifoutoctets(netif, tot_len); ethhdr = (struct eth_hdr *)p->payload; if ((ethhdr->dest.addr[0] & 1) != 0) { /* broadcast or multicast packet*/ snmp_inc_ifoutnucastpkts(netif); } else { /* unicast packet */ snmp_inc_ifoutucastpkts(netif); } return ERR_OK; } /** low_level_input(): Allocate a pbuf and transfer the bytes of the incoming * packet from the interface into the pbuf. */ static struct pbuf * pcapif_low_level_input(struct netif *netif, const void *packet, int packet_len) { struct pbuf *p, *q; int start; int length = packet_len; struct eth_addr *dest = (struct eth_addr*)packet; struct eth_addr *src = dest + 1; int unicast; const u8_t bcast[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; const u8_t ipv4mcast[] = {0x01, 0x00, 0x5e}; const u8_t ipv6mcast[] = {0x33, 0x33}; /* Don't let feedback packets through (limitation in winpcap?) */ if(!memcmp(src, netif->hwaddr, ETHARP_HWADDR_LEN)) { /* don't update counters here! */ return NULL; } /* MAC filter: only let my MAC or non-unicast through (pcap receives loopback traffic, too) */ unicast = ((dest->addr[0] & 0x01) == 0); if (memcmp(dest, &netif->hwaddr, ETHARP_HWADDR_LEN) && (memcmp(dest, ipv4mcast, 3) || ((dest->addr[3] & 0x80) != 0)) && memcmp(dest, ipv6mcast, 2) && memcmp(dest, bcast, 6)) { /* don't update counters here! */ return NULL; } /* We allocate a pbuf chain of pbufs from the pool. */ p = pbuf_alloc(PBUF_RAW, (u16_t)length + ETH_PAD_SIZE, PBUF_POOL); LWIP_DEBUGF(NETIF_DEBUG, ("netif: recv length %i p->tot_len %i\n", length, (int)p->tot_len)); if (p != NULL) { /* We iterate over the pbuf chain until we have read the entire packet into the pbuf. */ start=0; for (q = p; q != NULL; q = q->next) { u16_t copy_len = q->len; /* Read enough bytes to fill this pbuf in the chain. The available data in the pbuf is given by the q->len variable. */ /* read data into(q->payload, q->len); */ LWIP_DEBUGF(NETIF_DEBUG, ("netif: recv start %i length %i q->payload %p q->len %i q->next %p\n", start, length, q->payload, (int)q->len, (void*)q->next)); if (q == p) { #if ETH_PAD_SIZE LWIP_ASSERT("q->len >= ETH_PAD_SIZE", q->len >= ETH_PAD_SIZE); copy_len -= ETH_PAD_SIZE; #endif /* ETH_PAD_SIZE*/ memcpy(&((char*)q->payload)[ETH_PAD_SIZE], &((char*)packet)[start], copy_len); } else { memcpy(q->payload, &((char*)packet)[start], copy_len); } start += copy_len; length -= copy_len; if (length <= 0) { break; } } LINK_STATS_INC(link.recv); snmp_add_ifinoctets(netif, p->tot_len); if (unicast) { snmp_inc_ifinucastpkts(netif); } else { snmp_inc_ifinnucastpkts(netif); } } else { /* drop packet(); */ LINK_STATS_INC(link.memerr); LINK_STATS_INC(link.drop); } return p; } /** pcapif_input: This function is called when a packet is ready to be read * from the interface. It uses the function low_level_input() that should * handle the actual reception of bytes from the network interface. */ static void pcapif_input(u_char *user, const struct pcap_pkthdr *pkt_header, const u_char *packet) { struct pcapif_private *pa = (struct pcapif_private*)user; int packet_len = pkt_header->caplen; struct netif *netif = (struct netif *)pa->input_fn_arg; struct pbuf *p; /* move received packet into a new pbuf */ p = pcapif_low_level_input(netif, packet, packet_len); /* no packet could be read, silently ignore this */ if (p != NULL) { /* pass all packets to ethernet_input, which decides what packets it supports */ if (netif->input(p, netif) != ERR_OK) { LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_input: IP input error\n")); pbuf_free(p); } } } /** * pcapif_init(): initialization function, pass to netif_add(). */ err_t pcapif_init(struct netif *netif) { static int ethernetif_index; int local_index; SYS_ARCH_DECL_PROTECT(lev); SYS_ARCH_PROTECT(lev); local_index = ethernetif_index++; SYS_ARCH_UNPROTECT(lev); netif->name[0] = IFNAME0; netif->name[1] = (char)(IFNAME1 + local_index); netif->linkoutput = pcapif_low_level_output; #if LWIP_ARP netif->output = etharp_output; #if LWIP_IPV6 netif->output_ip6 = ethip6_output; #endif /* LWIP_IPV6 */ #else /* LWIP_ARP */ netif->output = NULL; /* not used for PPPoE */ #if LWIP_IPV6 netif->output_ip6 = NULL; /* not used for PPPoE */ #endif /* LWIP_IPV6 */ #endif /* LWIP_ARP */ #if LWIP_NETIF_HOSTNAME /* Initialize interface hostname */ netif_set_hostname(netif, "lwip"); #endif /* LWIP_NETIF_HOSTNAME */ netif->mtu = 1500; netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_IGMP; netif->hwaddr_len = ETHARP_HWADDR_LEN; NETIF_INIT_SNMP(netif, snmp_ifType_ethernet_csmacd, 100000000); /* sets link up or down based on current status */ pcapif_low_level_init(netif); return ERR_OK; } #if !PCAPIF_RX_USE_THREAD void pcapif_poll(struct netif *netif) { struct pcapif_private *pa = (struct pcapif_private*)netif->state; int ret; do { ret = pcap_dispatch(pa->adapter, -1, pcapif_input, (u_char*)pa); } while(ret > 0); } #endif /* !PCAPIF_RX_USE_THREAD */ #endif /* LWIP_ETHERNET */ ocproxy-1.60/contrib/ports/win32/pcapif.h000066400000000000000000000012441303453231400203260ustar00rootroot00000000000000#ifndef LWIP_PCAPIF_H #define LWIP_PCAPIF_H #ifdef __cplusplus extern "C" { #endif #include "lwip/err.h" /** Set to 1 to let rx use an own thread (only for NO_SYS==0). * If set to 0, ethernetif_poll is used to poll for packets. */ #ifndef PCAPIF_RX_USE_THREAD #define PCAPIF_RX_USE_THREAD !NO_SYS #endif #if PCAPIF_RX_USE_THREAD && NO_SYS #error "Can't create a dedicated RX thread with NO_SYS==1" #endif struct netif; err_t pcapif_init (struct netif *netif); void pcapif_shutdown(struct netif *netif); #if !PCAPIF_RX_USE_THREAD void pcapif_poll (struct netif *netif); #endif /* !PCAPIF_RX_USE_THREAD */ #ifdef __cplusplus } #endif #endif /* LWIP_PCAPIF_H */ ocproxy-1.60/contrib/ports/win32/pcapif_helper.c000066400000000000000000000052361303453231400216650ustar00rootroot00000000000000/** * pcapif_helper.c - This file is part of lwIP pcapif and provides helper functions * for managing the link state. */ #include "pcapif_helper.h" #include #include #ifdef WIN32 #ifdef _MSC_VER #pragma warning (disable: 4201) /* don't warn about union without name */ #endif /* _MSC_VER */ #define WIN32_LEAN_AND_MEAN #include #include #include struct pcapifh_linkstate { LPADAPTER lpAdapter; PPACKET_OID_DATA ppacket_oid_data; }; struct pcapifh_linkstate* pcapifh_linkstate_init(const char *adapter_name) { struct pcapifh_linkstate* state = (struct pcapifh_linkstate*)malloc(sizeof(struct pcapifh_linkstate)); if (state != NULL) { memset(state, 0, sizeof(struct pcapifh_linkstate)); state->ppacket_oid_data = (PPACKET_OID_DATA)malloc(sizeof(PACKET_OID_DATA) + sizeof(NDIS_MEDIA_STATE)); if (state->ppacket_oid_data == NULL) { free(state); state = NULL; } else { state->lpAdapter = PacketOpenAdapter((char*)adapter_name); if ((state->lpAdapter == NULL) || (state->lpAdapter->hFile == INVALID_HANDLE_VALUE)) { /* failed to open adapter */ free(state); state = NULL; } } } return state; } enum pcapifh_link_event pcapifh_linkstate_get(struct pcapifh_linkstate* state) { enum pcapifh_link_event ret = PCAPIF_LINKEVENT_UNKNOWN; if (state != NULL) { state->ppacket_oid_data->Oid = OID_GEN_MEDIA_CONNECT_STATUS; state->ppacket_oid_data->Length = sizeof(NDIS_MEDIA_STATE); if (PacketRequest(state->lpAdapter, FALSE, state->ppacket_oid_data)) { NDIS_MEDIA_STATE fNdisMediaState; fNdisMediaState = (*((PNDIS_MEDIA_STATE)(state->ppacket_oid_data->Data))); ret = ((fNdisMediaState == NdisMediaStateConnected) ? PCAPIF_LINKEVENT_UP : PCAPIF_LINKEVENT_DOWN); } } return ret; } void pcapifh_linkstate_close(struct pcapifh_linkstate* state) { if (state != NULL) { if (state->lpAdapter != NULL) { PacketCloseAdapter(state->lpAdapter); } if (state->ppacket_oid_data != NULL) { free(state->ppacket_oid_data); } free(state); } } #else /* WIN32 */ /* @todo: add linux/unix implementation? */ struct pcapifh_linkstate { u8_t empty; }; struct pcapifh_linkstate* pcapifh_linkstate_init(const char *adapter_name) { LWIP_UNUSED_ARG(adapter_name); return NULL; } enum pcapifh_link_event pcapifh_linkstate_get(struct pcapifh_linkstate* state) { LWIP_UNUSED_ARG(state); LWIP_ASSERT("not implemented", 0); return LINKEVENT_UNKNOWN; } void pcapifh_linkstate_close(struct pcapifh_linkstate* state) { LWIP_UNUSED_ARG(state); LWIP_ASSERT("not implemented", 0); } #endif /* WIN32 */ocproxy-1.60/contrib/ports/win32/pcapif_helper.h000066400000000000000000000010021303453231400216550ustar00rootroot00000000000000#ifndef LWIP_PCAPIF_HELPER_H #define LWIP_PCAPIF_HELPER_H #ifdef __cplusplus extern "C" { #endif struct pcapifh_linkstate; enum pcapifh_link_event { PCAPIF_LINKEVENT_UNKNOWN, PCAPIF_LINKEVENT_UP, PCAPIF_LINKEVENT_DOWN }; struct pcapifh_linkstate* pcapifh_linkstate_init(const char *adapter_name); enum pcapifh_link_event pcapifh_linkstate_get(struct pcapifh_linkstate* state); void pcapifh_linkstate_close(struct pcapifh_linkstate* state); #ifdef __cplusplus } #endif #endif /* LWIP_PCAPIF_HELPER_H */ocproxy-1.60/contrib/ports/win32/readme.txt000066400000000000000000000004421303453231400207100ustar00rootroot00000000000000lwIP for Win32 - MSVC6 compiler, read contrib\ports\win32\msvc6\readme.txt - MSVC8 compiler, read contrib\ports\win32\msvc8\readme.txt lwIP: http://savannah.nongnu.org/projects/lwip/ WinPCap: http://netgroup-serv.polito.it/winpcap/ Visual C++: http://www.microsoft.com/express/download/ ocproxy-1.60/contrib/ports/win32/sio.c000066400000000000000000000220401303453231400176460ustar00rootroot00000000000000/* * Copyright (c) 2001-2003 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * */ #include #include #include #include #include #include #include "lwipcfg_msvc.h" /** When 1, use COM ports, when 0, use named pipes (for simulation). */ #ifndef SIO_USE_COMPORT #define SIO_USE_COMPORT 1 #endif /** If SIO_USE_COMPORT==1, use COMx, if 0, use a pipe (default) */ #if SIO_USE_COMPORT #define SIO_DEVICENAME "\\\\.\\COM" #else #define SIO_DEVICENAME "\\\\.\\pipe\\lwip" #endif #if SIO_USE_COMPORT #ifndef SIO_COMPORT_SPEED #define SIO_COMPORT_SPEED 115200 #endif #ifndef SIO_COMPORT_BYTESIZE #define SIO_COMPORT_BYTESIZE 8 #endif #ifndef SIO_COMPORT_STOPBITS #define SIO_COMPORT_STOPBITS 0 /* ONESTOPBIT */ #endif #ifndef SIO_COMPORT_PARITY #define SIO_COMPORT_PARITY 0 /* NOPARITY */ #endif #endif /* SIO_USE_COMPORT */ static int sio_abort = 0; /* \\.\pipe\lwip0 */ /* pppd /dev/ttyS0 logfile mylog debug nocrtscts local noauth noccp ms-dns 212.27.54.252 192.168.0.4:192.168.0.5 */ /** * SIO_DEBUG: Enable debugging for SIO. */ #ifndef SIO_DEBUG #define SIO_DEBUG LWIP_DBG_OFF #endif #if SIO_USE_COMPORT /** When using a real COM port, set up the * serial line settings (baudrate etc.) */ static BOOL sio_setup(HANDLE fd) { COMMTIMEOUTS cto; DCB dcb; /* set up baudrate and other communication settings */ memset(&dcb, 0, sizeof(dcb)); /* Obtain the DCB structure for the device */ if (!GetCommState(fd, &dcb)) { return FALSE; } /* Set the new data */ dcb.BaudRate = SIO_COMPORT_SPEED; dcb.ByteSize = SIO_COMPORT_BYTESIZE; dcb.StopBits = 0; /* ONESTOPBIT */ dcb.Parity = 0; /* NOPARITY */ dcb.fParity = 0; /* parity is not used */ /* do not use flow control */ /*dcb.fOutxDsrFlow = dcb.fDtrControl = 0; dcb.fOutxCtsFlow = dcb.fRtsControl = 0; dcb.fErrorChar = dcb.fNull = 0; dcb.fInX = dcb.fOutX = 0; dcb.XonChar = dcb.XoffChar = 0; dcb.XonLim = dcb.XoffLim = 100;*/ /* Set the new DCB structure */ if (!SetCommState(fd, &dcb)) { return FALSE; } memset(&cto, 0, sizeof(cto)); if(!GetCommTimeouts(fd, &cto)) { return FALSE; } /* change read timeout, leave write timeout as it is */ cto.ReadIntervalTimeout = 1; cto.ReadTotalTimeoutMultiplier = 0; cto.ReadTotalTimeoutConstant = 1;// 1ms //100; /* 10 ms */ if(!SetCommTimeouts(fd, &cto)) { return FALSE; } return TRUE; } #endif /* SIO_USE_COMPORT */ /** * Opens a serial device for communication. * * @param devnum device number * @return handle to serial device if successful, NULL otherwise */ sio_fd_t sio_open(u8_t devnum) { HANDLE fileHandle = INVALID_HANDLE_VALUE; CHAR fileName[256]; LWIP_DEBUGF(SIO_DEBUG, ("sio_open(%lu)\n", (DWORD)devnum)); #if SIO_USE_COMPORT _snprintf(fileName, 255, SIO_DEVICENAME"%lu", (DWORD)(devnum)); #else /* SIO_USE_COMPORT */ _snprintf(fileName, 255, SIO_DEVICENAME"%lu", (DWORD)(devnum & ~1)); if ((devnum & 1) == 0) { fileHandle = CreateNamedPipe(fileName, PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_NOWAIT, PIPE_UNLIMITED_INSTANCES, 102400, 102400, 100, NULL); } else #endif /* SIO_USE_COMPORT */ { fileHandle = CreateFile(fileName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); } if (fileHandle != INVALID_HANDLE_VALUE) { sio_abort = 0; #if !SIO_USE_COMPORT if (devnum & 1) { DWORD mode = PIPE_NOWAIT; if (!SetNamedPipeHandleState(fileHandle, &mode, NULL, NULL)) { LWIP_DEBUGF(SIO_DEBUG, ("sio_open(%lu): SetNamedPipeHandleState failed. GetLastError() returns %d\n", (DWORD)devnum, GetLastError())); } } else #endif /* !SIO_USE_COMPORT */ { FlushFileBuffers(fileHandle); } #if SIO_USE_COMPORT if(!sio_setup(fileHandle)) { CloseHandle(fileHandle); LWIP_DEBUGF(SIO_DEBUG, ("sio_open(%lu): sio_setup failed. GetLastError() returns %d\n", (DWORD)devnum, GetLastError())); return NULL; } #endif /* SIO_USE_COMPORT */ LWIP_DEBUGF(SIO_DEBUG, ("sio_open: file \"%s\" successfully opened.\n", fileName)); printf("sio_open: file \"%s\" (%lu) successfully opened: 0x%08x\n", fileName, devnum, (u32_t)fileHandle); return (sio_fd_t)(fileHandle); } LWIP_DEBUGF(SIO_DEBUG, ("sio_open(%lu) failed. GetLastError() returns %d\n", (DWORD)devnum, GetLastError())); printf("sio_open(%lu) failed. GetLastError() returns %d\n", (DWORD)devnum, GetLastError()); return NULL; } /** * Sends a single character to the serial device. * * @param c character to send * @param fd serial device handle * * @note This function will block until the character can be sent. */ void sio_send(u8_t c, sio_fd_t fd) { DWORD dwNbBytesWritten = 0; LWIP_DEBUGF(SIO_DEBUG, ("sio_send(%lu)\n", (DWORD)c)); while ((!WriteFile((HANDLE)(fd), &c, 1, &dwNbBytesWritten, NULL)) || (dwNbBytesWritten < 1)) { } } /** * Receives a single character from the serial device. * * @param fd serial device handle * * @note This function will block until a character is received. */ u8_t sio_recv(sio_fd_t fd) { DWORD dwNbBytesReadden = 0; u8_t byte = 0; LWIP_DEBUGF(SIO_DEBUG, ("sio_recv()\n")); while ((sio_abort == 0) && ((!ReadFile((HANDLE)(fd), &byte, 1, &dwNbBytesReadden, NULL)) || (dwNbBytesReadden < 1))); LWIP_DEBUGF(SIO_DEBUG, ("sio_recv()=%lu\n", (DWORD)byte)); return byte; } /** * Reads from the serial device. * * @param fd serial device handle * @param data pointer to data buffer for receiving * @param len maximum length (in bytes) of data to receive * @return number of bytes actually received - may be 0 if aborted by sio_read_abort * * @note This function will block until data can be received. The blocking * can be cancelled by calling sio_read_abort(). */ u32_t sio_read(sio_fd_t fd, u8_t* data, u32_t len) { BOOL ret; DWORD dwNbBytesReadden = 0; LWIP_DEBUGF(SIO_DEBUG, ("sio_read()...\n")); ret = ReadFile((HANDLE)(fd), data, len, &dwNbBytesReadden, NULL); LWIP_DEBUGF(SIO_DEBUG, ("sio_read()=%lu bytes -> %d\n", dwNbBytesReadden, ret)); return dwNbBytesReadden; } /** * Tries to read from the serial device. Same as sio_read but returns * immediately if no data is available and never blocks. * * @param fd serial device handle * @param data pointer to data buffer for receiving * @param len maximum length (in bytes) of data to receive * @return number of bytes actually received */ u32_t sio_tryread(sio_fd_t fd, u8_t* data, u32_t len) { /* @todo: implement non-blocking read */ BOOL ret; DWORD dwNbBytesReadden = 0; LWIP_DEBUGF(SIO_DEBUG, ("sio_read()...\n")); ret = ReadFile((HANDLE)(fd), data, len, &dwNbBytesReadden, NULL); LWIP_DEBUGF(SIO_DEBUG, ("sio_read()=%lu bytes -> %d\n", dwNbBytesReadden, ret)); return dwNbBytesReadden; } /** * Writes to the serial device. * * @param fd serial device handle * @param data pointer to data to send * @param len length (in bytes) of data to send * @return number of bytes actually sent * * @note This function will block until all data can be sent. */ u32_t sio_write(sio_fd_t fd, u8_t* data, u32_t len) { BOOL ret; DWORD dwNbBytesWritten = 0; LWIP_DEBUGF(SIO_DEBUG, ("sio_write()...\n")); ret = WriteFile((HANDLE)(fd), data, len, &dwNbBytesWritten, NULL); LWIP_DEBUGF(SIO_DEBUG, ("sio_write()=%lu bytes -> %d\n", dwNbBytesWritten, ret)); return dwNbBytesWritten; } /** * Aborts a blocking sio_read() call. * @todo: This currently ignores fd and aborts all reads * * @param fd serial device handle */ void sio_read_abort(sio_fd_t fd) { LWIP_UNUSED_ARG(fd); LWIP_DEBUGF(SIO_DEBUG, ("sio_read_abort() !!!!!...\n")); sio_abort = 1; return; } ocproxy-1.60/contrib/ports/win32/sys_arch.c000066400000000000000000000243241303453231400206760ustar00rootroot00000000000000/* * Copyright (c) 2001-2003 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * Simon Goldschmidt * */ #include #include /* sprintf() for task names */ #include #include #include #include #include #include #include /* These functions are used from NO_SYS also, for precise timer triggering */ LARGE_INTEGER freq, sys_start_time; void sys_init_timing() { QueryPerformanceFrequency(&freq); QueryPerformanceCounter(&sys_start_time); } static LONGLONG sys_get_ms_longlong() { LONGLONG ret; LARGE_INTEGER now; #if NO_SYS if (freq.QuadPart == 0) { sys_init_timing(); } #endif /* NO_SYS */ QueryPerformanceCounter(&now); ret = now.QuadPart-sys_start_time.QuadPart; return (u32_t)(((ret)*1000)/freq.QuadPart); } u32_t sys_jiffies() { return (u32_t)sys_get_ms_longlong(); } u32_t sys_now() { return (u32_t)sys_get_ms_longlong(); } CRITICAL_SECTION critSec; void InitSysArchProtect() { InitializeCriticalSection(&critSec); } u32_t sys_arch_protect() { EnterCriticalSection(&critSec); return 0; } void sys_arch_unprotect(u32_t pval) { LWIP_UNUSED_ARG(pval); LeaveCriticalSection(&critSec); } void msvc_sys_init() { srand(time(0)); sys_init_timing(); InitSysArchProtect(); } void sys_init() { msvc_sys_init(); } #if !NO_SYS struct threadlist { DWORD id; struct threadlist *next; }; struct threadlist *lwip_win32_threads = NULL; void do_sleep(int ms) { Sleep(ms); } err_t sys_sem_new(sys_sem_t *sem, u8_t count) { HANDLE new_sem = NULL; LWIP_ASSERT("sem != NULL", sem != NULL); new_sem = CreateSemaphore(0, count, 100000, 0); LWIP_ASSERT("Error creating semaphore", new_sem != NULL); if(new_sem != NULL) { SYS_STATS_INC_USED(sem); #if LWIP_STATS && SYS_STATS LWIP_ASSERT("sys_sem_new() counter overflow", lwip_stats.sys.sem.used != 0 ); #endif /* LWIP_STATS && SYS_STATS*/ sem->sem = new_sem; return ERR_OK; } /* failed to allocate memory... */ SYS_STATS_INC(sem.err); sem->sem = SYS_SEM_NULL; return ERR_MEM; } void sys_sem_free(sys_sem_t *sem) { /* parameter check */ LWIP_ASSERT("sem != NULL", sem != NULL); LWIP_ASSERT("sem->sem != SYS_SEM_NULL", sem->sem != SYS_SEM_NULL); LWIP_ASSERT("sem->sem != INVALID_HANDLE_VALUE", sem->sem != INVALID_HANDLE_VALUE); CloseHandle(sem->sem); SYS_STATS_DEC(sem.used); #if LWIP_STATS && SYS_STATS LWIP_ASSERT("sys_sem_free() closed more than created", lwip_stats.sys.sem.used != (u16_t)-1); #endif /* LWIP_STATS && SYS_STATS */ sem->sem = NULL; } u32_t sys_arch_sem_wait(sys_sem_t *sem, u32_t timeout) { DWORD ret; LONGLONG starttime, endtime; LWIP_ASSERT("sem != NULL", sem != NULL); LWIP_ASSERT("sem != INVALID_HANDLE_VALUE", sem != INVALID_HANDLE_VALUE); if(!timeout) { /* wait infinite */ starttime = sys_get_ms_longlong(); ret = WaitForSingleObject(sem->sem, INFINITE); LWIP_ASSERT("Error waiting for semaphore", ret == WAIT_OBJECT_0); endtime = sys_get_ms_longlong(); /* return the time we waited for the sem */ return (u32_t)(endtime - starttime); } else { int ret; starttime = sys_get_ms_longlong(); ret = WaitForSingleObject(sem->sem, timeout); LWIP_ASSERT("Error waiting for semaphore", (ret == WAIT_OBJECT_0) || (ret == WAIT_TIMEOUT)); if(ret == WAIT_OBJECT_0) { endtime = sys_get_ms_longlong(); /* return the time we waited for the sem */ return (u32_t)(endtime - starttime); } else { /* timeout */ return SYS_ARCH_TIMEOUT; } } } void sys_sem_signal(sys_sem_t *sem) { DWORD ret; LWIP_ASSERT("sem != NULL", sem != NULL); LWIP_ASSERT("sem->sem != NULL", sem->sem != NULL); LWIP_ASSERT("sem->sem != INVALID_HANDLE_VALUE", sem->sem != INVALID_HANDLE_VALUE); ret = ReleaseSemaphore(sem->sem, 1, NULL); LWIP_ASSERT("Error releasing semaphore", ret != 0); } sys_thread_t sys_thread_new(const char *name, lwip_thread_fn function, void *arg, int stacksize, int prio) { struct threadlist *new_thread; HANDLE h; SYS_ARCH_DECL_PROTECT(lev); LWIP_UNUSED_ARG(name); LWIP_UNUSED_ARG(stacksize); LWIP_UNUSED_ARG(prio); new_thread = (struct threadlist*)malloc(sizeof(struct threadlist)); LWIP_ASSERT("new_thread != NULL", new_thread != NULL); if(new_thread != NULL) { SYS_ARCH_PROTECT(lev); new_thread->next = lwip_win32_threads; lwip_win32_threads = new_thread; h = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)function, arg, 0, &(new_thread->id)); LWIP_ASSERT("h != 0", h != 0); LWIP_ASSERT("h != -1", h != INVALID_HANDLE_VALUE); SYS_ARCH_UNPROTECT(lev); return new_thread->id; } return 0; } err_t sys_mbox_new(sys_mbox_t *mbox, int size) { LWIP_ASSERT("mbox != NULL", mbox != NULL); LWIP_UNUSED_ARG(size); mbox->sem = CreateSemaphore(0, 0, MAX_QUEUE_ENTRIES, 0); LWIP_ASSERT("Error creating semaphore", mbox->sem != NULL); if(mbox->sem == NULL) { SYS_STATS_INC(mbox.err); return ERR_MEM; } memset(&mbox->q_mem, 0, sizeof(u32_t)*MAX_QUEUE_ENTRIES); mbox->head = 0; mbox->tail = 0; SYS_STATS_INC_USED(mbox); #if LWIP_STATS && SYS_STATS LWIP_ASSERT("sys_mbox_new() counter overflow", lwip_stats.sys.mbox.used != 0 ); #endif /* LWIP_STATS && SYS_STATS */ return ERR_OK; } void sys_mbox_free(sys_mbox_t *mbox) { /* parameter check */ LWIP_ASSERT("mbox != NULL", mbox != NULL); LWIP_ASSERT("mbox->sem != NULL", mbox->sem != NULL); LWIP_ASSERT("mbox->sem != INVALID_HANDLE_VALUE", mbox->sem != INVALID_HANDLE_VALUE); CloseHandle(mbox->sem); SYS_STATS_DEC(mbox.used); #if LWIP_STATS && SYS_STATS LWIP_ASSERT( "sys_mbox_free() ", lwip_stats.sys.mbox.used!= (u16_t)-1 ); #endif /* LWIP_STATS && SYS_STATS */ mbox->sem = NULL; } void sys_mbox_post(sys_mbox_t *q, void *msg) { DWORD ret; SYS_ARCH_DECL_PROTECT(lev); /* parameter check */ LWIP_ASSERT("q != SYS_MBOX_NULL", q != SYS_MBOX_NULL); LWIP_ASSERT("q->sem != NULL", q->sem != NULL); LWIP_ASSERT("q->sem != INVALID_HANDLE_VALUE", q->sem != INVALID_HANDLE_VALUE); SYS_ARCH_PROTECT(lev); q->q_mem[q->head] = msg; (q->head)++; if (q->head >= MAX_QUEUE_ENTRIES) { q->head = 0; } LWIP_ASSERT("mbox is full!", q->head != q->tail); ret = ReleaseSemaphore(q->sem, 1, 0); LWIP_ASSERT("Error releasing sem", ret != 0); SYS_ARCH_UNPROTECT(lev); } err_t sys_mbox_trypost(sys_mbox_t *q, void *msg) { u32_t new_head; DWORD ret; SYS_ARCH_DECL_PROTECT(lev); /* parameter check */ LWIP_ASSERT("q != SYS_MBOX_NULL", q != SYS_MBOX_NULL); LWIP_ASSERT("q->sem != NULL", q->sem != NULL); LWIP_ASSERT("q->sem != INVALID_HANDLE_VALUE", q->sem != INVALID_HANDLE_VALUE); SYS_ARCH_PROTECT(lev); new_head = q->head + 1; if (new_head >= MAX_QUEUE_ENTRIES) { new_head = 0; } if (new_head == q->tail) { SYS_ARCH_UNPROTECT(lev); return ERR_MEM; } q->q_mem[q->head] = msg; q->head = new_head; LWIP_ASSERT("mbox is full!", q->head != q->tail); ret = ReleaseSemaphore(q->sem, 1, 0); LWIP_ASSERT("Error releasing sem", ret != 0); SYS_ARCH_UNPROTECT(lev); return ERR_OK; } u32_t sys_arch_mbox_fetch(sys_mbox_t *q, void **msg, u32_t timeout) { DWORD ret; LONGLONG starttime, endtime; SYS_ARCH_DECL_PROTECT(lev); /* parameter check */ LWIP_ASSERT("q != SYS_MBOX_NULL", q != SYS_MBOX_NULL); LWIP_ASSERT("q->sem != NULL", q->sem != NULL); LWIP_ASSERT("q->sem != INVALID_HANDLE_VALUE", q->sem != INVALID_HANDLE_VALUE); if (timeout == 0) { timeout = INFINITE; } starttime = sys_get_ms_longlong(); if ((ret = WaitForSingleObject(q->sem, timeout)) == WAIT_OBJECT_0) { SYS_ARCH_PROTECT(lev); if(msg != NULL) { *msg = q->q_mem[q->tail]; } (q->tail)++; if (q->tail >= MAX_QUEUE_ENTRIES) { q->tail = 0; } SYS_ARCH_UNPROTECT(lev); endtime = sys_get_ms_longlong(); return (u32_t)(endtime - starttime); } else { LWIP_ASSERT("Error waiting for sem", ret == WAIT_TIMEOUT); if(msg != NULL) { *msg = NULL; } return SYS_ARCH_TIMEOUT; } } u32_t sys_arch_mbox_tryfetch(sys_mbox_t *q, void **msg) { DWORD ret; SYS_ARCH_DECL_PROTECT(lev); /* parameter check */ LWIP_ASSERT("q != SYS_MBOX_NULL", q != SYS_MBOX_NULL); LWIP_ASSERT("q->sem != NULL", q->sem != NULL); LWIP_ASSERT("q->sem != INVALID_HANDLE_VALUE", q->sem != INVALID_HANDLE_VALUE); if ((ret = WaitForSingleObject(q->sem, 0)) == WAIT_OBJECT_0) { SYS_ARCH_PROTECT(lev); if(msg != NULL) { *msg = q->q_mem[q->tail]; } (q->tail)++; if (q->tail >= MAX_QUEUE_ENTRIES) { q->tail = 0; } SYS_ARCH_UNPROTECT(lev); return 0; } else { LWIP_ASSERT("Error waiting for sem", ret == WAIT_TIMEOUT); if(msg != NULL) { *msg = NULL; } return SYS_ARCH_TIMEOUT; } } #endif /* !NO_SYS */ ocproxy-1.60/contrib/ports/win32/test.c000066400000000000000000000443731303453231400200500ustar00rootroot00000000000000/* * Copyright (c) 2001,2002 Florian Schulze. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the authors nor the names of the contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * test.c - This file is part of lwIP test * */ /* C runtime includes */ #include #include #include #include #include /* lwIP core includes */ #include "lwip/opt.h" #include "lwip/sys.h" #include "lwip/timers.h" #include "lwip/debug.h" #include "lwip/stats.h" #include "lwip/init.h" #include "lwip/tcpip.h" #include "lwip/netif.h" #include "lwip/tcp.h" #include "lwip/udp.h" #include "lwip/dns.h" #include "lwip/dhcp.h" #include "lwip/autoip.h" /* lwIP netif includes */ #include "netif/etharp.h" /* applications includes */ #include "apps/httpserver_raw/httpd.h" #include "apps/httpserver/httpserver-netconn.h" #include "apps/netio/netio.h" #include "apps/netbios/netbios.h" #include "apps/ping/ping.h" #include "apps/rtp/rtp.h" #include "apps/sntp/sntp.h" #include "apps/chargen/chargen.h" #include "apps/shell/shell.h" #include "apps/tcpecho/tcpecho.h" #include "apps/udpecho/udpecho.h" #include "apps/tcpecho_raw/echo.h" #include "apps/socket_examples/socket_examples.h" #if NO_SYS /* ... then we need information about the timer intervals: */ #include "lwip/ip_frag.h" #include "lwip/igmp.h" #endif /* NO_SYS */ #if PPP_SUPPORT /* PPP includes */ #include "../netif/ppp/ppp_impl.h" #include "lwip/sio.h" #include "netif/ppp_oe.h" #endif /* PPP_SUPPORT */ /* include the port-dependent configuration */ #include "lwipcfg_msvc.h" /** Define this to 1 to enable a PCAP interface as default interface. */ #ifndef USE_PCAPIF #define USE_PCAPIF 1 #endif /** Define this to 1 or 2 to support 1 or 2 SLIP interfaces. */ #ifndef USE_SLIPIF #define USE_SLIPIF 0 #endif /** Use an ethernet adapter? Default to enabled if PCAPIF or PPPoE are used. */ #ifndef USE_ETHERNET #define USE_ETHERNET (USE_PCAPIF || PPPOE_SUPPORT) #endif /** Use an ethernet adapter for TCP/IP? By default only if PCAPIF is used. */ #ifndef USE_ETHERNET_TCPIP #define USE_ETHERNET_TCPIP (USE_PCAPIF) #endif #if USE_ETHERNET #include "pcapif.h" #endif /* USE_ETHERNET */ #if USE_SLIPIF #include #endif /* USE_SLIPIF */ #ifndef USE_DHCP #define USE_DHCP LWIP_DHCP #endif #ifndef USE_AUTOIP #define USE_AUTOIP LWIP_AUTOIP #endif /* globales variables for netifs */ #if USE_ETHERNET /* THE ethernet interface */ struct netif netif; #if LWIP_DHCP /* dhcp struct for the ethernet netif */ struct dhcp netif_dhcp; #endif /* LWIP_DHCP */ #if LWIP_AUTOIP /* autoip struct for the ethernet netif */ struct autoip netif_autoip; #endif /* LWIP_AUTOIP */ #endif /* USE_ETHERNET */ #if PPP_SUPPORT /* THE PPP descriptor */ int ppp_desc = -1; u8_t sio_idx = 0; sio_fd_t ppp_sio; #endif /* PPP_SUPPORT */ #if USE_SLIPIF struct netif slipif1; #if USE_SLIPIF > 1 struct netif slipif2; #endif /* USE_SLIPIF > 1 */ #endif /* USE_SLIPIF */ #if PPP_SUPPORT void pppLinkStatusCallback(void *ctx, int errCode, void *arg) { LWIP_UNUSED_ARG(ctx); switch(errCode) { case PPPERR_NONE: { /* No error. */ struct ppp_addrs *ppp_addrs = (struct ppp_addrs *)arg; printf("pppLinkStatusCallback: PPPERR_NONE\n"); printf(" our_ipaddr=%s\n", ip_ntoa(&ppp_addrs->our_ipaddr)); printf(" his_ipaddr=%s\n", ip_ntoa(&ppp_addrs->his_ipaddr)); printf(" netmask =%s\n", ip_ntoa(&ppp_addrs->netmask)); printf(" dns1 =%s\n", ip_ntoa(&ppp_addrs->dns1)); printf(" dns2 =%s\n", ip_ntoa(&ppp_addrs->dns2)); break; } case PPPERR_PARAM: { /* Invalid parameter. */ printf("pppLinkStatusCallback: PPPERR_PARAM\n"); break; } case PPPERR_OPEN: { /* Unable to open PPP session. */ printf("pppLinkStatusCallback: PPPERR_OPEN\n"); break; } case PPPERR_DEVICE: { /* Invalid I/O device for PPP. */ printf("pppLinkStatusCallback: PPPERR_DEVICE\n"); break; } case PPPERR_ALLOC: { /* Unable to allocate resources. */ printf("pppLinkStatusCallback: PPPERR_ALLOC\n"); break; } case PPPERR_USER: { /* User interrupt. */ printf("pppLinkStatusCallback: PPPERR_USER\n"); break; } case PPPERR_CONNECT: { /* Connection lost. */ printf("pppLinkStatusCallback: PPPERR_CONNECT\n"); break; } case PPPERR_AUTHFAIL: { /* Failed authentication challenge. */ printf("pppLinkStatusCallback: PPPERR_AUTHFAIL\n"); break; } case PPPERR_PROTOCOL: { /* Failed to meet protocol. */ printf("pppLinkStatusCallback: PPPERR_PROTOCOL\n"); break; } default: { printf("pppLinkStatusCallback: unknown errCode %d\n", errCode); break; } } } #endif /* PPP_SUPPORT */ #if LWIP_NETIF_STATUS_CALLBACK void status_callback(struct netif *netif) { if (netif_is_up(netif)) { printf("status_callback==UP, local interface IP is %s\n", ip_ntoa(&netif->ip_addr)); } else { printf("status_callback==DOWN\n"); } } #endif /* LWIP_NETIF_STATUS_CALLBACK */ #if LWIP_NETIF_LINK_CALLBACK void link_callback(struct netif *netif) { if (netif_is_link_up(netif)) { printf("link_callback==UP\n"); #if USE_DHCP if (netif->dhcp != NULL) { dhcp_renew(netif); } #endif /* USE_DHCP */ } else { printf("link_callback==DOWN\n"); } } #endif /* LWIP_NETIF_LINK_CALLBACK */ /* This function initializes all network interfaces */ static void msvc_netif_init() { #if USE_ETHERNET ip_addr_t ipaddr, netmask, gw; #endif /* USE_ETHERNET */ #if USE_SLIPIF u8_t num_slip1 = 0; ip_addr_t ipaddr_slip1, netmask_slip1, gw_slip1; #if USE_SLIPIF > 1 u8_t num_slip2 = 1; ip_addr_t ipaddr_slip2, netmask_slip2, gw_slip2; #endif /* USE_SLIPIF > 1 */ #endif /* USE_SLIPIF */ #if PPP_SUPPORT const char *username = NULL, *password = NULL; #ifdef PPP_USERNAME username = PPP_USERNAME; #endif #ifdef PPP_PASSWORD password = PPP_PASSWORD; #endif printf("pppInit\n"); pppInit(); pppSetAuth(PPPAUTHTYPE_ANY, username, password); printf("pppOpen: COM%d\n", (int)sio_idx); #if PPPOS_SUPPORT ppp_sio = sio_open(sio_idx); if (ppp_sio == NULL) { printf("sio_open error\n"); } else { ppp_desc = pppOpen(ppp_sio, pppLinkStatusCallback, NULL); } #endif /* PPPOS_SUPPORT */ #endif /* PPP_SUPPORT */ #if USE_ETHERNET ip_addr_set_zero(&gw); ip_addr_set_zero(&ipaddr); ip_addr_set_zero(&netmask); #if USE_ETHERNET_TCPIP #if USE_DHCP printf("Starting lwIP, local interface IP is dhcp-enabled\n"); #elif USE_AUTOIP printf("Starting lwIP, local interface IP is autoip-enabled\n"); #else /* USE_DHCP */ LWIP_PORT_INIT_GW(&gw); LWIP_PORT_INIT_IPADDR(&ipaddr); LWIP_PORT_INIT_NETMASK(&netmask); printf("Starting lwIP, local interface IP is %s\n", ip_ntoa(&ipaddr)); #endif /* USE_DHCP */ #endif /* USE_ETHERNET_TCPIP */ #if NO_SYS #if LWIP_ARP netif_set_default(netif_add(&netif, &ipaddr, &netmask, &gw, NULL, pcapif_init, ethernet_input)); #else /* LWIP_ARP */ netif_set_default(netif_add(&netif, &ipaddr, &netmask, &gw, NULL, pcapif_init, ip_input)); #endif /* LWIP_ARP */ #else /* NO_SYS */ netif_set_default(netif_add(&netif, &ipaddr, &netmask, &gw, NULL, pcapif_init, tcpip_input)); #if LWIP_IPV6 netif_create_ip6_linklocal_address(&netif, 1); printf("ip6 linklocal address: "); ip6_addr_debug_print(0xFFFFFFFF & ~LWIP_DBG_HALT, &netif.ip6_addr[0]); printf("\n"); #endif /* LWIP_IPV6 */ #endif /* NO_SYS */ #if LWIP_NETIF_STATUS_CALLBACK netif_set_status_callback(&netif, status_callback); #endif /* LWIP_NETIF_STATUS_CALLBACK */ #if LWIP_NETIF_LINK_CALLBACK netif_set_link_callback(&netif, link_callback); #endif /* LWIP_NETIF_LINK_CALLBACK */ #if USE_ETHERNET_TCPIP #if LWIP_AUTOIP autoip_set_struct(&netif, &netif_autoip); #endif /* LWIP_AUTOIP */ #if LWIP_DHCP dhcp_set_struct(&netif, &netif_dhcp); #endif /* LWIP_DHCP */ #if USE_DHCP dhcp_start(&netif); #elif USE_AUTOIP autoip_start(&netif); #else /* USE_DHCP */ netif_set_up(&netif); #endif /* USE_DHCP */ #else /* USE_ETHERNET_TCPIP */ /* Use ethernet for PPPoE only */ netif.flags &= ~(NETIF_FLAG_ETHARP | NETIF_FLAG_IGMP); /* no ARP */ netif.flags |= NETIF_FLAG_ETHERNET; /* but pure ethernet */ #endif /* USE_ETHERNET_TCPIP */ #if PPP_SUPPORT && PPPOE_SUPPORT /* start PPPoE after ethernet netif is added! */ ppp_desc = pppOverEthernetOpen(&netif, NULL, NULL, pppLinkStatusCallback, NULL); #endif /* PPP_SUPPORT && PPPOE_SUPPORT */ #endif /* USE_ETHERNET */ #if USE_SLIPIF LWIP_PORT_INIT_SLIP1_IPADDR(&ipaddr_slip1); LWIP_PORT_INIT_SLIP1_GW(&gw_slip1); LWIP_PORT_INIT_SLIP1_NETMASK(&netmask_slip1); printf("Starting lwIP slipif, local interface IP is %s\n", ip_ntoa(&ipaddr_slip1)); #if SIO_USE_COMPORT num_slip1++; /* COM ports cannot be 0-based */ #endif netif_add(&slipif1, &ipaddr_slip1, &netmask_slip1, &gw_slip1, &num_slip1, slipif_init, ip_input); #if !USE_ETHERNET netif_set_default(&slipif1); #endif /* !USE_ETHERNET */ #if LWIP_IPV6 netif_create_ip6_linklocal_address(&slipif1, 1); printf("SLIP ip6 linklocal address: "); ip6_addr_debug_print(0xFFFFFFFF & ~LWIP_DBG_HALT, &slipif1.ip6_addr[0]); printf("\n"); #endif /* LWIP_IPV6 */ #if LWIP_NETIF_STATUS_CALLBACK netif_set_status_callback(&slipif1, status_callback); #endif /* LWIP_NETIF_STATUS_CALLBACK */ #if LWIP_NETIF_LINK_CALLBACK netif_set_link_callback(&slipif1, link_callback); #endif /* LWIP_NETIF_LINK_CALLBACK */ netif_set_up(&slipif1); #if USE_SLIPIF > 1 LWIP_PORT_INIT_SLIP2_IPADDR(&ipaddr_slip2); LWIP_PORT_INIT_SLIP2_GW(&gw_slip2); LWIP_PORT_INIT_SLIP2_NETMASK(&netmask_slip2); printf("Starting lwIP SLIP if #2, local interface IP is %s\n", ip_ntoa(&ipaddr_slip2)); #if SIO_USE_COMPORT num_slip2++; /* COM ports cannot be 0-based */ #endif netif_add(&slipif2, &ipaddr_slip2, &netmask_slip2, &gw_slip2, &num_slip2, slipif_init, ip_input); #if LWIP_IPV6 netif_create_ip6_linklocal_address(&slipif1, 1); printf("SLIP2 ip6 linklocal address: "); ip6_addr_debug_print(0xFFFFFFFF & ~LWIP_DBG_HALT, &slipif2.ip6_addr[0]); printf("\n"); #endif /* LWIP_IPV6 */ #if LWIP_NETIF_STATUS_CALLBACK netif_set_status_callback(&slipif2, status_callback); #endif /* LWIP_NETIF_STATUS_CALLBACK */ #if LWIP_NETIF_LINK_CALLBACK netif_set_link_callback(&slipif2, link_callback); #endif /* LWIP_NETIF_LINK_CALLBACK */ netif_set_up(&slipif2); #endif /* USE_SLIPIF > 1*/ #endif /* USE_SLIPIF */ } #if LWIP_DNS_APP && LWIP_DNS void dns_found(const char *name, ip_addr_t *addr, void *arg) { LWIP_UNUSED_ARG(arg); printf("%s: %s\n", name, addr ? ip_ntoa(addr) : ""); } void dns_dorequest(void *arg) { char* dnsname = "3com.com"; ip_addr_t dnsresp; LWIP_UNUSED_ARG(arg); if (dns_gethostbyname(dnsname, &dnsresp, dns_found, 0) == ERR_OK) { dns_found(dnsname, &dnsresp, 0); } } #endif /* LWIP_DNS_APP && LWIP_DNS */ /* This function initializes applications */ static void apps_init() { #if LWIP_DNS_APP && LWIP_DNS /* wait until the netif is up (for dhcp, autoip or ppp) */ sys_timeout(5000, dns_dorequest, NULL); #endif /* LWIP_DNS_APP && LWIP_DNS */ #if LWIP_CHARGEN_APP && LWIP_SOCKET chargen_init(); #endif /* LWIP_CHARGEN_APP && LWIP_SOCKET */ #if LWIP_PING_APP && LWIP_RAW && LWIP_ICMP ping_init(); #endif /* LWIP_PING_APP && LWIP_RAW && LWIP_ICMP */ #if LWIP_NETBIOS_APP && LWIP_UDP netbios_init(); #endif /* LWIP_NETBIOS_APP && LWIP_UDP */ #if LWIP_HTTPD_APP && LWIP_TCP #ifdef LWIP_HTTPD_APP_NETCONN http_server_netconn_init(); #else /* LWIP_HTTPD_APP_NETCONN */ httpd_init(); #endif /* LWIP_HTTPD_APP_NETCONN */ #endif /* LWIP_HTTPD_APP && LWIP_TCP */ #if LWIP_NETIO_APP && LWIP_TCP netio_init(); #endif /* LWIP_NETIO_APP && LWIP_TCP */ #if LWIP_RTP_APP && LWIP_SOCKET && LWIP_IGMP rtp_init(); #endif /* LWIP_RTP_APP && LWIP_SOCKET && LWIP_IGMP */ #if LWIP_SNTP_APP && LWIP_SOCKET sntp_init(); #endif /* LWIP_SNTP_APP && LWIP_SOCKET */ #if LWIP_SHELL_APP && LWIP_NETCONN shell_init(); #endif /* LWIP_SHELL_APP && LWIP_NETCONN */ #if LWIP_TCPECHO_APP #if LWIP_NETCONN && defined(LWIP_TCPECHO_APP_NETCONN) tcpecho_init(); #else /* LWIP_NETCONN && defined(LWIP_TCPECHO_APP_NETCONN) */ echo_init(); #endif #endif /* LWIP_TCPECHO_APP && LWIP_NETCONN */ #if LWIP_UDPECHO_APP && LWIP_NETCONN udpecho_init(); #endif /* LWIP_UDPECHO_APP && LWIP_NETCONN */ #if LWIP_SOCKET_EXAMPLES_APP && LWIP_SOCKET socket_examples_init(); #endif /* LWIP_SOCKET_EXAMPLES_APP && LWIP_SOCKET */ #ifdef LWIP_APP_INIT LWIP_APP_INIT(); #endif } /* This function initializes this lwIP test. When NO_SYS=1, this is done in * the main_loop context (there is no other one), when NO_SYS=0, this is done * in the tcpip_thread context */ static void test_init(void * arg) { /* remove compiler warning */ #if NO_SYS LWIP_UNUSED_ARG(arg); #else /* NO_SYS */ sys_sem_t *init_sem; LWIP_ASSERT("arg != NULL", arg != NULL); init_sem = (sys_sem_t*)arg; #endif /* NO_SYS */ /* init network interfaces */ msvc_netif_init(); /* init apps */ apps_init(); #if !NO_SYS sys_sem_signal(init_sem); #endif /* !NO_SYS */ } #if PPP_SUPPORT static void pppCloseCallback(void *arg) { int pd = (int)arg; pppClose(pd); } #endif /* PPP_SUPPORT */ /* This is somewhat different to other ports: we have a main loop here: * a dedicated task that waits for packets to arrive. This would normally be * done from interrupt context with embedded hardware, but we don't get an * interrupt in windows for that :-) */ void main_loop() { #if !NO_SYS err_t err; sys_sem_t init_sem; #endif /* NO_SYS */ #if PPP_SUPPORT #if !USE_ETHERNET int count; u8_t rxbuf[1024]; #endif volatile int callClosePpp = 0; #endif /* PPP_SUPPORT */ /* initialize lwIP stack, network interfaces and applications */ #if NO_SYS lwip_init(); test_init(NULL); #else /* NO_SYS */ err = sys_sem_new(&init_sem, 0); tcpip_init(test_init, &init_sem); /* we have to wait for initialization to finish before * calling update_adapter()! */ sys_sem_wait(&init_sem); sys_sem_free(&init_sem); #endif /* NO_SYS */ /* MAIN LOOP for driver update (and timers if NO_SYS) */ while (!_kbhit()) { #if NO_SYS /* handle timers (already done in tcpip.c when NO_SYS=0) */ sys_check_timeouts(); #endif /* NO_SYS */ #if USE_ETHERNET #if !PCAPIF_RX_USE_THREAD /* check for packets and link status*/ pcapif_poll(&netif); /* When pcapif_poll comes back, there are not packets, so sleep to prevent 100% CPU load. Don't do this in an embedded system since it increases latency! */ sys_msleep(1); #else /* !PCAPIF_RX_USE_THREAD */ sys_msleep(50); #endif /* !PCAPIF_RX_USE_THREAD */ #else /* USE_ETHERNET */ #if 0 /* set this to 1 if PPP_INPROC_OWNTHREAD==0 or not defined (see ppp.c) */ /* try to read characters from serial line and pass them to PPPoS */ count = sio_read(ppp_sio, (u8_t*)rxbuf, 1024); if(count > 0) { pppos_input(ppp_desc, rxbuf, count); } else #endif { /* nothing received, give other tasks a chance to run */ sys_msleep(1); } #endif /* USE_ETHERNET */ #if USE_SLIPIF slipif_poll(&slipif1); #if USE_SLIPIF > 1 slipif_poll(&slipif2); #endif /* USE_SLIPIF > 1 */ #endif /* USE_SLIPIF */ #if ENABLE_LOOPBACK && !LWIP_NETIF_LOOPBACK_MULTITHREADING /* check for loopback packets on all netifs */ netif_poll_all(); #endif /* ENABLE_LOOPBACK && !LWIP_NETIF_LOOPBACK_MULTITHREADING */ #if PPP_SUPPORT { int do_hup = 0; if(do_hup) { pppSigHUP(ppp_desc); do_hup = 0; } } if(callClosePpp && (ppp_desc >= 0)) { /* make sure to disconnect PPP before stopping the program... */ callClosePpp = 0; #if NO_SYS pppClose(ppp_desc); #else tcpip_callback_with_block(pppCloseCallback, (void*)ppp_desc, 0); #endif ppp_desc = -1; } #endif /* PPP_SUPPORT */ } #if PPP_SUPPORT if(ppp_desc >= 0) { u32_t started; printf("Closing PPP connection...\n"); /* make sure to disconnect PPP before stopping the program... */ #if NO_SYS pppClose(ppp_desc); #else tcpip_callback_with_block(pppCloseCallback, (void*)ppp_desc, 0); #endif ppp_desc = -1; /* Wait for some time to let PPP finish... */ started = sys_now(); do { #if USE_ETHERNET && !PCAPIF_RX_USE_THREAD pcapif_poll(&netif); #else /* USE_ETHERNET && !PCAPIF_RX_USE_THREAD */ sys_msleep(50); #endif /* USE_ETHERNET && !PCAPIF_RX_USE_THREAD */ /* @todo: need a better check here: only wait until PPP is down */ } while(sys_now() - started < 5000); } #endif /* PPP_SUPPORT */ #if USE_ETHERNET /* release the pcap library... */ pcapif_shutdown(&netif); #endif /* USE_ETHERNET */ } #if PPP_SUPPORT && PPPOS_SUPPORT int main(int argc, char **argv) #else /* PPP_SUPPORT && PPPOS_SUPPORT */ int main(void) #endif /* PPP_SUPPORT && PPPOS_SUPPORT */ { #if PPP_SUPPORT && PPPOS_SUPPORT if(argc > 1) { sio_idx = (u8_t)atoi(argv[1]); } printf("Using serial port %d for PPP\n", sio_idx); #endif /* PPP_SUPPORT && PPPOS_SUPPORT */ /* no stdio-buffering, please! */ setvbuf(stdout, NULL,_IONBF, 0); main_loop(); return 0; } ocproxy-1.60/lwip/000077500000000000000000000000001303453231400141145ustar00rootroot00000000000000ocproxy-1.60/lwip/.gitattributes000066400000000000000000000001351303453231400170060ustar00rootroot00000000000000# These files are text and should be normalized *.txt text *.c text *.h text ocproxy-1.60/lwip/CHANGELOG000066400000000000000000004441771303453231400153470ustar00rootroot00000000000000HISTORY (CVS HEAD) * [Enter new changes just after this line - do not remove this line] ++ New features: 2013-03-17: Simon Goldschmidt (patch by Ghobad Emadi) * opt.h, etharp.c: Added LWIP_HOOK_ETHARP_GET_GW to implement IPv4 routing with multiple gateways 2013-04-20: Fatih Asici * opt.h, etharp.h/.c: patch #7993: Added support for transmitting packets with VLAN headers via hook function LWIP_HOOK_VLAN_SET and to check them via hook function LWIP_HOOK_VLAN_CHECK 2014-02-20: Simon Goldschmidt (based on patch by Artem Pisarenko) * patch #7885: modification of api modules to support FreeRTOS-MPU (don't pass stack-pointers to other threads) 2014-02-05: Simon Goldschmidt (patch by "xtian" and "alex_ab") * patch #6537/#7858: TCP window scaling support 2014-01-17: Jiri Engelthaler * icmp, icmp6, opt.h: patch #8027: Completed HW checksuming for IPv4 and IPv6 ICMP's 2012-08-22: Sylvain Rochet * New PPP stack for lwIP, developed in ppp-new branch. Based from pppd 2.4.5, released 2009-11-17, with huge changes to match code size and memory requirements for embedded devices, including: - Gluing together the previous low-level PPP code in lwIP to pppd 2.4.5, which is more or less what pppd sys-* files are, so that we get something working using the unix port. - Merged some patchs from lwIP Git repository which add interesting features or fix bugs. - Merged some patchs from Debian pppd package which add interesting features or fix bugs. - Ported PPP timeout handling to the lwIP timers system - Disabled all the PPP code using filesystem access, replaced in necessary cases to configuration variables. - Disabled all the PPP code forking processes. - Removed IPX support, lwIP does not support IPX. - Ported and improved random module from the previous PPP port. - Removed samba TDB (file-driven database) usage, because it needs a filesystem. - MS-CHAP required a DES implementation, we added the latest PolarSSL DES implementation which is under a BSD-ish license. - Also switched to PolarSSL MD4,MD5,SHA1 implementations, which are meant to be used in embedded devices with reduced memory footprint. - Removed PPP configuration file parsing support. - Added macro definition EAP_SUPPORT to make EAP support optional. - Added macro definition CHAP_SUPPORT to make CHAP support optional. - Added macro definition MSCHAP_SUPPORT to make MSCHAP support optional. - Added macro definition PAP_SUPPORT to make PAP support optional. - Cleared all Linux syscall calls. - Disabled demand support using a macro, so that it can be ported later. - Disabled ECP support using a macro, so that it can be ported later. - Disabled CCP support using a macro, so that it can be ported later. - Disabled CBCP support using a macro, so that it can be ported later. - Disabled LQR support using a macro, so that it can be ported later. - Print packet debug feature optional, through PRINTPKT_SUPPORT - Removed POSIX signal usage. - Fully ported PPPoS code from the previous port. - Fully ported PPPoE code from the previous port. - Fully ported VJ compression protocol code from the previous port. - Removed all malloc()/free() use from PPP, replaced by stack usage or PBUF. - Disabled PPP server support using a macro, so that it can be ported later. - Switched all PPP debug to lwIP debug system. - Created PPP Control Block (PPP PCB), removed PPP unit integer everywhere, removed all global variables everywhere, did everything necessary for the PPP stack to support more than one PPP session (pppd only support one session per process). - Removed the statically allocated output buffer, now using PBUF. - Improved structure size of all PPP modules, deep analyze of code to reduce variables size to the bare minimum. Switched all boolean type (char type in most architecture) to compiler generated bitfields. - Added PPP IPv6 support, glued lwIP IPv6 support to PPP. - Now using a persistent netif interface which can then be used in lwIP functions requiring a netif. - Now initializing PPP in lwip_init() function. - Reworked completely the PPP state machine, so that we don't end up in anymore in inconsistent state, especially with PPPoE. - Improved the way we handle PPP reconnection after disconnect, cleaning everything required so that we start the PPP connection again from a clean state. - Added PPP holdoff support, allow the lwIP user to wait a little bit before reconnecting, prevents connection flood, especially when using PPPoL2TP. - Added PPPoL2TP LAC support (a.k.a. UDP tunnels), adding a VPN client feature to lwIP, L2TP being a widely used tunnel protocol. - Switched all used PPP types to lwIP types (u8t, u16t, u32t, ...) - Added PPP API "sequential" thread-safe API, based from NETIFAPI. 2012-03-25: Simon Goldschmidt (idea by Mason) * posix/*: added posix-compatibility include files posix/netdb.h and posix/sys/socket.h which are a simple wrapper to the correct lwIP include files. 2012-01-16: Simon Goldschmidt * opt.h, icmp.c: Added option CHECKSUM_GEN_ICMP 2011-12-17: Simon Goldschmidt * ip.h: implemented API functions to access so_options of IP pcbs (UDP, TCP, RAW) (fixes bug #35061) 2011-09-27: Simon Goldschmidt * opt.h, tcp.c, tcp_in.c: Implemented limiting data on ooseq queue (task #9989) (define TCP_OOSEQ_MAX_BYTES / TCP_OOSEQ_MAX_PBUFS in lwipopts.h) 2011-09-21: Simon Goldschmidt * opt.h, api.h, api_lib.c, api_msg.h/.c, sockets.c: Implemented timeout on send (TCP only, bug #33820) 2011-09-21: Simon Goldschmidt * init.c: Converted runtime-sanity-checks into compile-time checks that can be disabled (since runtime checks can often not be seen on embedded targets) 2011-09-11: Simon Goldschmidt * ppp.h, ppp_impl.h: splitted ppp.h to an internal and external header file to get a clear separation of which functions an application or port may use (task #11281) 2011-09-11: Simon Goldschmidt * opt.h, tcp_impl.h, tcp.c, udp.h/.c: Added a config option to randomize initial local TCP/UDP ports (so that different port ranges are used after a reboot; bug #33818; this one added tcp_init/udp_init functions again) 2011-09-03: Simon Goldschmidt * dhcp.c: DHCP uses LWIP_RAND() for xid's (bug #30302) 2011-08-24: Simon Goldschmidt * opt.h, netif.h/.c: added netif remove callback (bug #32397) 2011-07-26: Simon Goldschmidt * etharp.c: ETHARP_SUPPORT_VLAN: add support for an external VLAN filter function instead of only checking for one VLAN (define ETHARP_VLAN_CHECK_FN) 2011-07-21: Simon Goldschmidt (patch by hanhui) * ip4.c, etharp.c, pbuf.h: bug #33634 ip_forward() have a faulty behaviour: Added pbuf flags to mark incoming packets as link-layer broadcast/multicast. Also added code to allow ip_forward() to forward non-broadcast packets to the input netif (set IP_FORWARD_ALLOW_TX_ON_RX_NETIF==1). 2011-07-21: Simon Goldschmidt * sockets.c, opt.h: (bug #30185): added LWIP_FIONREAD_LINUXMODE that makes ioctl/FIONREAD return the size of the next pending datagram. 2011-06-26: Simon Goldschmidt (patch by Cameron Gutman) * tcp.c, tcp_out.c: bug #33604: added some more asserts to check that pcb->state != LISTEN 2011-05-25: Simon Goldschmidt * again nearly the whole stack, renamed ip.c to ip4.c, ip_addr.c to ip4_addr.c, combined ipv4/ipv6 inet_chksum.c, added ip.h, ip_addr.h: Combined IPv4 and IPv6 code where possible, added defines to access IPv4/IPv6 in non-IP code so that the code is more readable. 2011-05-17: Patch by Ivan Delamer (only checked in by Simon Goldschmidt) * nearly the whole stack: Finally, we got decent IPv6 support, big thanks to Ivan! (this is work in progress: we're just post release anyway :-) 2011-05-14: Simon Goldschmidt (patch by Stéphane Lesage) * tcpip.c/.h: patch #7449 allow tcpip callback from interrupt with static memory message ++ Bugfixes: 2014-06-03: Simon Goldschmidt * tcp_impl.h, tcp_in.c: fixed bug #37969 SYN packet dropped as short packet in tcp_input function 2014-05-20: Simon Goldschmidt * tcp_out.c: fixed bug #37184 tcp_write problem for pcbs in the SYN_SENT state 2014-05-19: Simon Goldschmidt * *.h: Fixed bug #35874 reserved identifier violation (removed leading underscores from header include guards) 2014-04-08: Simon Goldschmidt * tcp.c: Fixed bug #36167 tcp server crash when client closes (maximum window) 2014-04-06: Simon Goldschmidt * tcp_in.c: Fixed bug #36210 lwIP does not elicit an empty ACK when received unacceptable ACK 2014-04-06: Simon Goldschmidt * dhcp.c, ip4.c/.h, ip6.c/.h, udp.c/.h, ip.h: Fixed bug #41787 DHCP Discovery is invalid when an IP is set to thet netif. 2014-03-14: Simon Goldschmidt * tcp_out.c: Fixed bug #36153 TCP Cheksum error if LWIP_CHECKSUM_ON_COPY=1 2014-03-11: Simon Goldschmidt (patch by Mason) * opt.h, sockets.c: fixed bug #35928 BSD sockets functions must set errno for POSIX-compliance 2014-02-27: Simon Goldschmidt * dhcp.c: fixed bug #40303 DHCP xid renewed when sending a DHCPREQUEST 2014-02-27: Simon Goldschmidt * raw.c: fixed bug #41680 raw socket can not receive IPv6 packet when IP_SOF_BROADCAST_RECV==1 2014-02-27: Simon Goldschmidt * api_msg.c, sockets.c: fixed bug #38404 getpeeraddr returns success on unconnected/listening TCP sockets 2014-02-27: Simon Goldschmidt * sockets.c: fixed bug #41729 Some socket functions return Exyz instead of -1 2014-02-25: Simon Goldschmidt * ip4.c: fixed bug #39514 ip_route() may return an IPv6-only interface 2014-02-25: Simon Goldschmidt, patch by Fatih Asici * pbuf.c: fixed bug #39356 Wrong increment in pbuf_memfind() 2014-02-25: Simon Goldschmidt * netif.c/.h, udp.c: fixed bug #39225 udp.c uses netif_matches_ip6_addr() incorrectly; renamed function netif_matches_ip6_addr() to netif_get_ip6_addr_match() 2014-02-25: Simon Goldschmidt * igmp.c: fixed bug #39145 IGMP membership report for 224.0.0.1 2014-02-22: Simon Goldschmidt (patch by Amir Shalem) * etharp.c, opt.h: fixed bug #34681 Limit ARP queue length by ARP_QUEUE_LEN (=3) 2014-02-22: Simon Goldschmidt (patch by Amir Shalem) * etharp.h/.c: fixed bug #34682 Limit ARP request flood for unresolved entry 2014-02-20: Simon Goldschmidt * tcp_out.c: fixed bug #39683 Assertion "seg->tcphdr not aligned" failed with MEM_ALIGNMENT = 8 2014-02-20: Simon Goldschmidt * sockets.c: fixed bug #39882 No function shall set errno to 0 2014-02-20: Simon Goldschmidt * mib_structs.c: fixed bug #40050 SNMP problem with MIB arrays > 255 2014-02-20: Simon Goldschmidt * api.h, sockets.c: fixed bug #41499 netconn::recv_avail can overflow 2014-01-08: Stathis Voukelatos * memp_std.h: patch #7928 Fixed size calculation in MALLOC memory pool creation macro 2014-01-18: Brian Fahs * tcp_out.c: patch #8237: tcp_rexmit_rto fails to update pcb->unsent_oversize when necessary 2014-01-17: Grant Erickson, Jay Logue, Simon Goldschmidt * ipv6.c, netif.c: patch #7913 Enable Support for IPv6 Loopback 2014-01-16: Stathis Voukelatos * netif.c: patch #7902 Fixed netif_poll() operation when LWIP_LOOPBACK_MAX_PBUFS > 0 2014-01-14: "Freddie Chopin" * snmp.h, mib2.c: fixed constness and spelling of sysdescr 2014-01-14: Simon Goldschmidt (patch by Thomas Faber) * tcpip.c: patch #8241: Fix implicit declaration of ip_input with LWIP_TCPIP_CORE_LOCKING_INPUT disabled 2014-01-14: chrysn * timers.c: patch #8244 make timeouts usable reliably from outside of the timeout routine 2014-01-10: Simon Goldschmidt * ip_frag.c, ip6_frag.c: fixed bug #41041 Potential use-after-free in IPv6 reassembly 2014-01-10: Simon Goldschmidt * memp.c: fixed bug #41188 Alignment error in memp_init() when MEMP_SEPARATE_POOLS==1 2014-01-10: Simon Goldschmidt * tcp.c: fixed bug #39898 tcp_fasttmr() possible lock due to infinte queue process loop 2013-06-29: Simon Goldschmidt * inet.h, sockets.h: partially fixed bug #37585: IPv6 compatibility (in socket structs) 2013-06-29: Simon Goldschmidt * inet6.h: bug #37585/task #12600: fixed struct in6_addr.s6_addr to conform to spec 2013-04-24: patch by Liam * api_msg.c: patch #8008 Fix a potential null pointer dereference in assert 2013-04-24: Simon Goldschmidt * igmp.c: fixed possible division by zero 2013-04-24: Simon Goldschmidt * ip6.h, some ipv6 C files: fixed bug #38526 Coverity: Recursive Header Inclusion in ip6.h 2013-04-24: Simon Goldschmidt (patch by Emil Ljungdahl): * netif.c: fixed bug #38586 netif_loop_output() "deadlocks" 2013-01-15: Simon Goldschmidt * ip4.c: fixed bug #37665 ip_canforward operates on address in wrong byte order 2013-01-15: Simon Goldschmidt * pbuf.h: fixed bug #38097 pbuf_free_ooseq() warning 2013-01-14: Simon Goldschmidt * dns.c: fixed bug #37705 Possible memory corruption in DNS query 2013-01-11: Simon Goldschmidt * raw.c: fixed bug #38066 Raw pcbs can alter packet without eating it 2012-09-26: Simon Goldschmidt * api_msg.c: fixed bug #37405 'err_tcp()' uses already freed 'netconn' object 2012-09-26: patch by Henrik Persson * dhcp.c: patch #7843 Fix corner case with dhcp timeouts 2012-09-26: patch by Henrik Persson * dhcp.c: patch #7840 Segfault in dhcp_parse_reply if no end marker in dhcp packet 2012-08-22: Simon Goldschmidt * memp.c: fixed bug #37166: memp_sanity check loops itself 2012-08-13: Simon Goldschmidt * dhcp.c: fixed bug #36645: Calling dhcp_release before dhcp_start dereferences NULL 2012-08-13: Simon Goldschmidt * msg_out.c: fixed bug #36840 snmp_send_trap() NULL de-reference if traps configured but no interfaces available 2012-08-13: Simon Goldschmidt * dns.c: fixed bug #36899 DNS TTL 0 is cached for a long time 2012-05-11: Simon Goldschmidt (patch by Marty) * memp.c: fixed bug #36412: memp.c does not compile when MEMP_OVERFLOW_CHECK > zero and MEMP_SEPARATE_POOLS == 1 2012-05-08: Simon Goldschmidt * tcp_out.c: fixed bug #36380: unsent_oversize mismatch in 1.4.1RC1 (this was a debug-check issue only) 2012-05-03: Simon Goldschmidt (patch by Sylvain Rochet) * ppp.c: fixed bug #36283 (PPP struct used on header size computation and not packed) 2012-05-03: Simon Goldschmidt (patch by David Empson) * ppp.c: fixed bug #36388 (PPP: checksum-only in last pbuf leads to pbuf with zero length) 2012-03-27: Simon Goldschmidt * vj.c: fixed bug #35756 header length calculation problem in ppp/vj.c 2012-03-27: Simon Goldschmidt (patch by Mason) * tcp_out.c: fixed bug #35945: SYN packet should provide the recv MSS not the send MSS 2012-03-25: Simon Goldschmidt * api_msg.c: Fixed bug #35817: do_connect() invalidly signals op_completed for UDP/RAW with LWIP_TCPIP_CORE_LOCKING==1 2012-03-25: Simon Goldschmidt * api_msg.h, api_lib.c, api_msg.c, netifapi.c: fixed bug #35931: Name space pollution in api_msg.c and netifapi.c 2012-03-22: Simon Goldschmidt * ip4.c: fixed bug #35927: missing refragmentaion in ip_forward 2012-03-20: Simon Goldschmidt (patch by Mason) * netdb.c: fixed bug #35907: lwip_gethostbyname_r returns an invalid h_addr_list 2012-03-12: Simon Goldschmidt (patch by Bostjan Meglic) * ppp.c: fixed bug #35809: PPP GetMask(): Compiler warning on big endian, possible bug on little endian system 2012-02-23: Simon Goldschmidt * etharp.c: fixed bug #35595: Impossible to send broadcast without a gateway (introduced when fixing bug# 33551) 2012-02-16: Simon Goldschmidt * ppp.c: fixed pbuf leak when PPP session is aborted through pppSigHUP() (bug #35541: PPP Memory Leak) 2012-02-16: Simon Goldschmidt * etharp.c: fixed bug #35531: Impossible to send multicast without a gateway (introduced when fixing bug# 33551) 2012-02-16: Simon Goldschmidt (patch by Stéphane Lesage) * msg_in.c, msg_out.c: fixed bug #35536 SNMP: error too big response is malformed 2012-02-15: Simon Goldschmidt * init.c: fixed bug #35537: MEMP_NUM_* sanity checks should be disabled with MEMP_MEM_MALLOC==1 2012-02-12: Simon Goldschmidt * tcp.h, tcp_in.c, tcp_out.c: partly fixed bug #25882: TCP hangs on MSS > pcb->snd_wnd (by not creating segments bigger than half the window) 2012-02-11: Simon Goldschmidt * tcp.c: fixed bug #35435: No pcb state check before adding it to time-wait queue while closing 2012-01-22: Simon Goldschmidt * tcp.c, tcp_in.c: fixed bug #35305: pcb may be freed too early on shutdown(WR) 2012-01-21: Simon Goldschmidt * tcp.c: fixed bug #34636: FIN_WAIT_2 - Incorrect shutdown of TCP pcb 2012-01-20: Simon Goldschmidt * dhcp.c: fixed bug #35151: DHCP asserts on incoming option lengths 2012-01-20: Simon Goldschmidt * pbuf.c: fixed bug #35291: NULL pointer in pbuf_copy 2011-11-25: Simon Goldschmidt * tcp.h/.c, tcp_impl.h, tcp_in.c: fixed bug #31177: tcp timers can corrupt tcp_active_pcbs in some cases 2011-11-23: Simon Goldschmidt * sys.c: fixed bug #34884: sys_msleep() body needs to be surrounded with '#ifndef sys_msleep' 2011-11-22: Simon Goldschmidt * netif.c, etharp.h/.c: fixed bug #34684: Clear the arp table cache when netif is brought down 2011-10-28: Simon Goldschmidt * tcp_in.c: fixed bug #34638: Dead code in tcp_receive - pcb->dupacks 2011-10-23: Simon Goldschmidt * mem.c: fixed bug #34429: possible memory corruption with LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT set to 1 2011-10-18: Simon Goldschmidt * arch.h, netdb.c: fixed bug #34592: lwip_gethostbyname_r uses nonstandard error value 2011-10-18: Simon Goldschmidt * opt.h: fixed default values of TCP_SNDLOWAT and TCP_SNDQUEUELOWAT for small windows (bug #34176 select after non-blocking send times out) 2011-10-18: Simon Goldschmidt * tcp_impl.h, tcp_out.c: fixed bug #34587: TCP_BUILD_MSS_OPTION doesn't consider netif->mtu, causes slow network 2011-10-18: Simon Goldschmidt * sockets.c: fixed bug #34581 missing parentheses in udplite sockets code 2011-10-18: Simon Goldschmidt * sockets.h: fixed bug #34580 fcntl() is missing in LWIP_COMPAT_SOCKETS 2011-10-17: Simon Goldschmidt * api_msg.c: fixed bug #34569: shutdown(SHUT_WR) crashes netconn/socket api 2011-10-13: Simon Goldschmidt * tcp_in.c, tcp_out.c: fixed bug #34517 (persist timer is started although no zero window is received) by starting the persist timer when a zero window is received, not when we have more data queued for sending than fits into the window 2011-10-13: Simon Goldschmidt * def.h, timers.c: fixed bug #34541: LWIP_U32_DIFF is unnecessarily complex 2011-10-13: Simon Goldschmidt * sockets.c, api_lib.c: fixed bug #34540: compiler error when CORE_LOCKING is used and not all protocols are enabled 2011-10-12: Simon Goldschmidt * pbuf.c: fixed bug #34534: Error in sending fragmented IP if MEM_ALIGNMENT > 4 2011-10-09: Simon Goldschmidt * tcp_out.c: fixed bug #34426: tcp_zero_window_probe() transmits incorrect byte value when pcb->unacked != NULL 2011-10-09: Simon Goldschmidt * ip4.c: fixed bug #34447 LWIP_IP_ACCEPT_UDP_PORT(dst_port) wrong 2011-09-27: Simon Goldschmidt * tcp_in.c, tcp_out.c: Reset pcb->unsent_oversize in 2 more places... 2011-09-27: Simon Goldschmidt * tcp_in.c: fixed bug #28288: Data after FIN in oos queue 2011-09-27: Simon Goldschmidt * dhcp.c: fixed bug #34406 dhcp_option_hostname() can overflow the pbuf 2011-09-24: Simon Goldschmidt * mem.h: fixed bug #34377 MEM_SIZE_F is not defined if MEM_LIBC_MALLOC==1 2011-09-23: Simon Goldschmidt * pbuf.h, tcp.c, tcp_in.c: fixed bug #33871: rejecting TCP_EVENT_RECV() for the last packet including FIN can lose data 2011-09-22: Simon Goldschmidt * tcp_impl.h: fixed bug #34355: nagle does not take snd_buf/snd_queuelen into account 2011-09-21: Simon Goldschmidt * opt.h: fixed default value of TCP_SND_BUF to not violate the sanity checks in init.c 2011-09-20: Simon Goldschmidt * timers.c: fixed bug #34337 (possible NULL pointer in sys_check_timeouts) 2011-09-11: Simon Goldschmidt * tcp_out.c: use pcb->mss instead of TCP_MSS for preallocate mss-sized pbufs (bug #34019) 2011-09-09: Simon Goldschmidt * udp.c: fixed bug #34072: UDP broadcast is received from wrong UDP pcb if udp port matches 2011-09-03: Simon Goldschmidt * tcp_in.c: fixed bug #33952 PUSH flag in incoming packet is lost when packet is aggregated and sent to application 2011-09-01: Simon Goldschmidt * opt.h: fixed bug #31809 LWIP_EVENT_API in opts.h is inconsistent compared to other options 2011-09-01: Simon Goldschmidt * tcp_in.c: fixed bug #34111 RST for ACK to listening pcb has wrong seqno 2011-08-24: Simon Goldschmidt * inet6.h: fixed bug #34124 struct in6_addr does not conform to the standard 2011-08-24: Simon Goldschmidt * api_msg.c, sockets.c: fixed bug #33956 Wrong error returned when calling accept() on UDP connections 2011-08-24: Simon Goldschmidt * sockets.h: fixed bug #34057 socklen_t should be a typedef 2011-08-24: Simon Goldschmidt * pbuf.c: fixed bug #34112 Odd check in pbuf_alloced_custom (typo) 2011-08-24: Simon Goldschmidt * dhcp.c: fixed bug #34122 dhcp: hostname can overflow 2011-08-24: Simon Goldschmidt * netif.c: fixed bug #34121 netif_add/netif_set_ipaddr fail on NULL ipaddr 2011-08-22: Simon Goldschmidt * tcp_out.c: fixed bug #33962 TF_FIN not always set after FIN is sent. (This merely prevents nagle from not transmitting fast after closing.) 2011-07-22: Simon Goldschmidt * api_lib.c, api_msg.c, sockets.c, api.h: fixed bug #31084 (socket API returns always EMSGSIZE on non-blocking sockets if data size > send buffers) -> now lwip_send() sends as much as possible for non-blocking sockets 2011-07-22: Simon Goldschmidt * pbuf.c/.h, timers.c: freeing ooseq pbufs when the pbuf pool is empty implemented for NO_SYS==1: when not using sys_check_timeouts(), call PBUF_CHECK_FREE_OOSEQ() at regular intervals from main level. 2011-07-21: Simon Goldschmidt * etharp.c: fixed bug #33551 (ARP entries may time out although in use) by sending an ARP request when an ARP entry is used in the last minute before it would time out. 2011-07-04: Simon Goldschmidt * sys_arch.txt: Fixed documentation after changing sys arch prototypes for 1.4.0. 2011-06-26: Simon Goldschmidt * tcp.c: fixed bug #31723 (tcp_kill_prio() kills pcbs with the same prio) by updating its documentation only. 2011-06-26: Simon Goldschmidt * mem.c: fixed bug #33545: With MEM_USE_POOLS==1, mem_malloc can return an unaligned pointer. 2011-06-26: Simon Goldschmidt * mem.c: fixed bug #33544 "warning in mem.c in lwip 1.4.0 with NO_SYS=1" (STABLE-1.4.0) ++ New features: 2011-03-27: Simon Goldschmidt * tcp_impl.h, tcp_in.c, tcp_out.c: Removed 'dataptr' from 'struct tcp_seg' and calculate it in tcp_zero_window_probe (the only place where it was used). 2010-11-21: Simon Goldschmidt * dhcp.c/.h: Added a function to deallocate the struct dhcp from a netif (fixes bug #31525). 2010-07-12: Simon Goldschmidt (patch by Stephane Lesage) * ip.c, udp.c/.h, pbuf.h, sockets.c: task #10495: Added support for IP_MULTICAST_LOOP at socket- and raw-API level. 2010-06-16: Simon Goldschmidt * ip.c: Added an optional define (LWIP_IP_ACCEPT_UDP_PORT) that can allow link-layer-addressed UDP traffic to be received while a netif is down (just like DHCP during configuration) 2010-05-22: Simon Goldschmidt * many many files: bug #27352: removed packing from ip_addr_t, the packed version is now only used in protocol headers. Added global storage for current src/dest IP address while in input functions. 2010-05-16: Simon Goldschmidt * def.h: task #10391: Add preprocessor-macros for compile-time htonl calculation (and use them throughout the stack where applicable) 2010-05-16: Simon Goldschmidt * opt.h, memp_std.h, memp.c, ppp_oe.h/.c: PPPoE now uses its own MEMP pool instead of the heap (moved struct pppoe_softc from ppp_oe.c to ppp_oe.h) 2010-05-16: Simon Goldschmidt * opt.h, memp_std.h, dns.h/.c: DNS_LOCAL_HOSTLIST_IS_DYNAMIC uses its own MEMP pool instead of the heap 2010-05-13: Simon Goldschmidt * tcp.c, udp.c: task #6995: Implement SO_REUSEADDR (correctly), added new option SO_REUSE_RXTOALL to pass received UDP broadcast/multicast packets to more than one pcb. 2010-05-02: Simon Goldschmidt * netbuf.h/.c, sockets.c, api_msg.c: use checksum-on-copy for sending UDP data for LWIP_NETIF_TX_SINGLE_PBUF==1 2010-04-30: Simon Goldschmidt * udp.h/.c, pbuf.h/.c: task #6849: added udp_send(_to/_if) functions that take a precalculated checksum, added pbuf_fill_chksum() to copy data into a pbuf and at the same time calculating the checksum for that data 2010-04-29: Simon Goldschmidt * ip_addr.h, etharp.h/.c, autoip.c: Create overridable macros for copying 2-byte-aligned IP addresses and MAC addresses 2010-04-28: Patch by Bill Auerbach * ip.c: Inline generating IP checksum to save a function call 2010-04-14: Simon Goldschmidt * tcpip.h/.c, timers.c: Added an overridable define to get informed when the tcpip_thread processes messages or timeouts to implement a watchdog. 2010-03-28: Simon Goldschmidt * ip_frag.c: create a new (contiguous) PBUF_RAM for every outgoing fragment if LWIP_NETIF_TX_SINGLE_PBUF==1 2010-03-27: Simon Goldschmidt * etharp.c: Speedup TX by moving code from find_entry to etharp_output/ etharp_query to prevent unnecessary function calls (inspired by patch #7135). 2010-03-20: Simon Goldschmidt * opt.h, tcpip.c/.h: Added an option to disable tcpip_(un)timeout code since the linker cannot do this automatically to save space. 2010-03-20: Simon Goldschmidt * opt.h, etharp.c/.h: Added support for static ARP table entries 2010-03-14: Simon Goldschmidt * tcp_impl.h, tcp_out.c, inet_chksum.h/.c: task #6849: Calculate checksum when creating TCP segments, not when (re-)transmitting them. 2010-03-07: Simon Goldschmidt * sockets.c: bug #28775 (select/event_callback: only check select_cb_list on change) plus use SYS_LIGHTWEIGHT_PROT to protect the select code. This should speed up receiving data on sockets as the select code in event_callback is only executed when select is waiting. 2010-03-06: Simon Goldschmidt * tcp_out.c: task #7013 (Create option to have all packets delivered to netif->output in one piece): Always copy to try to create single pbufs in tcp_write. 2010-03-06: Simon Goldschmidt * api.h, api_lib.c, sockets.c: task #10167 (sockets: speed up TCP recv by not allocating a netbuf): added function netconn_recv_tcp_pbuf() for tcp netconns to receive pbufs, not netbufs; use that function for tcp sockets. 2010-03-05: Jakob Ole Stoklundsen / Simon Goldschmidt * opt.h, tcp.h, tcp_impl.h, tcp.c, tcp_in.c, tcp_out.c: task #7040: Work on tcp_enqueue: Don't waste memory when chaining segments, added option TCP_OVERSIZE to prevent creating many small pbufs when calling tcp_write with many small blocks of data. Instead, pbufs are allocated larger than needed and the space is used for later calls to tcp_write. 2010-02-21: Simon Goldschmidt * stats.c/.h: Added const char* name to mem- and memp-stats for easier debugging. 2010-02-21: Simon Goldschmidt * tcp.h (and usages), added tcp_impl.h: Splitted API and internal implementation of tcp to make API usage cleare to application programmers 2010-02-14: Simon Goldschmidt/Stephane Lesage * ip_addr.h: Improved some defines working on ip addresses, added faster macro to copy addresses that cannot be NULL 2010-02-13: Simon Goldschmidt * api.h, api_lib.c, api_msg.c, sockets.c: task #7865 (implement non- blocking send operation) 2010-02-12: Simon Goldschmidt * sockets.c/.h: Added a minimal version of posix fctl() to have a standardised way to set O_NONBLOCK for nonblocking sockets. 2010-02-12: Simon Goldschmidt * dhcp.c/.h, autoip.c/.h: task #10139 (Prefer statically allocated memory): added autoip_set_struct() and dhcp_set_struct() to let autoip and dhcp work with user-allocated structs instead of callin mem_malloc 2010-02-12: Simon Goldschmidt/Jeff Barber * tcp.c/h: patch #6865 (SO_REUSEADDR for TCP): if pcb.so_options has SOF_REUSEADDR set, allow binding to endpoint in TIME_WAIT 2010-02-12: Simon Goldschmidt * sys layer: task #10139 (Prefer statically allocated memory): converted mbox and semaphore functions to take pointers to sys_mbox_t/sys_sem_t; converted sys_mbox_new/sys_sem_new to take pointers and return err_t; task #7212: Add Mutex concept in sys_arch (define LWIP_COMPAT_MUTEX to let sys.h use binary semaphores instead of mutexes - as before) 2010-02-09: Simon Goldschmidt (Simon Kallweit) * timers.c/.h: Added function sys_restart_timeouts() from patch #7085 (Restart system timeout handling) 2010-02-09: Simon Goldschmidt * netif.c/.h, removed loopif.c/.h: task #10153 (Integrate loopif into netif.c) - loopif does not have to be created by the port any more, just define LWIP_HAVE_LOOPIF to 1. 2010-02-08: Simon Goldschmidt * inet.h, ip_addr.c/.h: Added reentrant versions of inet_ntoa/ipaddr_ntoa inet_ntoa_r/ipaddr_ntoa_r 2010-02-08: Simon Goldschmidt * netif.h: Added netif_s/get_igmp_mac_filter() macros 2010-02-05: Simon Goldschmidt * netif.h: Added function-like macros to get/set the hostname on a netif 2010-02-04: Simon Goldschmidt * nearly every file: Replaced struct ip_addr by typedef ip_addr_t to make changing the actual implementation behind the typedef easier. 2010-02-01: Simon Goldschmidt * opt.h, memp_std.h, dns.h, netdb.c, memp.c: Let netdb use a memp pool for allocating memory when getaddrinfo() is called. 2010-01-31: Simon Goldschmidt * dhcp.h, dhcp.c: Reworked the code that parses DHCP options: parse them once instead of parsing for every option. This also removes the need for mem_malloc from dhcp_recv and makes it possible to correctly retrieve the BOOTP file. 2010-01-30: simon Goldschmidt * sockets.c: Use SYS_LIGHTWEIGHT_PROT instead of a semaphore to protect the sockets array. 2010-01-29: Simon Goldschmidt (patch by Laura Garrett) * api.h, api_msg.c, sockets.c: Added except set support in select (patch #6860) 2010-01-29: Simon Goldschmidt (patch by Laura Garrett) * api.h, sockets.h, err.h, api_lib.c, api_msg.c, sockets.c, err.c: Add non-blocking support for connect (partly from patch #6860), plus many cleanups in socket & netconn API. 2010-01-27: Simon Goldschmidt * opt.h, tcp.h, init.c, api_msg.c: Added TCP_SNDQUEUELOWAT corresponding to TCP_SNDLOWAT and added tcp_sndqueuelen() - this fixes bug #28605 2010-01-26: Simon Goldschmidt * snmp: Use memp pools for snmp instead of the heap; added 4 new pools. 2010-01-14: Simon Goldschmidt * ppp.c/.h: Fixed bug #27856: PPP: Set netif link- and status-callback by adding ppp_set_netif_statuscallback()/ppp_set_netif_linkcallback() 2010-01-13: Simon Goldschmidt * mem.c: The heap now may be moved to user-defined memory by defining LWIP_RAM_HEAP_POINTER as a void pointer to that memory's address (patch #6966 and bug #26133) 2010-01-10: Simon Goldschmidt (Bill Auerbach) * opt.h, memp.c: patch #6822 (Add option to place memory pools in separate arrays) 2010-01-10: Simon Goldschmidt * init.c, igmp.c: patch #6463 (IGMP - Adding Random Delay): added define LWIP_RAND() for lwip-wide randomization (to be defined in cc.h) 2009-12-31: Simon Goldschmidt * tcpip.c, init.c, memp.c, sys.c, memp_std.h, sys.h, tcpip.h added timers.c/.h: Separated timer implementation from semaphore/mbox implementation, moved timer implementation to timers.c/.h, timers are now only called from tcpip_thread or by explicitly checking them. (TASK#7235) 2009-12-27: Simon Goldschmidt * opt.h, etharp.h/.c, init.c, tcpip.c: Added an additional option LWIP_ETHERNET to support ethernet without ARP (necessary for pure PPPoE) ++ Bugfixes: 2011-04-20: Simon Goldschmidt * sys_arch.txt: sys_arch_timeouts() is not needed any more. 2011-04-13: Simon Goldschmidt * tcp.c, udp.c: Fixed bug #33048 (Bad range for IP source port numbers) by using ports in the IANA private/dynamic range (49152 through 65535). 2011-03-29: Simon Goldschmidt, patch by Emil Lhungdahl: * etharp.h/.c: Fixed broken VLAN support. 2011-03-27: Simon Goldschmidt * tcp.c: Fixed bug #32926 (TCP_RMV(&tcp_bound_pcbs) is called on unbound tcp pcbs) by checking if the pcb was bound (local_port != 0). 2011-03-27: Simon Goldschmidt * ppp.c: Fixed bug #32280 (ppp: a pbuf is freed twice) 2011-03-27: Simon Goldschmidt * sockets.c: Fixed bug #32906: lwip_connect+lwip_send did not work for udp and raw pcbs with LWIP_TCPIP_CORE_LOCKING==1. 2011-03-27: Simon Goldschmidt * tcp_out.c: Fixed bug #32820 (Outgoing TCP connections created before route is present never times out) by starting retransmission timer before checking route. 2011-03-22: Simon Goldschmidt * ppp.c: Fixed bug #32648 (PPP code crashes when terminating a link) by only calling sio_read_abort() if the file descriptor is valid. 2011-03-14: Simon Goldschmidt * err.h/.c, sockets.c, api_msg.c: fixed bug #31748 (Calling non-blocking connect more than once can render a socket useless) since it mainly involves changing "FATAL" classification of error codes: ERR_USE and ERR_ISCONN just aren't fatal. 2011-03-13: Simon Goldschmidt * sockets.c: fixed bug #32769 (ESHUTDOWN is linux-specific) by fixing err_to_errno_table (ERR_CLSD: ENOTCONN instead of ESHUTDOWN), ERR_ISCONN: use EALRADY instead of -1 2011-03-13: Simon Goldschmidt * api_lib.c: netconn_accept: return ERR_ABRT instead of ERR_CLSD if the connection has been aborted by err_tcp (since this is not a normal closing procedure). 2011-03-13: Simon Goldschmidt * tcp.c: tcp_bind: return ERR_VAL instead of ERR_ISCONN when trying to bind with pcb->state != CLOSED 2011-02-17: Simon Goldschmidt * rawapi.txt: Fixed bug #32561 tcp_poll argument definition out-of-order in documentation 2011-02-17: Simon Goldschmidt * many files: Added missing U/UL modifiers to fix 16-bit-arch portability. 2011-01-24: Simon Goldschmidt * sockets.c: Fixed bug #31741: lwip_select seems to have threading problems 2010-12-02: Simon Goldschmidt * err.h: Fixed ERR_IS_FATAL so that ERR_WOULDBLOCK is not fatal. 2010-11-23: Simon Goldschmidt * api.h, api_lib.c, api_msg.c, sockets.c: netconn.recv_avail is only used for LWIP_SO_RCVBUF and ioctl/FIONREAD. 2010-11-23: Simon Goldschmidt * etharp.c: Fixed bug #31720: ARP-queueing: RFC 1122 recommends to queue at least 1 packet -> ARP_QUEUEING==0 now queues the most recent packet. 2010-11-23: Simon Goldschmidt * tcp_in.c: Fixed bug #30577: tcp_input: don't discard ACK-only packets after refusing 'refused_data' again. 2010-11-22: Simon Goldschmidt * sockets.c: Fixed bug #31590: getsockopt(... SO_ERROR ...) gives EINPROGRESS after a successful nonblocking connection. 2010-11-22: Simon Goldschmidt * etharp.c: Fixed bug #31722: IP packets sent with an AutoIP source addr must be sent link-local 2010-11-22: Simon Goldschmidt * timers.c: patch #7329: tcp_timer_needed prototype was ifdef'ed out for LWIP_TIMERS==0 2010-11-20: Simon Goldschmidt * sockets.c: Fixed bug #31170: lwip_setsockopt() does not set socket number 2010-11-20: Simon Goldschmidt * sockets.h: Fixed bug #31304: Changed SHUT_RD, SHUT_WR and SHUT_RDWR to resemble other stacks. 2010-11-20: Simon Goldschmidt * dns.c: Fixed bug #31535: TCP_SND_QUEUELEN must be at least 2 or else no-copy TCP writes will never succeed. 2010-11-20: Simon Goldschmidt * dns.c: Fixed bug #31701: Error return value from dns_gethostbyname() does not match documentation: return ERR_ARG instead of ERR_VAL if not initialized or wrong argument. 2010-10-20: Simon Goldschmidt * sockets.h: Fixed bug #31385: sizeof(struct sockaddr) is 30 but should be 16 2010-10-05: Simon Goldschmidt * dhcp.c: Once again fixed #30038: DHCP/AutoIP cooperation failed when replugging the network cable after an AutoIP address was assigned. 2010-08-10: Simon Goldschmidt * tcp.c: Fixed bug #30728: tcp_new_port() did not check listen pcbs 2010-08-03: Simon Goldschmidt * udp.c, raw.c: Don't chain empty pbufs when sending them (fixes bug #30625) 2010-08-01: Simon Goldschmidt (patch by Greg Renda) * ppp.c: Applied patch #7264 (PPP protocols are rejected incorrectly on big endian architectures) 2010-07-28: Simon Goldschmidt * api_lib.c, api_msg.c, sockets.c, mib2.c: Fixed compilation with TCP or UDP disabled. 2010-07-27: Simon Goldschmidt * tcp.c: Fixed bug #30565 (tcp_connect() check bound list): that check did no harm but never did anything 2010-07-21: Simon Goldschmidt * ip.c: Fixed invalid fix for bug #30402 (CHECKSUM_GEN_IP_INLINE does not add IP options) 2010-07-16: Kieran Mansley * msg_in.c: Fixed SNMP ASN constant defines to not use ! operator 2010-07-10: Simon Goldschmidt * ip.c: Fixed bug #30402: CHECKSUM_GEN_IP_INLINE does not add IP options 2010-06-30: Simon Goldschmidt * api_msg.c: fixed bug #30300 (shutdown parameter was not initialized in netconn_delete) 2010-06-28: Kieran Mansley * timers.c remove unportable printing of C function pointers 2010-06-24: Simon Goldschmidt * init.c, timers.c/.h, opt.h, memp_std.h: From patch #7221: added flag NO_SYS_NO_TIMERS to drop timer support for NO_SYS==1 for easier upgrading 2010-06-24: Simon Goldschmidt * api(_lib).c/.h, api_msg.c/.h, sockets.c/.h: Fixed bug #10088: Correctly implemented shutdown at socket level. 2010-06-21: Simon Goldschmidt * pbuf.c/.h, ip_frag.c/.h, opt.h, memp_std.h: Fixed bug #29361 (ip_frag has problems with zero-copy DMA MACs) by adding custom pbufs and implementing custom pbufs that reference other (original) pbufs. Additionally set IP_FRAG_USES_STATIC_BUF=0 as default to be on the safe side. 2010-06-15: Simon Goldschmidt * dhcp.c: Fixed bug #29970: DHCP endian issue parsing option responses 2010-06-14: Simon Goldschmidt * autoip.c: Fixed bug #30039: AutoIP does not reuse previous addresses 2010-06-12: Simon Goldschmidt * dhcp.c: Fixed bug #30038: dhcp_network_changed doesn't reset AUTOIP coop state 2010-05-17: Simon Goldschmidt * netdb.c: Correctly NULL-terminate h_addr_list 2010-05-16: Simon Goldschmidt * def.h/.c: changed the semantics of LWIP_PREFIX_BYTEORDER_FUNCS to prevent "symbol already defined" i.e. when linking to winsock 2010-05-05: Simon Goldschmidt * def.h, timers.c: Fixed bug #29769 (sys_check_timeouts: sys_now() may overflow) 2010-04-21: Simon Goldschmidt * api_msg.c: Fixed bug #29617 (sometime cause stall on delete listening connection) 2010-03-28: Luca Ceresoli * ip_addr.c/.h: patch #7143: Add a few missing const qualifiers 2010-03-27: Luca Ceresoli * mib2.c: patch #7130: remove meaningless const qualifiers 2010-03-26: Simon Goldschmidt * tcp_out.c: Make LWIP_NETIF_TX_SINGLE_PBUF work for TCP, too 2010-03-26: Simon Goldschmidt * various files: Fixed compiling with different options disabled (TCP/UDP), triggered by bug #29345; don't allocate acceptmbox if LWIP_TCP is disabled 2010-03-25: Simon Goldschmidt * sockets.c: Fixed bug #29332: lwip_select() processes readset incorrectly 2010-03-25: Simon Goldschmidt * tcp_in.c, test_tcp_oos.c: Fixed bug #29080: Correctly handle remote side overrunning our rcv_wnd in ooseq case. 2010-03-22: Simon Goldschmidt * tcp.c: tcp_listen() did not copy the pcb's prio. 2010-03-19: Simon Goldschmidt * snmp_msg.c: Fixed bug #29256: SNMP Trap address was not correctly set 2010-03-14: Simon Goldschmidt * opt.h, etharp.h: Fixed bug #29148 (Incorrect PBUF_POOL_BUFSIZE for ports where ETH_PAD_SIZE > 0) by moving definition of ETH_PAD_SIZE to opt.h and basing PBUF_LINK_HLEN on it. 2010-03-08: Simon Goldschmidt * netif.c, ipv4/ip.c: task #10241 (AutoIP: don't break existing connections when assiging routable address): when checking incoming packets and aborting existing connection on address change, filter out link-local addresses. 2010-03-06: Simon Goldschmidt * sockets.c: Fixed LWIP_NETIF_TX_SINGLE_PBUF for LWIP_TCPIP_CORE_LOCKING 2010-03-06: Simon Goldschmidt * ipv4/ip.c: Don't try to forward link-local addresses 2010-03-06: Simon Goldschmidt * etharp.c: Fixed bug #29087: etharp: don't send packets for LinkLocal- addresses to gw 2010-03-05: Simon Goldschmidt * dhcp.c: Fixed bug #29072: Correctly set ciaddr based on message-type and state. 2010-03-05: Simon Goldschmidt * api_msg.c: Correctly set TCP_WRITE_FLAG_MORE when netconn_write is split into multiple calls to tcp_write. 2010-02-21: Simon Goldschmidt * opt.h, mem.h, dns.c: task #10140: Remove DNS_USES_STATIC_BUF (keep the implementation of DNS_USES_STATIC_BUF==1) 2010-02-20: Simon Goldschmidt * tcp.h, tcp.c, tcp_in.c, tcp_out.c: Task #10088: Correctly implement close() vs. shutdown(). Now the application does not get any more recv callbacks after calling tcp_close(). Added tcp_shutdown(). 2010-02-19: Simon Goldschmidt * mem.c/.h, pbuf.c: Renamed mem_realloc() to mem_trim() to prevent confusion with realloc() 2010-02-15: Simon Goldschmidt/Stephane Lesage * netif.c/.h: Link status does not depend on LWIP_NETIF_LINK_CALLBACK (fixes bug #28899) 2010-02-14: Simon Goldschmidt * netif.c: Fixed bug #28877 (Duplicate ARP gratuitous packet with LWIP_NETIF_LINK_CALLBACK set on) by only sending if both link- and admin-status of a netif are up 2010-02-14: Simon Goldschmidt * opt.h: Disable ETHARP_TRUST_IP_MAC by default since it slows down packet reception and is not really necessary 2010-02-14: Simon Goldschmidt * etharp.c/.h: Fixed ARP input processing: only add a new entry if a request was directed as us (RFC 826, Packet Reception), otherwise only update existing entries; internalized some functions 2010-02-14: Simon Goldschmidt * netif.h, etharp.c, tcpip.c: Fixed bug #28183 (ARP and TCP/IP cannot be disabled on netif used for PPPoE) by adding a new netif flag (NETIF_FLAG_ETHERNET) that tells the stack the device is an ethernet device but prevents usage of ARP (so that ethernet_input can be used for PPPoE). 2010-02-12: Simon Goldschmidt * netif.c: netif_set_link_up/down: only do something if the link state actually changes 2010-02-12: Simon Goldschmidt/Stephane Lesage * api_msg.c: Fixed bug #28865 (Cannot close socket/netconn in non-blocking connect) 2010-02-12: Simon Goldschmidt * mem.h: Fixed bug #28866 (mem_realloc function defined in mem.h) 2010-02-09: Simon Goldschmidt * api_lib.c, api_msg.c, sockets.c, api.h, api_msg.h: Fixed bug #22110 (recv() makes receive window update for data that wasn't received by application) 2010-02-09: Simon Goldschmidt/Stephane Lesage * sockets.c: Fixed bug #28853 (lwip_recvfrom() returns 0 on receive time-out or any netconn_recv() error) 2010-02-09: Simon Goldschmidt * ppp.c: task #10154 (PPP: Update snmp in/out counters for tx/rx packets) 2010-02-09: Simon Goldschmidt * netif.c: For loopback packets, adjust the stats- and snmp-counters for the loopback netif. 2010-02-08: Simon Goldschmidt * igmp.c/.h, ip.h: Moved most defines from igmp.h to igmp.c for clarity since they are not used anywhere else. 2010-02-08: Simon Goldschmidt (Stéphane Lesage) * igmp.c, igmp.h, stats.c, stats.h: Improved IGMP stats (patch from bug #28798) 2010-02-08: Simon Goldschmidt (Stéphane Lesage) * igmp.c: Fixed bug #28798 (Error in "Max Response Time" processing) and another bug when LWIP_RAND() returns zero. 2010-02-04: Simon Goldschmidt * nearly every file: Use macros defined in ip_addr.h (some of them new) to work with IP addresses (preparation for bug #27352 - Change ip_addr from struct to typedef (u32_t) - and better code). 2010-01-31: Simon Goldschmidt * netif.c: Don't call the link-callback from netif_set_up/down() since this invalidly retriggers DHCP. 2010-01-29: Simon Goldschmidt * ip_addr.h, inet.h, def.h, inet.c, def.c, more: Cleanly separate the portability file inet.h and its contents from the stack: moved htonX- functions to def.h (and the new def.c - they are not ipv4 dependent), let inet.h depend on ip_addr.h and not the other way round. This fixes bug #28732. 2010-01-28: Kieran Mansley * tcp.c: Ensure ssthresh >= 2*MSS 2010-01-27: Simon Goldschmidt * tcp.h, tcp.c, tcp_in.c: Fixed bug #27871: Calling tcp_abort() in recv callback can lead to accessing unallocated memory. As a consequence, ERR_ABRT means the application has called tcp_abort()! 2010-01-25: Simon Goldschmidt * snmp_structs.h, msg_in.c: Partly fixed bug #22070 (MIB_OBJECT_WRITE_ONLY not implemented in SNMP): write-only or not-accessible are still returned by getnext (though not by get) 2010-01-24: Simon Goldschmidt * snmp: Renamed the private mib node from 'private' to 'mib_private' to not use reserved C/C++ keywords 2010-01-23: Simon Goldschmidt * sockets.c: Fixed bug #28716: select() returns 0 after waiting for less than 1 ms 2010-01-21: Simon Goldschmidt * tcp.c, api_msg.c: Fixed bug #28651 (tcp_connect: no callbacks called if tcp_enqueue fails) both in raw- and netconn-API 2010-01-19: Simon Goldschmidt * api_msg.c: Fixed bug #27316: netconn: Possible deadlock in err_tcp 2010-01-18: Iordan Neshev/Simon Goldschmidt * src/netif/ppp: reorganised PPP sourcecode to 2.3.11 including some bugfix backports from 2.4.x. 2010-01-18: Simon Goldschmidt * mem.c: Fixed bug #28679: mem_realloc calculates mem_stats wrong 2010-01-17: Simon Goldschmidt * api_lib.c, api_msg.c, (api_msg.h, api.h, sockets.c, tcpip.c): task #10102: "netconn: clean up conn->err threading issues" by adding error return value to struct api_msg_msg 2010-01-17: Simon Goldschmidt * api.h, api_lib.c, sockets.c: Changed netconn_recv() and netconn_accept() to return err_t (bugs #27709 and #28087) 2010-01-14: Simon Goldschmidt * ...: Use typedef for function prototypes throughout the stack. 2010-01-13: Simon Goldschmidt * api_msg.h/.c, api_lib.c: Fixed bug #26672 (close connection when receive window = 0) by correctly draining recvmbox/acceptmbox 2010-01-11: Simon Goldschmidt * pap.c: Fixed bug #13315 (PPP PAP authentication can result in erroneous callbacks) by copying the code from recent pppd 2010-01-10: Simon Goldschmidt * raw.c: Fixed bug #28506 (raw_bind should filter received packets) 2010-01-10: Simon Goldschmidt * tcp.h/.c: bug #28127 (remove call to tcp_output() from tcp_ack(_now)()) 2010-01-08: Simon Goldschmidt * sockets.c: Fixed bug #28519 (lwip_recvfrom bug with len > 65535) 2010-01-08: Simon Goldschmidt * dns.c: Copy hostname for DNS_LOCAL_HOSTLIST_IS_DYNAMIC==1 since string passed to dns_local_addhost() might be volatile 2010-01-07: Simon Goldschmidt * timers.c, tcp.h: Call tcp_timer_needed() with NO_SYS==1, too 2010-01-06: Simon Goldschmidt * netdb.h: Fixed bug #28496: missing include guards in netdb.h 2009-12-31: Simon Goldschmidt * many ppp files: Reorganised PPP source code from ucip structure to pppd structure to easily compare our code against the pppd code (around v2.3.1) 2009-12-27: Simon Goldschmidt * tcp_in.c: Another fix for bug #28241 (ooseq processing) and adapted unit test (STABLE-1.3.2) ++ New features: 2009-10-27 Simon Goldschmidt/Stephan Lesage * netifapi.c/.h: Added netifapi_netif_set_addr() 2009-10-07 Simon Goldschmidt/Fabian Koch * api_msg.c, netbuf.c/.h, opt.h: patch #6888: Patch for UDP Netbufs to support dest-addr and dest-port (optional: LWIP_NETBUF_RECVINFO) 2009-08-26 Simon Goldschmidt/Simon Kallweit * slipif.c/.h: bug #26397: SLIP polling support 2009-08-25 Simon Goldschmidt * opt.h, etharp.h/.c: task #9033: Support IEEE 802.1q tagged frame (VLAN), New configuration options ETHARP_SUPPORT_VLAN and ETHARP_VLAN_CHECK. 2009-08-25 Simon Goldschmidt * ip_addr.h, netdb.c: patch #6900: added define ip_ntoa(struct ip_addr*) 2009-08-24 Jakob Stoklund Olesen * autoip.c, dhcp.c, netif.c: patch #6725: Teach AutoIP and DHCP to respond to netif_set_link_up(). 2009-08-23 Simon Goldschmidt * tcp.h/.c: Added function tcp_debug_state_str() to convert a tcp state to a human-readable string. ++ Bugfixes: 2009-12-24: Kieran Mansley * tcp_in.c Apply patches from Oleg Tyshev to improve OOS processing (BUG#28241) 2009-12-06: Simon Goldschmidt * ppp.h/.c: Fixed bug #27079 (Yet another leak in PPP): outpacket_buf can be statically allocated (like in ucip) 2009-12-04: Simon Goldschmidt (patch by Ioardan Neshev) * pap.c: patch #6969: PPP: missing PAP authentication UNTIMEOUT 2009-12-03: Simon Goldschmidt * tcp.h, tcp_in.c, tcp_out.c: Fixed bug #28106: dup ack for fast retransmit could have non-zero length 2009-12-02: Simon Goldschmidt * tcp_in.c: Fixed bug #27904: TCP sends too many ACKs: delay resetting tcp_input_pcb until after calling the pcb's callbacks 2009-11-29: Simon Goldschmidt * tcp_in.c: Fixed bug #28054: Two segments with FIN flag on the out-of- sequence queue, also fixed PBUF_POOL leak in the out-of-sequence code 2009-11-29: Simon Goldschmidt * pbuf.c: Fixed bug #28064: pbuf_alloc(PBUF_POOL) is not thread-safe by queueing a call into tcpip_thread to free ooseq-bufs if the pool is empty 2009-11-26: Simon Goldschmidt * tcp.h: Fixed bug #28098: Nagle can prevent fast retransmit from sending segment 2009-11-26: Simon Goldschmidt * tcp.h, sockets.c: Fixed bug #28099: API required to disable Nagle algorithm at PCB level 2009-11-22: Simon Goldschmidt * tcp_out.c: Fixed bug #27905: FIN isn't combined with data on unsent 2009-11-22: Simon Goldschmidt (suggested by Bill Auerbach) * tcp.c: tcp_alloc: prevent increasing stats.err for MEMP_TCP_PCB when reusing time-wait pcb 2009-11-20: Simon Goldschmidt (patch by Albert Bartel) * sockets.c: Fixed bug #28062: Data received directly after accepting does not wake up select 2009-11-11: Simon Goldschmidt * netdb.h: Fixed bug #27994: incorrect define for freeaddrinfo(addrinfo) 2009-10-30: Simon Goldschmidt * opt.h: Increased default value for TCP_MSS to 536, updated default value for TCP_WND to 4*TCP_MSS to keep delayed ACK working. 2009-10-28: Kieran Mansley * tcp_in.c, tcp_out.c, tcp.h: re-work the fast retransmission code to follow algorithm from TCP/IP Illustrated 2009-10-27: Kieran Mansley * tcp_in.c: fix BUG#27445: grow cwnd with every duplicate ACK 2009-10-25: Simon Goldschmidt * tcp.h: bug-fix in the TCP_EVENT_RECV macro (has to call tcp_recved if pcb->recv is NULL to keep rcv_wnd correct) 2009-10-25: Simon Goldschmidt * tcp_in.c: Fixed bug #26251: RST process in TIME_WAIT TCP state 2009-10-23: Simon Goldschmidt (David Empson) * tcp.c: Fixed bug #27783: Silly window avoidance for small window sizes 2009-10-21: Simon Goldschmidt * tcp_in.c: Fixed bug #27215: TCP sent() callback gives leading and trailing 1 byte len (SYN/FIN) 2009-10-21: Simon Goldschmidt * tcp_out.c: Fixed bug #27315: zero window probe and FIN 2009-10-19: Simon Goldschmidt * dhcp.c/.h: Minor code simplification (don't store received pbuf, change conditional code to assert where applicable), check pbuf length before testing for valid reply 2009-10-19: Simon Goldschmidt * dhcp.c: Removed most calls to udp_connect since they aren't necessary when using udp_sendto_if() - always stay connected to IP_ADDR_ANY. 2009-10-16: Simon Goldschmidt * ip.c: Fixed bug #27390: Source IP check in ip_input() causes it to drop valid DHCP packets -> allow 0.0.0.0 as source address when LWIP_DHCP is enabled 2009-10-15: Simon Goldschmidt (Oleg Tyshev) * tcp_in.c: Fixed bug #27329: dupacks by unidirectional data transmit 2009-10-15: Simon Goldschmidt * api_lib.c: Fixed bug #27709: conn->err race condition on netconn_recv() timeout 2009-10-15: Simon Goldschmidt * autoip.c: Fixed bug #27704: autoip starts with wrong address LWIP_AUTOIP_CREATE_SEED_ADDR() returned address in host byte order instead of network byte order 2009-10-11 Simon Goldschmidt (Jörg Kesten) * tcp_out.c: Fixed bug #27504: tcp_enqueue wrongly concatenates segments which are not consecutive when retransmitting unacked segments 2009-10-09 Simon Goldschmidt * opt.h: Fixed default values of some stats to only be enabled if used Fixes bug #27338: sys_stats is defined when NO_SYS = 1 2009-08-30 Simon Goldschmidt * ip.c: Fixed bug bug #27345: "ip_frag() does not use the LWIP_NETIF_LOOPBACK function" by checking for loopback before calling ip_frag 2009-08-25 Simon Goldschmidt * dhcp.c: fixed invalid dependency to etharp_query if DHCP_DOES_ARP_CHECK==0 2009-08-23 Simon Goldschmidt * ppp.c: bug #27078: Possible memory leak in pppInit() 2009-08-23 Simon Goldschmidt * netdb.c, dns.c: bug #26657: DNS, if host name is "localhost", result is error. 2009-08-23 Simon Goldschmidt * opt.h, init.c: bug #26649: TCP fails when TCP_MSS > TCP_SND_BUF Fixed wrong parenthesis, added check in init.c 2009-08-23 Simon Goldschmidt * ppp.c: bug #27266: wait-state debug message in pppMain occurs every ms 2009-08-23 Simon Goldschmidt * many ppp files: bug #27267: Added include to string.h where needed 2009-08-23 Simon Goldschmidt * tcp.h: patch #6843: tcp.h macro optimization patch (for little endian) (STABLE-1.3.1) ++ New features: 2009-05-10 Simon Goldschmidt * opt.h, sockets.c, pbuf.c, netbuf.h, pbuf.h: task #7013: Added option LWIP_NETIF_TX_SINGLE_PBUF to try to create transmit packets from only one pbuf to help MACs that don't support scatter-gather DMA. 2009-05-09 Simon Goldschmidt * icmp.h, icmp.c: Shrinked ICMP code, added option to NOT check icoming ECHO pbuf for size (just use it): LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN 2009-05-05 Simon Goldschmidt, Jakob Stoklund Olesen * ip.h, ip.c: Added ip_current_netif() & ip_current_header() to receive extended info about the currently received packet. 2009-04-27 Simon Goldschmidt * sys.h: Made SYS_LIGHTWEIGHT_PROT and sys_now() work with NO_SYS=1 2009-04-25 Simon Goldschmidt * mem.c, opt.h: Added option MEM_USE_POOLS_TRY_BIGGER_POOL to try the next bigger malloc pool if one is empty (only usable with MEM_USE_POOLS). 2009-04-21 Simon Goldschmidt * dns.c, init.c, dns.h, opt.h: task #7507, patch #6786: DNS supports static hosts table. New configuration options DNS_LOCAL_HOSTLIST and DNS_LOCAL_HOSTLIST_IS_DYNAMIC. Also, DNS_LOOKUP_LOCAL_EXTERN() can be defined as an external function for lookup. 2009-04-15 Simon Goldschmidt * dhcp.c: patch #6763: Global DHCP XID can be redefined to something more unique 2009-03-31 Kieran Mansley * tcp.c, tcp_out.c, tcp_in.c, sys.h, tcp.h, opts.h: add support for TCP timestamp options, off by default. Rework tcp_enqueue() to take option flags rather than specified option data 2009-02-18 Simon Goldschmidt * cc.h: Added printf formatter for size_t: SZT_F 2009-02-16 Simon Goldschmidt (patch by Rishi Khan) * icmp.c, opt.h: patch #6539: (configurable) response to broadcast- and multicast pings 2009-02-12 Simon Goldschmidt * init.h: Added LWIP_VERSION to get the current version of the stack 2009-02-11 Simon Goldschmidt (suggested by Gottfried Spitaler) * opt.h, memp.h/.c: added MEMP_MEM_MALLOC to use mem_malloc/mem_free instead of the pool allocator (can save code size with MEM_LIBC_MALLOC if libc-malloc is otherwise used) 2009-01-28 Jonathan Larmour (suggested by Bill Bauerbach) * ipv4/inet_chksum.c, ipv4/lwip/inet_chksum.h: inet_chksum_pseudo_partial() is only used by UDPLITE at present, so conditionalise it. 2008-12-03 Simon Goldschmidt (base on patch from Luca Ceresoli) * autoip.c: checked in (slightly modified) patch #6683: Customizable AUTOIP "seed" address. This should reduce AUTOIP conflicts if LWIP_AUTOIP_CREATE_SEED_ADDR is overridden. 2008-10-02 Jonathan Larmour and Rishi Khan * sockets.c (lwip_accept): Return EWOULDBLOCK if would block on non-blocking socket. 2008-06-30 Simon Goldschmidt * mem.c, opt.h, stats.h: fixed bug #21433: Calling mem_free/pbuf_free from interrupt context isn't safe: LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT allows mem_free to run between mem_malloc iterations. Added illegal counter for mem stats. 2008-06-27 Simon Goldschmidt * stats.h/.c, some other files: patch #6483: stats module improvement: Added defines to display each module's statistic individually, added stats defines for MEM, MEMP and SYS modules, removed (unused) rexmit counter. 2008-06-17 Simon Goldschmidt * err.h: patch #6459: Made err_t overridable to use a more efficient type (define LWIP_ERR_T in cc.h) 2008-06-17 Simon Goldschmidt * slipif.c: patch #6480: Added a configuration option for slipif for symmetry to loopif 2008-06-17 Simon Goldschmidt (patch by Luca Ceresoli) * netif.c, loopif.c, ip.c, netif.h, loopif.h, opt.h: Checked in slightly modified version of patch # 6370: Moved loopif code to netif.c so that loopback traffic is supported on all netifs (all local IPs). Added option to limit loopback packets for each netifs. ++ Bugfixes: 2009-08-12 Kieran Mansley * tcp_in.c, tcp.c: Fix bug #27209: handle trimming of segments when out of window or out of order properly 2009-08-12 Kieran Mansley * tcp_in.c: Fix bug #27199: use snd_wl2 instead of snd_wl1 2009-07-28 Simon Goldschmidt * mem.h: Fixed bug #27105: "realloc() cannot replace mem_realloc()"s 2009-07-27 Kieran Mansley * api.h api_msg.h netdb.h sockets.h: add missing #include directives 2009-07-09 Kieran Mansley * api_msg.c, sockets.c, api.h: BUG23240 use signed counters for recv_avail and don't increment counters until message successfully sent to mbox 2009-06-25 Kieran Mansley * api_msg.c api.h: BUG26722: initialise netconn write variables in netconn_alloc 2009-06-25 Kieran Mansley * tcp.h: BUG26879: set ret value in TCP_EVENT macros when function is not set 2009-06-25 Kieran Mansley * tcp.c, tcp_in.c, tcp_out.c, tcp.h: BUG26301 and BUG26267: correct simultaneous close behaviour, and make snd_nxt have the same meaning as in the RFCs. 2009-05-12 Simon Goldschmidt * etharp.h, etharp.c, netif.c: fixed bug #26507: "Gratuitous ARP depends on arp_table / uses etharp_query" by adding etharp_gratuitous() 2009-05-12 Simon Goldschmidt * ip.h, ip.c, igmp.c: bug #26487: Added ip_output_if_opt that can add IP options to the IP header (used by igmp_ip_output_if) 2009-05-06 Simon Goldschmidt * inet_chksum.c: On little endian architectures, use LWIP_PLATFORM_HTONS (if defined) for SWAP_BYTES_IN_WORD to speed up checksumming. 2009-05-05 Simon Goldschmidt * sockets.c: bug #26405: Prematurely released semaphore causes lwip_select() to crash 2009-05-04 Simon Goldschmidt * init.c: snmp was not initialized in lwip_init() 2009-05-04 Frédéric Bernon * dhcp.c, netbios.c: Changes if IP_SOF_BROADCAST is enabled. 2009-05-03 Simon Goldschmidt * tcp.h: bug #26349: Nagle algorithm doesn't send although segment is full (and unsent->next == NULL) 2009-05-02 Simon Goldschmidt * tcpip.h, tcpip.c: fixed tcpip_untimeout (does not need the time, broken after 1.3.0 in CVS only) - fixes compilation of ppp_oe.c 2009-05-02 Simon Goldschmidt * msg_in.c: fixed bug #25636: SNMPSET value is ignored for integer fields 2009-05-01 Simon Goldschmidt * pap.c: bug #21680: PPP upap_rauthnak() drops legal NAK packets 2009-05-01 Simon Goldschmidt * ppp.c: bug #24228: Memory corruption with PPP and DHCP 2009-04-29 Frédéric Bernon * raw.c, udp.c, init.c, opt.h, ip.h, sockets.h: bug #26309: Implement the SO(F)_BROADCAST filter for all API layers. Avoid the unindented reception of broadcast packets even when this option wasn't set. Port maintainers which want to enable this filter have to set IP_SOF_BROADCAST=1 in opt.h. If you want this option also filter broadcast on recv operations, you also have to set IP_SOF_BROADCAST_RECV=1 in opt.h. 2009-04-28 Simon Goldschmidt, Jakob Stoklund Olesen * dhcp.c: patch #6721, bugs #25575, #25576: Some small fixes to DHCP and DHCP/AUTOIP cooperation 2009-04-25 Simon Goldschmidt, Oleg Tyshev * tcp_out.c: bug #24212: Deadlocked tcp_retransmit due to exceeded pcb->cwnd Fixed by sorting the unsent and unacked queues (segments are inserted at the right place in tcp_output and tcp_rexmit). 2009-04-25 Simon Goldschmidt * memp.c, mem.c, memp.h, mem_std.h: bug #26213 "Problem with memory allocation when debugging": memp_sizes contained the wrong sizes (including sanity regions); memp pools for MEM_USE_POOLS were too small 2009-04-24 Simon Goldschmidt, Frédéric Bernon * inet.c: patch #6765: Fix a small problem with the last changes (incorrect behavior, with with ip address string not ended by a '\0', a space or a end of line) 2009-04-19 Simon Goldschmidt * rawapi.txt: Fixed bug #26069: Corrected documentation: if tcp_connect fails, pcb->err is called, not pcb->connected (with an error code). 2009-04-19 Simon Goldschmidt * tcp_out.c: Fixed bug #26236: "TCP options (timestamp) don't work with no-copy-tcpwrite": deallocate option data, only concat segments with same flags 2009-04-19 Simon Goldschmidt * tcp_out.c: Fixed bug #25094: "Zero-length pbuf" (options are now allocated in the header pbuf, not the data pbuf) 2009-04-18 Simon Goldschmidt * api_msg.c: fixed bug #25695: Segmentation fault in do_writemore() 2009-04-15 Simon Goldschmidt * sockets.c: tried to fix bug #23559: lwip_recvfrom problem with tcp 2009-04-15 Simon Goldschmidt * dhcp.c: task #9192: mem_free of dhcp->options_in and dhcp->msg_in 2009-04-15 Simon Goldschmidt * ip.c, ip6.c, tcp_out.c, ip.h: patch #6808: Add a utility function ip_hinted_output() (for smaller code mainly) 2009-04-15 Simon Goldschmidt * inet.c: patch #6765: Supporting new line characters in inet_aton() 2009-04-15 Simon Goldschmidt * dhcp.c: patch #6764: DHCP rebind and renew did not send hostnam option; Converted constant OPTION_MAX_MSG_SIZE to netif->mtu, check if netif->mtu is big enough in dhcp_start 2009-04-15 Simon Goldschmidt * netbuf.c: bug #26027: netbuf_chain resulted in pbuf memory leak 2009-04-15 Simon Goldschmidt * sockets.c, ppp.c: bug #25763: corrected 4 occurrences of SMEMCPY to MEMCPY 2009-04-15 Simon Goldschmidt * sockets.c: bug #26121: set_errno can be overridden 2009-04-09 Kieran Mansley (patch from Luca Ceresoli ) * init.c, opt.h: Patch#6774 TCP_QUEUE_OOSEQ breaks compilation when LWIP_TCP==0 2009-04-09 Kieran Mansley (patch from Roy Lee ) * tcp.h: Patch#6802 Add do-while-clauses to those function like macros in tcp.h 2009-03-31 Kieran Mansley * tcp.c, tcp_in.c, tcp_out.c, tcp.h, opt.h: Rework the way window updates are calculated and sent (BUG20515) * tcp_in.c: cope with SYN packets received during established states, and retransmission of initial SYN. * tcp_out.c: set push bit correctly when tcp segments are merged 2009-03-27 Kieran Mansley * tcp_out.c set window correctly on probes (correcting change made yesterday) 2009-03-26 Kieran Mansley * tcp.c, tcp_in.c, tcp.h: add tcp_abandon() to cope with dropping connections where no reset required (bug #25622) * tcp_out.c: set TCP_ACK flag on keepalive and zero window probes (bug #20779) 2009-02-18 Simon Goldschmidt (Jonathan Larmour and Bill Auerbach) * ip_frag.c: patch #6528: the buffer used for IP_FRAG_USES_STATIC_BUF could be too small depending on MEM_ALIGNMENT 2009-02-16 Simon Goldschmidt * sockets.h/.c, api_*.h/.c: fixed arguments of socket functions to match the standard; converted size argument of netconn_write to 'size_t' 2009-02-16 Simon Goldschmidt * tcp.h, tcp.c: fixed bug #24440: TCP connection close problem on 64-bit host by moving accept callback function pointer to TCP_PCB_COMMON 2009-02-12 Simon Goldschmidt * dhcp.c: fixed bug #25345 (DHCPDECLINE is sent with "Maximum message size" option) 2009-02-11 Simon Goldschmidt * dhcp.c: fixed bug #24480 (releasing old udp_pdb and pbuf in dhcp_start) 2009-02-11 Simon Goldschmidt * opt.h, api_msg.c: added configurable default valud for netconn->recv_bufsize: RECV_BUFSIZE_DEFAULT (fixes bug #23726: pbuf pool exhaustion on slow recv()) 2009-02-10 Simon Goldschmidt * tcp.c: fixed bug #25467: Listen backlog is not reset on timeout in SYN_RCVD: Accepts_pending is decrease on a corresponding listen pcb when a connection in state SYN_RCVD is close. 2009-01-28 Jonathan Larmour * pbuf.c: reclaim pbufs from TCP out-of-sequence segments if we run out of pool pbufs. 2008-12-19 Simon Goldschmidt * many files: patch #6699: fixed some warnings on platform where sizeof(int) == 2 2008-12-10 Tamas Somogyi, Frédéric Bernon * sockets.c: fixed bug #25051: lwip_recvfrom problem with udp: fromaddr and port uses deleted netbuf. 2008-10-18 Simon Goldschmidt * tcp_in.c: fixed bug ##24596: Vulnerability on faulty TCP options length in tcp_parseopt 2008-10-15 Simon Goldschmidt * ip_frag.c: fixed bug #24517: IP reassembly crashes on unaligned IP headers by packing the struct ip_reass_helper. 2008-10-03 David Woodhouse, Jonathan Larmour * etharp.c (etharp_arp_input): Fix type aliasing problem copying ip address. 2008-10-02 Jonathan Larmour * dns.c: Hard-code structure sizes, to avoid issues on some compilers where padding is included. 2008-09-30 Jonathan Larmour * sockets.c (lwip_accept): check addr isn't NULL. If it's valid, do an assertion check that addrlen isn't NULL. 2008-09-30 Jonathan Larmour * tcp.c: Fix bug #24227, wrong error message in tcp_bind. 2008-08-26 Simon Goldschmidt * inet.h, ip_addr.h: fixed bug #24132: Cross-dependency between ip_addr.h and inet.h -> moved declaration of struct in_addr from ip_addr.h to inet.h 2008-08-14 Simon Goldschmidt * api_msg.c: fixed bug #23847: do_close_internal references freed memory (when tcp_close returns != ERR_OK) 2008-07-08 Frédéric Bernon * stats.h: Fix some build bugs introduced with patch #6483 (missing some parameters in macros, mainly if MEM_STATS=0 and MEMP_STATS=0). 2008-06-24 Jonathan Larmour * tcp_in.c: Fix for bug #23693 as suggested by Art R. Ensure cseg is unused if tcp_seg_copy fails. 2008-06-17 Simon Goldschmidt * inet_chksum.c: Checked in some ideas of patch #6460 (loop optimizations) and created defines for swapping bytes and folding u32 to u16. 2008-05-30 Kieran Mansley * tcp_in.c Remove redundant "if" statement, and use real rcv_wnd rather than rcv_ann_wnd when deciding if packets are in-window. Contributed by 2008-05-30 Kieran Mansley * mem.h: Fix BUG#23254. Change macro definition of mem_* to allow passing as function pointers when MEM_LIBC_MALLOC is defined. 2008-05-09 Jonathan Larmour * err.h, err.c, sockets.c: Fix bug #23119: Reorder timeout error code to stop it being treated as a fatal error. 2008-04-15 Simon Goldschmidt * dhcp.c: fixed bug #22804: dhcp_stop doesn't clear NETIF_FLAG_DHCP (flag now cleared) 2008-03-27 Simon Goldschmidt * mem.c, tcpip.c, tcpip.h, opt.h: fixed bug #21433 (Calling mem_free/pbuf_free from interrupt context isn't safe): set LWIP_USE_HEAP_FROM_INTERRUPT to 1 in lwipopts.h or use pbuf_free_callback(p)/mem_free_callback(m) to free pbufs or heap memory from interrupt context 2008-03-26 Simon Goldschmidt * tcp_in.c, tcp.c: fixed bug #22249: division by zero could occur if a remote host sent a zero mss as TCP option. (STABLE-1.3.0) ++ New features: 2008-03-10 Jonathan Larmour * inet_chksum.c: Allow choice of one of the sample algorithms to be made from lwipopts.h. Fix comment on how to override LWIP_CHKSUM. 2008-01-22 Frédéric Bernon * tcp.c, tcp_in.c, tcp.h, opt.h: Rename LWIP_CALCULATE_EFF_SEND_MSS in TCP_CALCULATE_EFF_SEND_MSS to have coherent TCP options names. 2008-01-14 Frédéric Bernon * rawapi.txt, api_msg.c, tcp.c, tcp_in.c, tcp.h: changes for task #7675 "Enable to refuse data on a TCP_EVENT_RECV call". Important, behavior changes for the tcp_recv callback (see rawapi.txt). 2008-01-14 Frédéric Bernon, Marc Chaland * ip.c: Integrate patch #6369" ip_input : checking before realloc". 2008-01-12 Frédéric Bernon * tcpip.h, tcpip.c, api.h, api_lib.c, api_msg.c, sockets.c: replace the field netconn::sem per netconn::op_completed like suggested for the task #7490 "Add return value to sys_mbox_post". 2008-01-12 Frédéric Bernon * api_msg.c, opt.h: replace DEFAULT_RECVMBOX_SIZE per DEFAULT_TCP_RECVMBOX_SIZE, DEFAULT_UDP_RECVMBOX_SIZE and DEFAULT_RAW_RECVMBOX_SIZE (to optimize queues sizes), like suggested for the task #7490 "Add return value to sys_mbox_post". 2008-01-10 Frédéric Bernon * tcpip.h, tcpip.c: add tcpip_callback_with_block function for the task #7490 "Add return value to sys_mbox_post". tcpip_callback is always defined as "blocking" ("block" parameter = 1). 2008-01-10 Frédéric Bernon * tcpip.h, tcpip.c, api.h, api_lib.c, api_msg.c, sockets.c: replace the field netconn::mbox (sys_mbox_t) per netconn::sem (sys_sem_t) for the task #7490 "Add return value to sys_mbox_post". 2008-01-05 Frédéric Bernon * sys_arch.txt, api.h, api_lib.c, api_msg.h, api_msg.c, tcpip.c, sys.h, opt.h: Introduce changes for task #7490 "Add return value to sys_mbox_post" with some modifications in the sys_mbox api: sys_mbox_new take a "size" parameters which indicate the number of pointers query by the mailbox. There is three defines in opt.h to indicate sizes for tcpip::mbox, netconn::recvmbox, and for the netconn::acceptmbox. Port maintainers, you can decide to just add this new parameter in your implementation, but to ignore it to keep the previous behavior. The new sys_mbox_trypost function return a value to know if the mailbox is full or if the message is posted. Take a look to sys_arch.txt for more details. This new function is used in tcpip_input (so, can be called in an interrupt context since the function is not blocking), and in recv_udp and recv_raw. 2008-01-04 Frédéric Bernon, Simon Goldschmidt, Jonathan Larmour * rawapi.txt, api.h, api_lib.c, api_msg.h, api_msg.c, sockets.c, tcp.h, tcp.c, tcp_in.c, init.c, opt.h: rename backlog options with TCP_ prefix, limit the "backlog" parameter in an u8_t, 0 is interpreted as "smallest queue", add documentation in the rawapi.txt file. 2007-12-31 Kieran Mansley (based on patch from Per-Henrik Lundbolm) * tcp.c, tcp_in.c, tcp_out.c, tcp.h: Add TCP persist timer 2007-12-31 Frédéric Bernon, Luca Ceresoli * autoip.c, etharp.c: ip_addr.h: Integrate patch #6348: "Broadcast ARP packets in autoip". The change in etharp_raw could be removed, since all calls to etharp_raw use ethbroadcast for the "ethdst_addr" parameter. But it could be wrong in the future. 2007-12-30 Frédéric Bernon, Tom Evans * ip.c: Fix bug #21846 "LwIP doesn't appear to perform any IP Source Address Filtering" reported by Tom Evans. 2007-12-21 Frédéric Bernon, Simon Goldschmidt, Jonathan Larmour * tcp.h, opt.h, api.h, api_msg.h, tcp.c, tcp_in.c, api_lib.c, api_msg.c, sockets.c, init.c: task #7252: Implement TCP listen backlog: Warning: raw API applications have to call 'tcp_accepted(pcb)' in their accept callback to keep accepting new connections. 2007-12-13 Frédéric Bernon * api_msg.c, err.h, err.c, sockets.c, dns.c, dns.h: replace "enum dns_result" by err_t type. Add a new err_t code "ERR_INPROGRESS". 2007-12-12 Frédéric Bernon * dns.h, dns.c, opt.h: move DNS options to the "right" place. Most visibles are the one which have ram usage. 2007-12-05 Frédéric Bernon * netdb.c: add a LWIP_DNS_API_HOSTENT_STORAGE option to decide to use a static set of variables (=0) or a local one (=1). In this last case, your port should provide a function "struct hostent* sys_thread_hostent( struct hostent* h)" which have to do a copy of "h" and return a pointer ont the "per-thread" copy. 2007-12-03 Simon Goldschmidt * ip.c: ip_input: check if a packet is for inp first before checking all other netifs on netif_list (speeds up packet receiving in most cases) 2007-11-30 Simon Goldschmidt * udp.c, raw.c: task #7497: Sort lists (pcb, netif, ...) for faster access UDP: move a (connected) pcb selected for input to the front of the list of pcbs so that it is found faster next time. Same for RAW pcbs that have eaten a packet. 2007-11-28 Simon Goldschmidt * etharp.c, stats.c, stats.h, opt.h: Introduced ETHARP_STATS 2007-11-25 Simon Goldschmidt * dhcp.c: dhcp_unfold_reply() uses pbuf_copy_partial instead of its own copy algorithm. 2007-11-24 Simon Goldschmidt * netdb.h, netdb.c, sockets.h/.c: Moved lwip_gethostbyname from sockets.c to the new file netdb.c; included lwip_getaddrinfo. 2007-11-21 Simon Goldschmidt * tcp.h, opt.h, tcp.c, tcp_in.c: implemented calculating the effective send-mss based on the MTU of the netif used to send. Enabled by default. Disable by setting LWIP_CALCULATE_EFF_SEND_MSS to 0. This fixes bug #21492. 2007-11-19 Frédéric Bernon * api_msg.c, dns.h, dns.c: Implement DNS_DOES_NAME_CHECK option (check if name received match the name query), implement DNS_USES_STATIC_BUF (the place where copy dns payload to parse the response), return an error if there is no place for a new query, and fix some minor problems. 2007-11-16 Simon Goldschmidt * new files: ipv4/inet.c, ipv4/inet_chksum.c, ipv6/inet6.c removed files: core/inet.c, core/inet6.c Moved inet files into ipv4/ipv6 directory; splitted inet.c/inet.h into inet and chksum part; changed includes in all lwIP files as appropriate 2007-11-16 Simon Goldschmidt * api.h, api_msg.h, api_lib.c, api_msg.c, socket.h, socket.c: Added sequential dns resolver function for netconn api (netconn_gethostbyname) and socket api (gethostbyname/gethostbyname_r). 2007-11-15 Jim Pettinato, Frédéric Bernon * opt.h, init.c, tcpip.c, dhcp.c, dns.h, dns.c: add DNS client for simple name requests with RAW api interface. Initialization is done in lwip_init() with build time options. DNS timer is added in tcpip_thread context. DHCP can set DNS server ip addresses when options are received. You need to set LWIP_DNS=1 in your lwipopts.h file (LWIP_DNS=0 in opt.h). DNS_DEBUG can be set to get some traces with LWIP_DEBUGF. Sanity check have been added. There is a "todo" list with points to improve. 2007-11-06 Simon Goldschmidt * opt.h, mib2.c: Patch #6215: added ifAdminStatus write support (if explicitly enabled by defining SNMP_SAFE_REQUESTS to 0); added code to check link status for ifOperStatus if LWIP_NETIF_LINK_CALLBACK is defined. 2007-11-06 Simon Goldschmidt * api.h, api_msg.h and dependent files: Task #7410: Removed the need to include core header files in api.h (ip/tcp/udp/raw.h) to hide the internal implementation from netconn api applications. 2007-11-03 Frédéric Bernon * api.h, api_lib.c, api_msg.c, sockets.c, opt.h: add SO_RCVBUF option for UDP & RAW netconn. You need to set LWIP_SO_RCVBUF=1 in your lwipopts.h (it's disabled by default). Netconn API users can use the netconn_recv_bufsize macro to access it. This is a first release which have to be improve for TCP. Note it used the netconn::recv_avail which need to be more "thread-safe" (note there is already the problem for FIONREAD with lwip_ioctl/ioctlsocket). 2007-11-01 Frédéric Bernon, Marc Chaland * sockets.h, sockets.c, api.h, api_lib.c, api_msg.h, api_msg.c, tcp.h, tcp_out.c: Integrate "patch #6250 : MSG_MORE flag for send". MSG_MORE is used at socket api layer, NETCONN_MORE at netconn api layer, and TCP_WRITE_FLAG_MORE at raw api layer. This option enable to delayed TCP PUSH flag on multiple "write" calls. Note that previous "copy" parameter for "write" APIs is now called "apiflags". 2007-10-24 Frédéric Bernon * api.h, api_lib.c, api_msg.c: Add macro API_EVENT in the same spirit than TCP_EVENT_xxx macros to get a code more readable. It could also help to remove some code (like we have talk in "patch #5919 : Create compile switch to remove select code"), but it could be done later. 2007-10-08 Simon Goldschmidt * many files: Changed initialization: many init functions are not needed any more since we now rely on the compiler initializing global and static variables to zero! 2007-10-06 Simon Goldschmidt * ip_frag.c, memp.c, mib2.c, ip_frag.h, memp_std.h, opt.h: Changed IP_REASSEMBLY to enqueue the received pbufs so that multiple packets can be reassembled simultaneously and no static reassembly buffer is needed. 2007-10-05 Simon Goldschmidt * tcpip.c, etharp.h, etharp.c: moved ethernet_input from tcpip.c to etharp.c so all netifs (or ports) can use it. 2007-10-05 Frédéric Bernon * netifapi.h, netifapi.c: add function netifapi_netif_set_default. Change the common function to reduce a little bit the footprint (for all functions using only the "netif" parameter). 2007-10-03 Frédéric Bernon * netifapi.h, netifapi.c: add functions netifapi_netif_set_up, netifapi_netif_set_down, netifapi_autoip_start and netifapi_autoip_stop. Use a common function to reduce a little bit the footprint (for all functions using only the "netif" parameter). 2007-09-15 Frédéric Bernon * udp.h, udp.c, sockets.c: Changes for "#20503 IGMP Improvement". Add IP_MULTICAST_IF option in socket API, and a new field "multicast_ip" in "struct udp_pcb" (for netconn and raw API users), only if LWIP_IGMP=1. Add getsockopt processing for IP_MULTICAST_TTL and IP_MULTICAST_IF. 2007-09-10 Frédéric Bernon * snmp.h, mib2.c: enable to remove SNMP timer (which consumne several cycles even when it's not necessary). snmp_agent.txt tell to call snmp_inc_sysuptime() each 10ms (but, it's intrusive if you use sys_timeout feature). Now, you can decide to call snmp_add_sysuptime(100) each 1000ms (which is bigger "step", but call to a lower frequency). Or, you can decide to not call snmp_inc_sysuptime() or snmp_add_sysuptime(), and to define the SNMP_GET_SYSUPTIME(sysuptime) macro. This one is undefined by default in mib2.c. SNMP_GET_SYSUPTIME is called inside snmp_get_sysuptime(u32_t *value), and enable to change "sysuptime" value only when it's queried (any direct call to "sysuptime" is changed by a call to snmp_get_sysuptime). 2007-09-09 Frédéric Bernon, Bill Florac * igmp.h, igmp.c, netif.h, netif.c, ip.c: To enable to have interfaces with IGMP, and others without it, there is a new NETIF_FLAG_IGMP flag to set in netif->flags if you want IGMP on an interface. igmp_stop() is now called inside netif_remove(). igmp_report_groups() is now called inside netif_set_link_up() (need to have LWIP_NETIF_LINK_CALLBACK=1) to resend reports once the link is up (avoid to wait the next query message to receive the matching multicast streams). 2007-09-08 Frédéric Bernon * sockets.c, ip.h, api.h, tcp.h: declare a "struct ip_pcb" which only contains IP_PCB. Add in the netconn's "pcb" union a "struct ip_pcb *ip;" (no size change). Use this new field to access to common pcb fields (ttl, tos, so_options, etc...). Enable to access to these fields with LWIP_TCP=0. 2007-09-05 Frédéric Bernon * udp.c, ipv4/icmp.c, ipv4/ip.c, ipv6/icmp.c, ipv6/ip6.c, ipv4/icmp.h, ipv6/icmp.h, opt.h: Integrate "task #7272 : LWIP_ICMP option". The new option LWIP_ICMP enable/disable ICMP module inside the IP stack (enable per default). Be careful, disabling ICMP make your product non-compliant to RFC1122, but help to reduce footprint, and to reduce "visibility" on the Internet. 2007-09-05 Frédéric Bernon, Bill Florac * opt.h, sys.h, tcpip.c, slipif.c, ppp.c, sys_arch.txt: Change parameters list for sys_thread_new (see "task #7252 : Create sys_thread_new_ex()"). Two new parameters have to be provided: a task name, and a task stack size. For this one, since it's platform dependant, you could define the best one for you in your lwipopts.h. For port maintainers, you can just add these new parameters in your sys_arch.c file, and but it's not mandatory, use them in your OS specific functions. 2007-09-05 Frédéric Bernon * inet.c, autoip.c, msg_in.c, msg_out.c, init.c: Move some build time checkings inside init.c for task #7142 "Sanity check user-configurable values". 2007-09-04 Frédéric Bernon, Bill Florac * igmp.h, igmp.c, memp_std.h, memp.c, init.c, opt.h: Replace mem_malloc call by memp_malloc, and use a new MEMP_NUM_IGMP_GROUP option (see opt.h to define the value). It will avoid potential fragmentation problems, use a counter to know how many times a group is used on an netif, and free it when all applications leave it. MEMP_NUM_IGMP_GROUP got 8 as default value (and init.c got a sanity check if LWIP_IGMP!=0). 2007-09-03 Frédéric Bernon * igmp.h, igmp.c, sockets.c, api_msg.c: Changes for "#20503 IGMP Improvement". Initialize igmp_mac_filter to NULL in netif_add (this field should be set in the netif's "init" function). Use the "imr_interface" field (for socket layer) and/or the "interface" field (for netconn layer), for join/leave operations. The igmp_join/leavegroup first parameter change from a netif to an ipaddr. This field could be a netif's ipaddr, or "any" (same meaning than ip_addr_isany). 2007-08-30 Frédéric Bernon * Add netbuf.h, netbuf.c, Change api.h, api_lib.c: #7249 "Split netbuf functions from api/api_lib". Now netbuf API is independant of netconn, and can be used with other API (application based on raw API, or future "socket2" API). Ports maintainers just have to add src/api/netbuf.c in their makefile/projects. 2007-08-30 Frédéric Bernon, Jonathan Larmour * init.c: Add first version of lwip_sanity_check for task #7142 "Sanity check user-configurable values". 2007-08-29 Frédéric Bernon * igmp.h, igmp.c, tcpip.c, init.c, netif.c: change igmp_init and add igmp_start. igmp_start is call inside netif_add. Now, igmp initialization is in the same spirit than the others modules. Modify some IGMP debug traces. 2007-08-29 Frédéric Bernon * Add init.h, init.c, Change opt.h, tcpip.c: Task #7213 "Add a lwip_init function" Add lwip_init function to regroup all modules initializations, and to provide a place to add code for task #7142 "Sanity check user-configurable values". Ports maintainers should remove direct initializations calls from their code, and add init.c in their makefiles. Note that lwip_init() function is called inside tcpip_init, but can also be used by raw api users since all calls are disabled when matching options are disabled. Also note that their is new options in opt.h, you should configure in your lwipopts.h (they are enabled per default). 2007-08-26 Marc Boucher * api_msg.c: do_close_internal(): Reset the callbacks and arg (conn) to NULL since they can under certain circumstances be called with an invalid conn pointer after the connection has been closed (and conn has been freed). 2007-08-25 Frédéric Bernon (Artem Migaev's Patch) * netif.h, netif.c: Integrate "patch #6163 : Function to check if link layer is up". Add a netif_is_link_up() function if LWIP_NETIF_LINK_CALLBACK option is set. 2007-08-22 Frédéric Bernon * netif.h, netif.c, opt.h: Rename LWIP_NETIF_CALLBACK in LWIP_NETIF_STATUS_CALLBACK to be coherent with new LWIP_NETIF_LINK_CALLBACK option before next release. 2007-08-22 Frédéric Bernon * tcpip.h, tcpip.c, ethernetif.c, opt.h: remove options ETHARP_TCPIP_INPUT & ETHARP_TCPIP_ETHINPUT, now, only "ethinput" code is supported, even if the name is tcpip_input (we keep the name of 1.2.0 function). 2007-08-17 Jared Grubb * memp_std.h, memp.h, memp.c, mem.c, stats.c: (Task #7136) Centralize mempool settings into new memp_std.h and optional user file lwippools.h. This adds more dynamic mempools, and allows the user to create an arbitrary number of mempools for mem_malloc. 2007-08-16 Marc Boucher * api_msg.c: Initialize newconn->state to NETCONN_NONE in accept_function; otherwise it was left to NETCONN_CLOSE and sent_tcp() could prematurely close the connection. 2007-08-16 Marc Boucher * sockets.c: lwip_accept(): check netconn_peer() error return. 2007-08-16 Marc Boucher * mem.c, mem.h: Added mem_calloc(). 2007-08-16 Marc Boucher * tcpip.c, tcpip.h memp.c, memp.h: Added distinct memp (MEMP_TCPIP_MSG_INPKT) for input packets to prevent floods from consuming all of MEMP_TCPIP_MSG and starving other message types. Renamed MEMP_TCPIP_MSG to MEMP_TCPIP_MSG_API 2007-08-16 Marc Boucher * pbuf.c, pbuf.h, etharp.c, tcp_in.c, sockets.c: Split pbuf flags in pbuf type and flgs (later renamed to flags). Use enum pbuf_flag as pbuf_type. Renumber PBUF_FLAG_*. Improved lwip_recvfrom(). TCP push now propagated. 2007-08-16 Marc Boucher * ethernetif.c, contrib/ports/various: ethbroadcast now a shared global provided by etharp. 2007-08-16 Marc Boucher * ppp_oe.c ppp_oe.h, auth.c chap.c fsm.c lcp.c ppp.c ppp.h, etharp.c ethernetif.c, etharp.h, opt.h tcpip.h, tcpip.c: Added PPPoE support and various PPP improvements. 2007-07-25 Simon Goldschmidt * api_lib.c, ip_frag.c, pbuf.c, api.h, pbuf.h: Introduced pbuf_copy_partial, making netbuf_copy_partial use this function. 2007-07-25 Simon Goldschmidt * tcp_in.c: Fix bug #20506: Slow start / initial congestion window starts with 2 * mss (instead of 1 * mss previously) to comply with some newer RFCs and other stacks. 2007-07-13 Jared Grubb (integrated by Frédéric Bernon) * opt.h, netif.h, netif.c, ethernetif.c: Add new configuration option to add a link callback in the netif struct, and functions to handle it. Be carefull for port maintainers to add the NETIF_FLAG_LINK_UP flag (like in ethernetif.c) if you want to be sure to be compatible with future changes... 2007-06-30 Frédéric Bernon * sockets.h, sockets.c: Implement MSG_PEEK flag for recv/recvfrom functions. 2007-06-21 Simon Goldschmidt * etharp.h, etharp.c: Combined etharp_request with etharp_raw for both LWIP_AUTOIP =0 and =1 to remove redundant code. 2007-06-21 Simon Goldschmidt * mem.c, memp.c, mem.h, memp.h, opt.h: task #6863: Introduced the option MEM_USE_POOLS to use 4 pools with different sized elements instead of a heap. This both prevents memory fragmentation and gives a higher speed at the cost of more memory consumption. Turned off by default. 2007-06-21 Simon Goldschmidt * api_lib.c, api_msg.c, api.h, api_msg.h: Converted the length argument of netconn_write (and therefore also api_msg_msg.msg.w.len) from u16_t into int to be able to send a bigger buffer than 64K with one time (mainly used from lwip_send). 2007-06-21 Simon Goldschmidt * tcp.h, api_msg.c: Moved the nagle algorithm from netconn_write/do_write into a define (tcp_output_nagle) in tcp.h to provide it to raw api users, too. 2007-06-21 Simon Goldschmidt * api.h, api_lib.c, api_msg.c: Fixed bug #20021: Moved sendbuf-processing in netconn_write from api_lib.c to api_msg.c to also prevent multiple context- changes on low memory or empty send-buffer. 2007-06-18 Simon Goldschmidt * etharp.c, etharp.h: Changed etharp to use a defined hardware address length of 6 to avoid loading netif->hwaddr_len every time (since this file is only used for ethernet and struct eth_addr already had a defined length of 6). 2007-06-17 Simon Goldschmidt * sockets.c, sockets.h: Implemented socket options SO_NO_CHECK for UDP sockets to disable UDP checksum generation on transmit. 2007-06-13 Frédéric Bernon, Simon Goldschmidt * debug.h, api_msg.c: change LWIP_ERROR to use it to check errors like invalid pointers or parameters, and let the possibility to redefined it in cc.h. Use this macro to check "conn" parameter in api_msg.c functions. 2007-06-11 Simon Goldschmidt * sockets.c, sockets.h: Added UDP lite support for sockets 2007-06-10 Simon Goldschmidt * udp.h, opt.h, api_msg.c, ip.c, udp.c: Included switch LWIP_UDPLITE (enabled by default) to switch off UDP-Lite support if not needed (reduces udp.c code size) 2007-06-09 Dominik Spies (integrated by Frédéric Bernon) * autoip.h, autoip.c, dhcp.h, dhcp.c, netif.h, netif.c, etharp.h, etharp.c, opt.h: AutoIP implementation available for IPv4, with new options LWIP_AUTOIP and LWIP_DHCP_AUTOIP_COOP if you want to cooperate with DHCP. Some tips to adapt (see TODO mark in the source code). 2007-06-09 Simon Goldschmidt * etharp.h, etharp.c, ethernetif.c: Modified order of parameters for etharp_output() to match netif->output so etharp_output() can be used directly as netif->output to save one function call. 2007-06-08 Simon Goldschmidt * netif.h, ethernetif.c, slipif.c, loopif.c: Added define NETIF_INIT_SNMP(netif, type, speed) to initialize per-netif snmp variables, added initialization of those to ethernetif, slipif and loopif. 2007-05-18 Simon Goldschmidt * opt.h, ip_frag.c, ip_frag.h, ip.c: Added option IP_FRAG_USES_STATIC_BUF (defaulting to off for now) that can be set to 0 to send fragmented packets by passing PBUF_REFs down the stack. 2007-05-23 Frédéric Bernon * api_lib.c: Implement SO_RCVTIMEO for accept and recv on TCP connections, such present in patch #5959. 2007-05-23 Frédéric Bernon * api.h, api_lib.c, api_msg.c, sockets.c: group the different NETCONN_UDPxxx code in only one part... 2007-05-18 Simon Goldschmidt * opt.h, memp.h, memp.c: Added option MEMP_OVERFLOW_CHECK to check for memp elements to overflow. This is achieved by adding some bytes before and after each pool element (increasing their size, of course), filling them with a prominent value and checking them on freeing the element. Set it to 2 to also check every element in every pool each time memp_malloc() or memp_free() is called (slower but more helpful). 2007-05-10 Simon Goldschmidt * opt.h, memp.h, memp.c, pbuf.c (see task #6831): use a new memp pool for PBUF_POOL pbufs instead of the old pool implementation in pbuf.c to reduce code size. 2007-05-11 Frédéric Bernon * sockets.c, api_lib.c, api_msg.h, api_msg.c, netifapi.h, netifapi.c, tcpip.c: Include a function pointer instead of a table index in the message to reduce footprint. Disable some part of lwip_send and lwip_sendto if some options are not set (LWIP_TCP, LWIP_UDP, LWIP_RAW). 2007-05-10 Simon Goldschmidt * *.h (except netif/ppp/*.h): Included patch #5448: include '#ifdef __cplusplus \ extern "C" {' in all header files. Now you can write your application using the lwIP stack in C++ and simply #include the core files. Note I have left out the netif/ppp/*h header files for now, since I don't know which files are included by applications and which are for internal use only. 2007-05-09 Simon Goldschmidt * opt.h, *.c/*.h: Included patch #5920: Create define to override C-library memcpy. 2 Defines are created: MEMCPY() for normal memcpy, SMEMCPY() for situations where some compilers might inline the copy and save a function call. Also replaced all calls to memcpy() with calls to (S)MEMCPY(). 2007-05-08 Simon Goldschmidt * mem.h: If MEM_LIBC_MALLOC==1, allow the defines (e.g. mem_malloc() -> malloc()) to be overriden in case the C-library malloc implementation is not protected against concurrent access. 2007-05-04 Simon Goldschmidt (Atte Kojo) * etharp.c: Introduced fast one-entry-cache to speed up ARP lookup when sending multiple packets to the same host. 2007-05-04 Frédéric Bernon, Jonathan Larmour * sockets.c, api.h, api_lib.c, api_msg.h, api_msg.c: Fix bug #19162 "lwip_sento: a possible to corrupt remote addr/port connection state". Reduce problems "not enought memory" with netbuf (if we receive lot of datagrams). Improve lwip_sendto (only one exchange between sockets api and api_msg which run in tcpip_thread context). Add netconn_sento function. Warning, if you directly access to "fromaddr" & "fromport" field from netbuf struct, these fields are now renamed "addr" & "port". 2007-04-11 Jonathan Larmour * sys.h, api_lib.c: Provide new sys_mbox_tryfetch function. Require ports to provide new sys_arch_mbox_tryfetch function to get a message if one is there, otherwise return with SYS_MBOX_EMPTY. sys_arch_mbox_tryfetch can be implemented as a function-like macro by the port in sys_arch.h if desired. 2007-04-06 Frédéric Bernon, Simon Goldschmidt * opt.h, tcpip.h, tcpip.c, netifapi.h, netifapi.c: New configuration option LWIP_NETIF_API allow to use thread-safe functions to add/remove netif in list, and to start/stop dhcp clients, using new functions from netifapi.h. Disable as default (no port change to do). 2007-04-05 Frédéric Bernon * sockets.c: remplace ENOBUFS errors on alloc_socket by ENFILE to be more BSD compliant. 2007-04-04 Simon Goldschmidt * arch.h, api_msg.c, dhcp.c, msg_in.c, sockets.c: Introduced #define LWIP_UNUSED_ARG(x) use this for and architecture-independent form to tell the compiler you intentionally are not using this variable. Can be overriden in cc.h. 2007-03-28 Frédéric Bernon * opt.h, netif.h, dhcp.h, dhcp.c: New configuration option LWIP_NETIF_HOSTNAME allow to define a hostname in netif struct (this is just a pointer, so, you can use a hardcoded string, point on one of your's ethernetif field, or alloc a string you will free yourself). It will be used by DHCP to register a client hostname, but can also be use when you call snmp_set_sysname. 2007-03-28 Frédéric Bernon * netif.h, netif.c: A new NETIF_FLAG_ETHARP flag is defined in netif.h, to allow to initialize a network interface's flag with. It tell this interface is an ethernet device, and we can use ARP with it to do a "gratuitous ARP" (RFC 3220 "IP Mobility Support for IPv4" section 4.6) when interface is "up" with netif_set_up(). 2007-03-26 Frédéric Bernon, Jonathan Larmour * opt.h, tcpip.c: New configuration option LWIP_ARP allow to disable ARP init at build time if you only use PPP or SLIP. The default is enable. Note we don't have to call etharp_init in your port's initilization sequence if you use tcpip.c, because this call is done in tcpip_init function. 2007-03-22 Frédéric Bernon * stats.h, stats.c, msg_in.c: Stats counters can be change to u32_t if necessary with the new option LWIP_STATS_LARGE. If you need this option, define LWIP_STATS_LARGE to 1 in your lwipopts.h. More, unused counters are not defined in the stats structs, and not display by stats_display(). Note that some options (SYS_STATS and RAW_STATS) are defined but never used. Fix msg_in.c with the correct #if test for a stat display. 2007-03-21 Kieran Mansley * netif.c, netif.h: Apply patch#4197 with some changes (originator: rireland@hmgsl.com). Provides callback on netif up/down state change. 2007-03-11 Frédéric Bernon, Mace Gael, Steve Reynolds * sockets.h, sockets.c, api.h, api_lib.c, api_msg.h, api_msg.c, igmp.h, igmp.c, ip.c, netif.h, tcpip.c, opt.h: New configuration option LWIP_IGMP to enable IGMP processing. Based on only one filter per all network interfaces. Declare a new function in netif to enable to control the MAC filter (to reduce lwIP traffic processing). 2007-03-11 Frédéric Bernon * tcp.h, tcp.c, sockets.c, tcp_out.c, tcp_in.c, opt.h: Keepalive values can be configured at run time with LWIP_TCP_KEEPALIVE, but don't change this unless you know what you're doing (default are RFC1122 compliant). Note that TCP_KEEPIDLE and TCP_KEEPINTVL have to be set in seconds. 2007-03-08 Frédéric Bernon * tcp.h: Keepalive values can be configured at compile time, but don't change this unless you know what you're doing (default are RFC1122 compliant). 2007-03-08 Frédéric Bernon * sockets.c, api.h, api_lib.c, tcpip.c, sys.h, sys.c, err.c, opt.h: Implement LWIP_SO_RCVTIMEO configuration option to enable/disable SO_RCVTIMEO on UDP sockets/netconn. 2007-03-08 Simon Goldschmidt * snmp_msg.h, msg_in.c: SNMP UDP ports can be configured at compile time. 2007-03-06 Frédéric Bernon * api.h, api_lib.c, sockets.h, sockets.c, tcpip.c, sys.h, sys.c, err.h: Implement SO_RCVTIMEO on UDP sockets/netconn. 2007-02-28 Kieran Mansley (based on patch from Simon Goldschmidt) * api_lib.c, tcpip.c, memp.c, memp.h: make API msg structs allocated on the stack and remove the API msg type from memp 2007-02-26 Jonathan Larmour (based on patch from Simon Goldschmidt) * sockets.h, sockets.c: Move socket initialization to new lwip_socket_init() function. NOTE: this changes the API with ports. Ports will have to be updated to call lwip_socket_init() now. 2007-02-26 Jonathan Larmour (based on patch from Simon Goldschmidt) * api_lib.c: Use memcpy in netbuf_copy_partial. ++ Bug fixes: 2008-03-17 Frédéric Bernon, Ed Kerekes * igmp.h, igmp.c: Fix bug #22613 "IGMP iphdr problem" (could have some problems to fill the IP header on some targets, use now the ip.h macros to do it). 2008-03-13 Frédéric Bernon * sockets.c: Fix bug #22435 "lwip_recvfrom with TCP break;". Using (lwip_)recvfrom with valid "from" and "fromlen" parameters, on a TCP connection caused a crash. Note that using (lwip_)recvfrom like this is a bit slow and that using (lwip)getpeername is the good lwip way to do it (so, using recv is faster on tcp sockets). 2008-03-12 Frédéric Bernon, Jonathan Larmour * api_msg.c, contrib/apps/ping.c: Fix bug #22530 "api_msg.c's recv_raw() does not consume data", and the ping sample (with LWIP_SOCKET=1, the code did the wrong supposition that lwip_recvfrom returned the IP payload, without the IP header). 2008-03-04 Jonathan Larmour * mem.c, stats.c, mem.h: apply patch #6414 to avoid compiler errors and/or warnings on some systems where mem_size_t and size_t differ. * pbuf.c, ppp.c: Fix warnings on some systems with mem_malloc. 2008-03-04 Kieran Mansley (contributions by others) * Numerous small compiler error/warning fixes from contributions to mailing list after 1.3.0 release candidate made. 2008-01-25 Cui hengbin (integrated by Frédéric Bernon) * dns.c: Fix bug #22108 "DNS problem" caused by unaligned structures. 2008-01-15 Kieran Mansley * tcp_out.c: BUG20511. Modify persist timer to start when we are prevented from sending by a small send window, not just a zero send window. 2008-01-09 Jonathan Larmour * opt.h, ip.c: Rename IP_OPTIONS define to IP_OPTIONS_ALLOWED to avoid conflict with Linux system headers. 2008-01-06 Jonathan Larmour * dhcp.c: fix bug #19927: "DHCP NACK problem" by clearing any existing set IP address entirely on receiving a DHCPNAK, and restarting discovery. 2007-12-21 Simon Goldschmidt * sys.h, api_lib.c, api_msg.c, sockets.c: fix bug #21698: "netconn->recv_avail is not protected" by using new macros for interlocked access to modify/test netconn->recv_avail. 2007-12-20 Kieran Mansley (based on patch from Oleg Tyshev) * tcp_in.c: fix bug# 21535 (nrtx not reset correctly in SYN_SENT state) 2007-12-20 Kieran Mansley (based on patch from Per-Henrik Lundbolm) * tcp.c, tcp_in.c, tcp_out.c, tcp.h: fix bug #20199 (better handling of silly window avoidance and prevent lwIP from shrinking the window) 2007-12-04 Simon Goldschmidt * tcp.c, tcp_in.c: fix bug #21699 (segment leak in ooseq processing when last data packet was lost): add assert that all segment lists are empty in tcp_pcb_remove before setting pcb to CLOSED state; don't directly set CLOSED state from LAST_ACK in tcp_process 2007-12-02 Simon Goldschmidt * sockets.h: fix bug #21654: exclude definition of struct timeval from #ifndef FD_SET If including for system-struct timeval, LWIP_TIMEVAL_PRIVATE now has to be set to 0 in lwipopts.h 2007-12-02 Simon Goldschmidt * api_msg.c, api_lib.c: fix bug #21656 (recvmbox problem in netconn API): always allocate a recvmbox in netconn_new_with_proto_and_callback. For a tcp-listen netconn, this recvmbox is later freed and a new mbox is allocated for acceptmbox. This is a fix for thread-safety and allocates all items needed for a netconn when the netconn is created. 2007-11-30 Simon Goldschmidt * udp.c: first attempt to fix bug #21655 (DHCP doesn't work reliably with multiple netifs): if LWIP_DHCP is enabled, UDP packets to DHCP_CLIENT_PORT are passed to netif->dhcp->pcb only (if that exists) and not to any other pcb for the same port (only solution to let UDP pcbs 'bind' to a netif instead of an IP address) 2007-11-27 Simon Goldschmidt * ip.c: fixed bug #21643 (udp_send/raw_send don't fail if netif is down) by letting ip_route only use netifs that are up. 2007-11-27 Simon Goldschmidt * err.h, api_lib.c, api_msg.c, sockets.c: Changed error handling: ERR_MEM, ERR_BUF and ERR_RTE are seen as non-fatal, all other errors are fatal. netconns and sockets block most operations once they have seen a fatal error. 2007-11-27 Simon Goldschmidt * udp.h, udp.c, dhcp.c: Implemented new function udp_sendto_if which takes the netif to send as an argument (to be able to send on netifs that are down). 2007-11-26 Simon Goldschmidt * tcp_in.c: Fixed bug #21582: pcb->acked accounting can be wrong when ACKs arrive out-of-order 2007-11-21 Simon Goldschmidt * tcp.h, tcp_out.c, api_msg.c: Fixed bug #20287: tcp_output_nagle sends too early Fixed the nagle algorithm; nagle now also works for all raw API applications and has to be explicitly disabled with 'tcp_pcb->flags |= TF_NODELAY' 2007-11-12 Frédéric Bernon * sockets.c, api.h, api_lib.c, api_msg.h, api_msg.c: Fixed bug #20900. Now, most of the netconn_peer and netconn_addr processing is done inside tcpip_thread context in do_getaddr. 2007-11-10 Simon Goldschmidt * etharp.c: Fixed bug: assert fired when MEMP_ARP_QUEUE was empty (which can happen any time). Now the packet simply isn't enqueued when out of memory. 2007-11-01 Simon Goldschmidt * tcp.c, tcp_in.c: Fixed bug #21494: The send mss (pcb->mss) is set to 536 (or TCP_MSS if that is smaller) as long as no MSS option is received from the remote host. 2007-11-01 Simon Goldschmidt * tcp.h, tcp.c, tcp_in.c: Fixed bug #21491: The MSS option sent (with SYN) is now based on TCP_MSS instead of pcb->mss (on passive open now effectively sending our configured TCP_MSS instead of the one received). 2007-11-01 Simon Goldschmidt * tcp_in.c: Fixed bug #21181: On active open, the initial congestion window was calculated based on the configured TCP_MSS, not on the MSS option received with SYN+ACK. 2007-10-09 Simon Goldschmidt * udp.c, inet.c, inet.h: Fixed UDPLite: send: Checksum was always generated too short and also was generated wrong if checksum coverage != tot_len; receive: checksum was calculated wrong if checksum coverage != tot_len 2007-10-08 Simon Goldschmidt * mem.c: lfree was not updated in mem_realloc! 2007-10-07 Frédéric Bernon * sockets.c, api.h, api_lib.c: First step to fix "bug #20900 : Potential crash error problem with netconn_peer & netconn_addr". VERY IMPORTANT: this change cause an API breakage for netconn_addr, since a parameter type change. Any compiler should cause an error without any changes in yours netconn_peer calls (so, it can't be a "silent change"). It also reduce a little bit the footprint for socket layer (lwip_getpeername & lwip_getsockname use now a common lwip_getaddrname function since netconn_peer & netconn_addr have the same parameters). 2007-09-20 Simon Goldschmidt * tcp.c: Fixed bug #21080 (tcp_bind without check pcbs in TIME_WAIT state) by checking tcp_tw_pcbs also 2007-09-19 Simon Goldschmidt * icmp.c: Fixed bug #21107 (didn't reset IP TTL in ICMP echo replies) 2007-09-15 Mike Kleshov * mem.c: Fixed bug #21077 (inaccuracy in calculation of lwip_stat.mem.used) 2007-09-06 Frédéric Bernon * several-files: replace some #include "arch/cc.h" by "lwip/arch.h", or simply remove it as long as "lwip/opt.h" is included before (this one include "lwip/debug.h" which already include "lwip/arch.h"). Like that, default defines are provided by "lwip/arch.h" if they are not defined in cc.h, in the same spirit than "lwip/opt.h" for lwipopts.h. 2007-08-30 Frédéric Bernon * igmp.h, igmp.c: Some changes to remove some redundant code, add some traces, and fix some coding style. 2007-08-28 Frédéric Bernon * tcpip.c: Fix TCPIP_MSG_INPKT processing: now, tcpip_input can be used for any kind of packets. These packets are considered like Ethernet packets (payload pointing to ethhdr) if the netif got the NETIF_FLAG_ETHARP flag. Else, packets are considered like IP packets (payload pointing to iphdr). 2007-08-27 Frédéric Bernon * api.h, api_lib.c, api_msg.c: First fix for "bug #20900 : Potential crash error problem with netconn_peer & netconn_addr". Introduce NETCONN_LISTEN netconn_state and remove obsolete ones (NETCONN_RECV & NETCONN_ACCEPT). 2007-08-24 Kieran Mansley * inet.c Modify (acc >> 16) test to ((acc >> 16) != 0) to help buggy compiler (Paradigm C++) 2007-08-09 Frédéric Bernon, Bill Florac * stats.h, stats.c, igmp.h, igmp.c, opt.h: Fix for bug #20503 : IGMP Improvement. Introduce IGMP_STATS to centralize statistics management. 2007-08-09 Frédéric Bernon, Bill Florac * udp.c: Fix for bug #20503 : IGMP Improvement. Enable to receive a multicast packet on a udp pcb binded on an netif's IP address, and not on "any". 2007-08-09 Frédéric Bernon, Bill Florac * igmp.h, igmp.c, ip.c: Fix minor changes from bug #20503 : IGMP Improvement. This is mainly on using lookup/lookfor, and some coding styles... 2007-07-26 Frédéric Bernon (and "thedoctor") * igmp.c: Fix bug #20595 to accept IGMPv3 "Query" messages. 2007-07-25 Simon Goldschmidt * api_msg.c, tcp.c: Another fix for bug #20021: by not returning an error if tcp_output fails in tcp_close, the code in do_close_internal gets simpler (tcp_output is called again later from tcp timers). 2007-07-25 Simon Goldschmidt * ip_frag.c: Fixed bug #20429: use the new pbuf_copy_partial instead of the old copy_from_pbuf, which illegally modified the given pbuf. 2007-07-25 Simon Goldschmidt * tcp_out.c: tcp_enqueue: pcb->snd_queuelen didn't work for chaine PBUF_RAMs: changed snd_queuelen++ to snd_queuelen += pbuf_clen(p). 2007-07-24 Simon Goldschmidt * api_msg.c, tcp.c: Fix bug #20480: Check the pcb passed to tcp_listen() for the correct state (must be CLOSED). 2007-07-13 Thomas Taranowski (commited by Jared Grubb) * memp.c: Fix bug #20478: memp_malloc returned NULL+MEMP_SIZE on failed allocation. It now returns NULL. 2007-07-13 Frédéric Bernon * api_msg.c: Fix bug #20318: api_msg "recv" callbacks don't call pbuf_free in all error cases. 2007-07-13 Frédéric Bernon * api_msg.c: Fix bug #20315: possible memory leak problem if tcp_listen failed, because current code doesn't follow rawapi.txt documentation. 2007-07-13 Kieran Mansley * src/core/tcp_in.c Apply patch#5741 from Oleg Tyshev to fix bug in out of sequence processing of received packets 2007-07-03 Simon Goldschmidt * nearly-all-files: Added assertions where PBUF_RAM pbufs are used and an assumption is made that this pbuf is in one piece (i.e. not chained). These assumptions clash with the possibility of converting to fully pool-based pbuf implementations, where PBUF_RAM pbufs might be chained. 2007-07-03 Simon Goldschmidt * api.h, api_lib.c, api_msg.c: Final fix for bug #20021 and some other problems when closing tcp netconns: removed conn->sem, less context switches when closing, both netconn_close and netconn_delete should safely close tcp connections. 2007-07-02 Simon Goldschmidt * ipv4/ip.h, ipv6/ip.h, opt.h, netif.h, etharp.h, ipv4/ip.c, netif.c, raw.c, tcp_out.c, udp.c, etharp.c: Added option LWIP_NETIF_HWADDRHINT (default=off) to cache ARP table indices with each pcb instead of single-entry cache for the complete stack. 2007-07-02 Simon Goldschmidt * tcp.h, tcp.c, tcp_in.c, tcp_out.c: Added some ASSERTS and casts to prevent warnings when assigning to smaller types. 2007-06-28 Simon Goldschmidt * tcp_out.c: Added check to prevent tcp_pcb->snd_queuelen from overflowing. 2007-06-28 Simon Goldschmidt * tcp.h: Fixed bug #20287: Fixed nagle algorithm (sending was done too early if a segment contained chained pbufs) 2007-06-28 Frédéric Bernon * autoip.c: replace most of rand() calls by a macro LWIP_AUTOIP_RAND which compute a "pseudo-random" value based on netif's MAC and some autoip fields. It's always possible to define this macro in your own lwipopts.h to always use C library's rand(). Note that autoip_create_rand_addr doesn't use this macro. 2007-06-28 Frédéric Bernon * netifapi.h, netifapi.c, tcpip.h, tcpip.c: Update code to handle the option LWIP_TCPIP_CORE_LOCKING, and do some changes to be coherent with last modifications in api_lib/api_msg (use pointers and not type with table, etc...) 2007-06-26 Simon Goldschmidt * udp.h: Fixed bug #20259: struct udp_hdr was lacking the packin defines. 2007-06-25 Simon Goldschmidt * udp.c: Fixed bug #20253: icmp_dest_unreach was called with a wrong p->payload for udp packets with no matching pcb. 2007-06-25 Simon Goldschmidt * udp.c: Fixed bug #20220: UDP PCB search in udp_input(): a non-local match could get udp input packets if the remote side matched. 2007-06-13 Simon Goldschmidt * netif.c: Fixed bug #20180 (TCP pcbs listening on IP_ADDR_ANY could get changed in netif_set_ipaddr if previous netif->ip_addr.addr was 0. 2007-06-13 Simon Goldschmidt * api_msg.c: pcb_new sets conn->err if protocol is not implemented -> netconn_new_..() does not allocate a new connection for unsupported protocols. 2007-06-13 Frédéric Bernon, Simon Goldschmidt * api_lib.c: change return expression in netconn_addr and netconn_peer, because conn->err was reset to ERR_OK without any reasons (and error was lost)... 2007-06-13 Frédéric Bernon, Matthias Weisser * opt.h, mem.h, mem.c, memp.c, pbuf.c, ip_frag.c, vj.c: Fix bug #20162. Rename MEM_ALIGN in LWIP_MEM_ALIGN and MEM_ALIGN_SIZE in LWIP_MEM_ALIGN_SIZE to avoid some macro names collision with some OS macros. 2007-06-11 Simon Goldschmidt * udp.c: UDP Lite: corrected the use of chksum_len (based on RFC3828: if it's 0, create checksum over the complete packet. On RX, if it's < 8 (and not 0), discard the packet. Also removed the duplicate 'udphdr->chksum = 0' for both UDP & UDP Lite. 2007-06-11 Srinivas Gollakota & Oleg Tyshev * tcp_out.c: Fix for bug #20075 : "A problem with keep-alive timer and TCP flags" where TCP flags wasn't initialized in tcp_keepalive. 2007-06-03 Simon Goldschmidt * udp.c: udp_input(): Input pbuf was not freed if pcb had no recv function registered, p->payload was modified without modifying p->len if sending icmp_dest_unreach() (had no negative effect but was definitively wrong). 2007-06-03 Simon Goldschmidt * icmp.c: Corrected bug #19937: For responding to an icmp echo request, icmp re-used the input pbuf even if that didn't have enough space to include the link headers. Now the space is tested and a new pbuf is allocated for the echo response packet if the echo request pbuf isn't big enough. 2007-06-01 Simon Goldschmidt * sockets.c: Checked in patch #5914: Moved sockopt processing into tcpip_thread. 2007-05-23 Frédéric Bernon * api_lib.c, sockets.c: Fixed bug #5958 for netconn_listen (acceptmbox only allocated by do_listen if success) and netconn_accept errors handling. In most of api_lib functions, we replace some errors checkings like "if (conn==NULL)" by ASSERT, except for netconn_delete. 2007-05-23 Frédéric Bernon * api_lib.c: Fixed bug #5957 "Safe-thread problem inside netconn_recv" to return an error code if it's impossible to fetch a pbuf on a TCP connection (and not directly close the recvmbox). 2007-05-22 Simon Goldschmidt * tcp.c: Fixed bug #1895 (tcp_bind not correct) by introducing a list of bound but unconnected (and non-listening) tcp_pcbs. 2007-05-22 Frédéric Bernon * sys.h, sys.c, api_lib.c, tcpip.c: remove sys_mbox_fetch_timeout() (was only used for LWIP_SO_RCVTIMEO option) and use sys_arch_mbox_fetch() instead of sys_mbox_fetch() in api files. Now, users SHOULD NOT use internal lwIP features like "sys_timeout" in their application threads. 2007-05-22 Frédéric Bernon * api.h, api_lib.c, api_msg.h, api_msg.c: change the struct api_msg_msg to see which parameters are used by which do_xxx function, and to avoid "misusing" parameters (patch #5938). 2007-05-22 Simon Goldschmidt * api_lib.c, api_msg.c, raw.c, api.h, api_msg.h, raw.h: Included patch #5938: changed raw_pcb.protocol from u16_t to u8_t since for IPv4 and IPv6, proto is only 8 bits wide. This affects the api, as there, the protocol was u16_t, too. 2007-05-18 Simon Goldschmidt * memp.c: addition to patch #5913: smaller pointer was returned but memp_memory was the same size -> did not save memory. 2007-05-16 Simon Goldschmidt * loopif.c, slipif.c: Fix bug #19729: free pbuf if netif->input() returns != ERR_OK. 2007-05-16 Simon Goldschmidt * api_msg.c, udp.c: If a udp_pcb has a local_ip set, check if it is the same as the one of the netif used for sending to prevent sending from old addresses after a netif address gets changed (partly fixes bug #3168). 2007-05-16 Frédéric Bernon * tcpip.c, igmp.h, igmp.c: Fixed bug "#19800 : IGMP: igmp_tick() will not work with NO_SYS=1". Note that igmp_init is always in tcpip_thread (and not in tcpip_init) because we have to be sure that network interfaces are already added (mac filter is updated only in igmp_init for the moment). 2007-05-16 Simon Goldschmidt * mem.c, memp.c: Removed semaphores from memp, changed sys_sem_wait calls into sys_arch_sem_wait calls to prevent timers from running while waiting for the heap. This fixes bug #19167. 2007-05-13 Simon Goldschmidt * tcp.h, sockets.h, sockets.c: Fixed bug from patch #5865 by moving the defines for socket options (lwip_set/-getsockopt) used with level IPPROTO_TCP from tcp.h to sockets.h. 2007-05-07 Simon Goldschmidt * mem.c: Another attempt to fix bug #17922. 2007-05-04 Simon Goldschmidt * pbuf.c, pbuf.h, etharp.c: Further update to ARP queueing: Changed pbuf_copy() implementation so that it can be reused (don't allocate the target pbuf inside pbuf_copy()). 2007-05-04 Simon Goldschmidt * memp.c: checked in patch #5913: in memp_malloc() we can return memp as mem to save a little RAM (next pointer of memp is not used while not in pool). 2007-05-03 "maq" * sockets.c: Fix ioctl FIONREAD when some data remains from last recv. (patch #3574). 2007-04-23 Simon Goldschmidt * loopif.c, loopif.h, opt.h, src/netif/FILES: fix bug #2595: "loopif results in NULL reference for incoming TCP packets". Loopif has to be configured (using LWIP_LOOPIF_MULTITHREADING) to directly call netif->input() (multithreading environments, e.g. netif->input() = tcpip_input()) or putting packets on a list that is fed to the stack by calling loopif_poll() (single-thread / NO_SYS / polling environment where e.g. netif->input() = ip_input). 2007-04-17 Jonathan Larmour * pbuf.c: Use s32_t in pbuf_realloc(), as an s16_t can't reliably hold the difference between two u16_t's. * sockets.h: FD_SETSIZE needs to match number of sockets, which is MEMP_NUM_NETCONN in sockets.c right now. 2007-04-12 Jonathan Larmour * icmp.c: Reset IP header TTL in ICMP ECHO responses (bug #19580). 2007-04-12 Kieran Mansley * tcp.c, tcp_in.c, tcp_out.c, tcp.h: Modify way the retransmission timer is reset to fix bug#19434, with help from Oleg Tyshev. 2007-04-11 Simon Goldschmidt * etharp.c, pbuf.c, pbuf.h: 3rd fix for bug #11400 (arp-queuing): More pbufs than previously thought need to be copied (everything but PBUF_ROM!). Cleaned up pbuf.c: removed functions no needed any more (by etharp). 2007-04-11 Kieran Mansley * inet.c, ip_addr.h, sockets.h, sys.h, tcp.h: Apply patch #5745: Fix "Constant is long" warnings with 16bit compilers. Contributed by avatar@mmlab.cse.yzu.edu.tw 2007-04-05 Frédéric Bernon, Jonathan Larmour * api_msg.c: Fix bug #16830: "err_tcp() posts to connection mailbox when no pend on the mailbox is active". Now, the post is only done during a connect, and do_send, do_write and do_join_leave_group don't do anything if a previous error was signaled. 2007-04-03 Frédéric Bernon * ip.c: Don't set the IP_DF ("Don't fragment") flag in the IP header in IP output packets. See patch #5834. 2007-03-30 Frédéric Bernon * api_msg.c: add a "pcb_new" helper function to avoid redundant code, and to add missing pcb allocations checking (in do_bind, and for each raw_new). Fix style. 2007-03-30 Frédéric Bernon * most of files: prefix all debug.h define with "LWIP_" to avoid any conflict with others environment defines (these were too "generic"). 2007-03-28 Frédéric Bernon * api.h, api_lib.c, sockets.c: netbuf_ref doesn't check its internal pbuf_alloc call result and can cause a crash. lwip_send now check netbuf_ref result. 2007-03-28 Simon Goldschmidt * sockets.c Remove "#include " from sockets.c to avoid multiple definition of macros (in errno.h and lwip/arch.h) if LWIP_PROVIDE_ERRNO is defined. This is the way it should have been already (looking at doc/sys_arch.txt) 2007-03-28 Kieran Mansley * opt.h Change default PBUF_POOL_BUFSIZE (again) to accomodate default MSS + IP and TCP headers *and* physical link headers 2007-03-26 Frédéric Bernon (based on patch from Dmitry Potapov) * api_lib.c: patch for netconn_write(), fixes a possible race condition which cause to send some garbage. It is not a definitive solution, but the patch does solve the problem for most cases. 2007-03-22 Frédéric Bernon * api_msg.h, api_msg.c: Remove obsolete API_MSG_ACCEPT and do_accept (never used). 2007-03-22 Frédéric Bernon * api_lib.c: somes resources couldn't be freed if there was errors during netconn_new_with_proto_and_callback. 2007-03-22 Frédéric Bernon * ethernetif.c: update netif->input calls to check return value. In older ports, it's a good idea to upgrade them, even if before, there could be another problem (access to an uninitialized mailbox). 2007-03-21 Simon Goldschmidt * sockets.c: fixed bug #5067 (essentialy a signed/unsigned warning fixed by casting to unsigned). 2007-03-21 Frédéric Bernon * api_lib.c, api_msg.c, tcpip.c: integrate sys_mbox_fetch(conn->mbox, NULL) calls from api_lib.c to tcpip.c's tcpip_apimsg(). Now, use a local variable and not a dynamic one from memp to send tcpip_msg to tcpip_thread in a synchrone call. Free tcpip_msg from tcpip_apimsg is not done in tcpip_thread. This give a faster and more reliable communication between api_lib and tcpip. 2007-03-21 Frédéric Bernon * opt.h: Add LWIP_NETIF_CALLBACK (to avoid compiler warning) and set it to 0. 2007-03-21 Frédéric Bernon * api_msg.c, igmp.c, igmp.h: Fix C++ style comments 2007-03-21 Kieran Mansley * opt.h Change default PBUF_POOL_BUFSIZE to accomodate default MSS + IP and TCP headers 2007-03-21 Kieran Mansley * Fix all uses of pbuf_header to check the return value. In some cases just assert if it fails as I'm not sure how to fix them, but this is no worse than before when they would carry on regardless of the failure. 2007-03-21 Kieran Mansley * sockets.c, igmp.c, igmp.h, memp.h: Fix C++ style comments and comment out missing header include in icmp.c 2007-03-20 Frédéric Bernon * memp.h, stats.c: Fix stats_display function where memp_names table wasn't synchronized with memp.h. 2007-03-20 Frédéric Bernon * tcpip.c: Initialize tcpip's mbox, and verify if initialized in tcpip_input, tcpip_ethinput, tcpip_callback, tcpip_apimsg, to fix a init problem with network interfaces. Also fix a compiler warning. 2007-03-20 Kieran Mansley * udp.c: Only try and use pbuf_header() to make space for headers if not a ROM or REF pbuf. 2007-03-19 Frédéric Bernon * api_msg.h, api_msg.c, tcpip.h, tcpip.c: Add return types to tcpip_apimsg() and api_msg_post(). 2007-03-19 Frédéric Bernon * Remove unimplemented "memp_realloc" function from memp.h. 2007-03-11 Simon Goldschmidt * pbuf.c: checked in patch #5796: pbuf_alloc: len field claculation caused memory corruption. 2007-03-11 Simon Goldschmidt (based on patch from Dmitry Potapov) * api_lib.c, sockets.c, api.h, api_msg.h, sockets.h: Fixed bug #19251 (missing `const' qualifier in socket functions), to get more compatible to standard POSIX sockets. 2007-03-11 Frédéric Bernon (based on patch from Dmitry Potapov) * sockets.c: Add asserts inside bind, connect and sendto to check input parameters. Remove excessive set_errno() calls after get_socket(), because errno is set inside of get_socket(). Move last sock_set_errno() inside lwip_close. 2007-03-09 Simon Goldschmidt * memp.c: Fixed bug #11400: New etharp queueing introduced bug: memp_memory was allocated too small. 2007-03-06 Simon Goldschmidt * tcpip.c: Initialize dhcp timers in tcpip_thread (if LWIP_DHCP) to protect the stack from concurrent access. 2007-03-06 Frédéric Bernon, Dmitry Potapov * tcpip.c, ip_frag.c, ethernetif.c: Fix some build problems, and a redundancy call to "lwip_stats.link.recv++;" in low_level_input() & ethernetif_input(). 2007-03-06 Simon Goldschmidt * ip_frag.c, ip_frag.h: Reduce code size: don't include code in those files if IP_FRAG == 0 and IP_REASSEMBLY == 0 2007-03-06 Frédéric Bernon, Simon Goldschmidt * opt.h, ip_frag.h, tcpip.h, tcpip.c, ethernetif.c: add new configuration option named ETHARP_TCPIP_ETHINPUT, which enable the new tcpip_ethinput. Allow to do ARP processing for incoming packets inside tcpip_thread (protecting ARP layer against concurrent access). You can also disable old code using tcp_input with new define ETHARP_TCPIP_INPUT set to 0. Older ports have to use tcpip_ethinput. 2007-03-06 Simon Goldschmidt (based on patch from Dmitry Potapov) * err.h, err.c: fixed compiler warning "initialization dircards qualifiers from pointer target type" 2007-03-05 Frédéric Bernon * opt.h, sockets.h: add new configuration options (LWIP_POSIX_SOCKETS_IO_NAMES, ETHARP_TRUST_IP_MAC, review SO_REUSE) 2007-03-04 Frédéric Bernon * api_msg.c: Remove some compiler warnings : parameter "pcb" was never referenced. 2007-03-04 Frédéric Bernon * api_lib.c: Fix "[patch #5764] api_lib.c cleanup: after patch #5687" (from Dmitry Potapov). The api_msg struct stay on the stack (not moved to netconn struct). 2007-03-04 Simon Goldschmidt (based on patch from Dmitry Potapov) * pbuf.c: Fix BUG#19168 - pbuf_free can cause deadlock (if SYS_LIGHTWEIGHT_PROT=1 & freeing PBUF_RAM when mem_sem is not available) Also fixed cast warning in pbuf_alloc() 2007-03-04 Simon Goldschmidt * etharp.c, etharp.h, memp.c, memp.h, opt.h: Fix BUG#11400 - don't corrupt existing pbuf chain when enqueuing multiple pbufs to a pending ARP request 2007-03-03 Frédéric Bernon * udp.c: remove obsolete line "static struct udp_pcb *pcb_cache = NULL;" It is static, and never used in udp.c except udp_init(). 2007-03-02 Simon Goldschmidt * tcpip.c: Moved call to ip_init(), udp_init() and tcp_init() from tcpip_thread() to tcpip_init(). This way, raw API connections can be initialized before tcpip_thread is running (e.g. before OS is started) 2007-03-02 Frédéric Bernon * rawapi.txt: Fix documentation mismatch with etharp.h about etharp_tmr's call interval. 2007-02-28 Kieran Mansley * pbuf.c: Fix BUG#17645 - ensure pbuf payload pointer is not moved outside the region of the pbuf by pbuf_header() 2007-02-28 Kieran Mansley * sockets.c: Fix BUG#19161 - ensure milliseconds timeout is non-zero when supplied timeout is also non-zero (STABLE-1.2.0) 2006-12-05 Leon Woestenberg * CHANGELOG: Mention STABLE-1.2.0 release. ++ New features: 2006-12-01 Christiaan Simons * mem.h, opt.h: Added MEM_LIBC_MALLOC option. Note this is a workaround. Currently I have no other options left. 2006-10-26 Christiaan Simons (accepted patch by Jonathan Larmour) * ipv4/ip_frag.c: rename MAX_MTU to IP_FRAG_MAX_MTU and move define to include/lwip/opt.h. * ipv4/lwip/ip_frag.h: Remove unused IP_REASS_INTERVAL. Move IP_REASS_MAXAGE and IP_REASS_BUFSIZE to include/lwip/opt.h. * opt.h: Add above new options. 2006-08-18 Christiaan Simons * tcp_{in,out}.c: added SNMP counters. * ipv4/ip.c: added SNMP counters. * ipv4/ip_frag.c: added SNMP counters. 2006-08-08 Christiaan Simons * etharp.{c,h}: added etharp_find_addr() to read (stable) ethernet/IP address pair from ARP table 2006-07-14 Christiaan Simons * mib_structs.c: added * include/lwip/snmp_structs.h: added * netif.{c,h}, netif/ethernetif.c: added SNMP statistics to netif struct 2006-07-06 Christiaan Simons * snmp/asn1_{enc,dec}.c added * snmp/mib2.c added * snmp/msg_{in,out}.c added * include/lwip/snmp_asn1.h added * include/lwip/snmp_msg.h added * doc/snmp_agent.txt added 2006-03-29 Christiaan Simons * inet.c, inet.h: Added platform byteswap support. Added LWIP_PLATFORM_BYTESWAP define (defaults to 0) and optional LWIP_PLATFORM_HTONS(), LWIP_PLATFORM_HTONL() macros. ++ Bug fixes: 2006-11-30 Christiaan Simons * dhcp.c: Fixed false triggers of request_timeout. 2006-11-28 Christiaan Simons * netif.c: In netif_add() fixed missing clear of ip_addr, netmask, gw and flags. 2006-10-11 Christiaan Simons * api_lib.c etharp.c, ip.c, memp.c, stats.c, sys.{c,h} tcp.h: Partially accepted patch #5449 for ANSI C compatibility / build fixes. * ipv4/lwip/ip.h ipv6/lwip/ip.h: Corrected UDP-Lite protocol identifier from 170 to 136 (bug #17574). 2006-10-10 Christiaan Simons * api_msg.c: Fixed Nagle algorithm as reported by Bob Grice. 2006-08-17 Christiaan Simons * udp.c: Fixed bug #17200, added check for broadcast destinations for PCBs bound to a unicast address. 2006-08-07 Christiaan Simons * api_msg.c: Flushing TCP output in do_close() (bug #15926). 2006-06-27 Christiaan Simons * api_msg.c: Applied patch for cold case (bug #11135). In accept_function() ensure newconn->callback is always initialized. 2006-06-15 Christiaan Simons * mem.h: added MEM_SIZE_F alias to fix an ancient cold case (bug #1748), facilitate printing of mem_size_t and u16_t statistics. 2006-06-14 Christiaan Simons * api_msg.c: Applied patch #5146 to handle allocation failures in accept() by Kevin Lawson. 2006-05-26 Christiaan Simons * api_lib.c: Removed conn->sem creation and destruction from netconn_write() and added sys_sem_new to netconn_new_*. (STABLE-1_1_1) 2006-03-03 Christiaan Simons * ipv4/ip_frag.c: Added bound-checking assertions on ip_reassbitmap access and added pbuf_alloc() return value checks. 2006-01-01 Leon Woestenberg * tcp_{in,out}.c, tcp_out.c: Removed 'even sndbuf' fix in TCP, which is now handled by the checksum routine properly. 2006-02-27 Leon Woestenberg * pbuf.c: Fix alignment; pbuf_init() would not work unless pbuf_pool_memory[] was properly aligned. (Patch by Curt McDowell.) 2005-12-20 Leon Woestenberg * tcp.c: Remove PCBs which stay in LAST_ACK state too long. Patch submitted by Mitrani Hiroshi. 2005-12-15 Christiaan Simons * inet.c: Disabled the added summing routine to preserve code space. 2005-12-14 Leon Woestenberg * tcp_in.c: Duplicate FIN ACK race condition fix by Kelvin Lawson. Added Curt McDowell's optimized checksumming routine for future inclusion. Need to create test case for unaliged, aligned, odd, even length combination of cases on various endianess machines. 2005-12-09 Christiaan Simons * inet.c: Rewrote standard checksum routine in proper portable C. 2005-11-25 Christiaan Simons * udp.c tcp.c: Removed SO_REUSE hack. Should reside in socket code only. * *.c: introduced cc.h LWIP_DEBUG formatters matching the u16_t, s16_t, u32_t, s32_t typedefs. This solves most debug word-length assumes. 2005-07-17 Leon Woestenberg * inet.c: Fixed unaligned 16-bit access in the standard checksum routine by Peter Jolasson. * slipif.c: Fixed implementation assumption of single-pbuf datagrams. 2005-02-04 Leon Woestenberg * tcp_out.c: Fixed uninitialized 'queue' referenced in memerr branch. * tcp_{out|in}.c: Applied patch fixing unaligned access. 2005-01-04 Leon Woestenberg * pbuf.c: Fixed missing semicolon after LWIP_DEBUG statement. 2005-01-03 Leon Woestenberg * udp.c: UDP pcb->recv() was called even when it was NULL. (STABLE-1_1_0) 2004-12-28 Leon Woestenberg * etharp.*: Disabled multiple packets on the ARP queue. This clashes with TCP queueing. 2004-11-28 Leon Woestenberg * etharp.*: Fixed race condition from ARP request to ARP timeout. Halved the ARP period, doubled the period counts. ETHARP_MAX_PENDING now should be at least 2. This prevents the counter from reaching 0 right away (which would allow too little time for ARP responses to be received). 2004-11-25 Leon Woestenberg * dhcp.c: Decline messages were not multicast but unicast. * etharp.c: ETHARP_CREATE is renamed to ETHARP_TRY_HARD. Do not try hard to insert arbitrary packet's source address, etharp_ip_input() now calls etharp_update() without ETHARP_TRY_HARD. etharp_query() now always DOES call ETHARP_TRY_HARD so that users querying an address will see it appear in the cache (DHCP could suffer from this when a server invalidly gave an in-use address.) * ipv4/ip_addr.h: Renamed ip_addr_maskcmp() to _netcmp() as we are comparing network addresses (identifiers), not the network masks themselves. * ipv4/ip_addr.c: ip_addr_isbroadcast() now checks that the given IP address actually belongs to the network of the given interface. 2004-11-24 Kieran Mansley * tcp.c: Increment pcb->snd_buf when ACK is received in SYN_SENT state. (STABLE-1_1_0-RC1) 2004-10-16 Kieran Mansley * tcp.c: Add code to tcp_recved() to send an ACK (window update) immediately, even if one is already pending, if the rcv_wnd is above a threshold (currently TCP_WND/2). This avoids waiting for a timer to expire to send a delayed ACK in order to open the window if the stack is only receiving data. 2004-09-12 Kieran Mansley * tcp*.*: Retransmit time-out handling improvement by Sam Jansen. 2004-08-20 Tony Mountifield * etharp.c: Make sure the first pbuf queued on an ARP entry is properly ref counted. 2004-07-27 Tony Mountifield * debug.h: Added (int) cast in LWIP_DEBUGF() to avoid compiler warnings about comparison. * pbuf.c: Stopped compiler complaining of empty if statement when LWIP_DEBUGF() empty. Closed an unclosed comment. * tcp.c: Stopped compiler complaining of empty if statement when LWIP_DEBUGF() empty. * ip.h Corrected IPH_TOS() macro: returns a byte, so doesn't need htons(). * inet.c: Added a couple of casts to quiet the compiler. No need to test isascii(c) before isdigit(c) or isxdigit(c). 2004-07-22 Tony Mountifield * inet.c: Made data types consistent in inet_ntoa(). Added casts for return values of checksum routines, to pacify compiler. * ip_frag.c, tcp_out.c, sockets.c, pbuf.c Small corrections to some debugging statements, to pacify compiler. 2004-07-21 Tony Mountifield * etharp.c: Removed spurious semicolon and added missing end-of-comment. * ethernetif.c Updated low_level_output() to match prototype for netif->linkoutput and changed low_level_input() similarly for consistency. * api_msg.c: Changed recv_raw() from int to u8_t, to match prototype of raw_recv() in raw.h and so avoid compiler error. * sockets.c: Added trivial (int) cast to keep compiler happier. * ip.c, netif.c Changed debug statements to use the tidier ip4_addrN() macros. (STABLE-1_0_0) ++ Changes: 2004-07-05 Leon Woestenberg * sockets.*: Restructured LWIP_PRIVATE_TIMEVAL. Make sure your cc.h file defines this either 1 or 0. If non-defined, defaults to 1. * .c: Added and includes where used. * etharp.c: Made some array indices unsigned. 2004-06-27 Leon Woestenberg * netif.*: Added netif_set_up()/down(). * dhcp.c: Changes to restart program flow. 2004-05-07 Leon Woestenberg * etharp.c: In find_entry(), instead of a list traversal per candidate, do a single-pass lookup for different candidates. Should exploit locality. 2004-04-29 Leon Woestenberg * tcp*.c: Cleaned up source comment documentation for Doxygen processing. * opt.h: ETHARP_ALWAYS_INSERT option removed to comply with ARP RFC. * etharp.c: update_arp_entry() only adds new ARP entries when adviced to by the caller. This deprecates the ETHARP_ALWAYS_INSERT overrule option. ++ Bug fixes: 2004-04-27 Leon Woestenberg * etharp.c: Applied patch of bug #8708 by Toni Mountifield with a solution suggested by Timmy Brolin. Fix for 32-bit processors that cannot access non-aligned 32-bit words, such as soms 32-bit TCP/IP header fields. Fix is to prefix the 14-bit Ethernet headers with two padding bytes. 2004-04-23 Leon Woestenberg * ip_addr.c: Fix in the ip_addr_isbroadcast() check. * etharp.c: Fixed the case where the packet that initiates the ARP request is not queued, and gets lost. Fixed the case where the packets destination address is already known; we now always queue the packet and perform an ARP request. (STABLE-0_7_0) ++ Bug fixes: * Fixed TCP bug for SYN_SENT to ESTABLISHED state transition. * Fixed TCP bug in dequeueing of FIN from out of order segment queue. * Fixed two possible NULL references in rare cases. (STABLE-0_6_6) ++ Bug fixes: * Fixed DHCP which did not include the IP address in DECLINE messages. ++ Changes: * etharp.c has been hauled over a bit. (STABLE-0_6_5) ++ Bug fixes: * Fixed TCP bug induced by bad window resizing with unidirectional TCP traffic. * Packets sent from ARP queue had invalid source hardware address. ++ Changes: * Pass-by ARP requests do now update the cache. ++ New features: * No longer dependent on ctype.h. * New socket options. * Raw IP pcb support. (STABLE-0_6_4) ++ Bug fixes: * Some debug formatters and casts fixed. * Numereous fixes in PPP. ++ Changes: * DEBUGF now is LWIP_DEBUGF * pbuf_dechain() has been re-enabled. * Mentioned the changed use of CVS branches in README. (STABLE-0_6_3) ++ Bug fixes: * Fixed pool pbuf memory leak in pbuf_alloc(). Occured if not enough PBUF_POOL pbufs for a packet pbuf chain. Reported by Savin Zlobec. * PBUF_POOL chains had their tot_len field not set for non-first pbufs. Fixed in pbuf_alloc(). ++ New features: * Added PPP stack contributed by Marc Boucher ++ Changes: * Now drops short packets for ICMP/UDP/TCP protocols. More robust. * ARP queueuing now queues the latest packet instead of the first. This is the RFC recommended behaviour, but can be overridden in lwipopts.h. (0.6.2) ++ Bugfixes: * TCP has been fixed to deal with the new use of the pbuf->ref counter. * DHCP dhcp_inform() crash bug fixed. ++ Changes: * Removed pbuf_pool_free_cache and pbuf_pool_alloc_cache. Also removed pbuf_refresh(). This has sped up pbuf pool operations considerably. Implemented by David Haas. (0.6.1) ++ New features: * The packet buffer implementation has been enhanced to support zero-copy and copy-on-demand for packet buffers which have their payloads in application-managed memory. Implemented by David Haas. Use PBUF_REF to make a pbuf refer to RAM. lwIP will use zero-copy if an outgoing packet can be directly sent on the link, or perform a copy-on-demand when necessary. The application can safely assume the packet is sent, and the RAM is available to the application directly after calling udp_send() or similar function. ++ Bugfixes: * ARP_QUEUEING should now correctly work for all cases, including PBUF_REF. Implemented by Leon Woestenberg. ++ Changes: * IP_ADDR_ANY is no longer a NULL pointer. Instead, it is a pointer to a '0.0.0.0' IP address. * The packet buffer implementation is changed. The pbuf->ref counter meaning has changed, and several pbuf functions have been adapted accordingly. * netif drivers have to be changed to set the hardware address length field that must be initialized correctly by the driver (hint: 6 for Ethernet MAC). See the contrib/ports/c16x cs8900 driver as a driver example. * netif's have a dhcp field that must be initialized to NULL by the driver. See the contrib/ports/c16x cs8900 driver as a driver example. (0.5.x) This file has been unmaintained up to 0.6.1. All changes are logged in CVS but have not been explained here. (0.5.3) Changes since version 0.5.2 ++ Bugfixes: * memp_malloc(MEMP_API_MSG) could fail with multiple application threads because it wasn't protected by semaphores. ++ Other changes: * struct ip_addr now packed. * The name of the time variable in arp.c has been changed to ctime to avoid conflicts with the time() function. (0.5.2) Changes since version 0.5.1 ++ New features: * A new TCP function, tcp_tmr(), now handles both TCP timers. ++ Bugfixes: * A bug in tcp_parseopt() could cause the stack to hang because of a malformed TCP option. * The address of new connections in the accept() function in the BSD socket library was not handled correctly. * pbuf_dechain() did not update the ->tot_len field of the tail. * Aborted TCP connections were not handled correctly in all situations. ++ Other changes: * All protocol header structs are now packed. * The ->len field in the tcp_seg structure now counts the actual amount of data, and does not add one for SYN and FIN segments. (0.5.1) Changes since version 0.5.0 ++ New features: * Possible to run as a user process under Linux. * Preliminary support for cross platform packed structs. * ARP timer now implemented. ++ Bugfixes: * TCP output queue length was badly initialized when opening connections. * TCP delayed ACKs were not sent correctly. * Explicit initialization of BSS segment variables. * read() in BSD socket library could drop data. * Problems with memory alignment. * Situations when all TCP buffers were used could lead to starvation. * TCP MSS option wasn't parsed correctly. * Problems with UDP checksum calculation. * IP multicast address tests had endianess problems. * ARP requests had wrong destination hardware address. ++ Other changes: * struct eth_addr changed from u16_t[3] array to u8_t[6]. * A ->linkoutput() member was added to struct netif. * TCP and UDP ->dest_* struct members where changed to ->remote_*. * ntoh* macros are now null definitions for big endian CPUs. (0.5.0) Changes since version 0.4.2 ++ New features: * Redesigned operating system emulation layer to make porting easier. * Better control over TCP output buffers. * Documenation added. ++ Bugfixes: * Locking issues in buffer management. * Bugfixes in the sequential API. * IP forwarding could cause memory leakage. This has been fixed. ++ Other changes: * Directory structure somewhat changed; the core/ tree has been collapsed. (0.4.2) Changes since version 0.4.1 ++ New features: * Experimental ARP implementation added. * Skeleton Ethernet driver added. * Experimental BSD socket API library added. ++ Bugfixes: * In very intense situations, memory leakage could occur. This has been fixed. ++ Other changes: * Variables named "data" and "code" have been renamed in order to avoid name conflicts in certain compilers. * Variable++ have in appliciable cases been translated to ++variable since some compilers generate better code in the latter case. (0.4.1) Changes since version 0.4 ++ New features: * TCP: Connection attempts time out earlier than data transmissions. Nagle algorithm implemented. Push flag set on the last segment in a burst. * UDP: experimental support for UDP-Lite extensions. ++ Bugfixes: * TCP: out of order segments were in some cases handled incorrectly, and this has now been fixed. Delayed acknowledgements was broken in 0.4, has now been fixed. Binding to an address that is in use now results in an error. Reset connections sometimes hung an application; this has been fixed. * Checksum calculation sometimes failed for chained pbufs with odd lengths. This has been fixed. * API: a lot of bug fixes in the API. The UDP API has been improved and tested. Error reporting and handling has been improved. Logical flaws and race conditions for incoming TCP connections has been found and removed. * Memory manager: alignment issues. Reallocating memory sometimes failed, this has been fixed. * Generic library: bcopy was flawed and has been fixed. ++ Other changes: * API: all datatypes has been changed from generic ones such as ints, to specified ones such as u16_t. Functions that return errors now have the correct type (err_t). * General: A lot of code cleaned up and debugging code removed. Many portability issues have been fixed. * The license was changed; the advertising clause was removed. * C64 port added. * Thanks: Huge thanks go to Dagan Galarneau, Horst Garnetzke, Petri Kosunen, Mikael Caleres, and Frits Wilmink for reporting and fixing bugs! (0.4) Changes since version 0.3.1 * Memory management has been radically changed; instead of allocating memory from a shared heap, memory for objects that are rapidly allocated and deallocated is now kept in pools. Allocation and deallocation from those memory pools is very fast. The shared heap is still present but is used less frequently. * The memory, memory pool, and packet buffer subsystems now support 4-, 2-, or 1-byte alignment. * "Out of memory" situations are handled in a more robust way. * Stack usage has been reduced. * Easier configuration of lwIP parameters such as memory usage, TTLs, statistics gathering, etc. All configuration parameters are now kept in a single header file "lwipopts.h". * The directory structure has been changed slightly so that all architecture specific files are kept under the src/arch hierarchy. * Error propagation has been improved, both in the protocol modules and in the API. * The code for the RTXC architecture has been implemented, tested and put to use. * Bugs have been found and corrected in the TCP, UDP, IP, API, and the Internet checksum modules. * Bugs related to porting between a 32-bit and a 16-bit architecture have been found and corrected. * The license has been changed slightly to conform more with the original BSD license, including the advertisement clause. (0.3.1) Changes since version 0.3 * Fix of a fatal bug in the buffer management. Pbufs with allocated RAM never returned the RAM when the pbuf was deallocated. * TCP congestion control, window updates and retransmissions did not work correctly. This has now been fixed. * Bugfixes in the API. (0.3) Changes since version 0.2 * New and improved directory structure. All include files are now kept in a dedicated include/ directory. * The API now has proper error handling. A new function, netconn_err(), now returns an error code for the connection in case of errors. * Improvements in the memory management subsystem. The system now keeps a pointer to the lowest free memory block. A new function, mem_malloc2() tries to allocate memory once, and if it fails tries to free some memory and retry the allocation. * Much testing has been done with limited memory configurations. lwIP now does a better job when overloaded. * Some bugfixes and improvements to the buffer (pbuf) subsystem. * Many bugfixes in the TCP code: - Fixed a bug in tcp_close(). - The TCP receive window was incorrectly closed when out of sequence segments was received. This has been fixed. - Connections are now timed-out of the FIN-WAIT-2 state. - The initial congestion window could in some cases be too large. This has been fixed. - The retransmission queue could in some cases be screwed up. This has been fixed. - TCP RST flag now handled correctly. - Out of sequence data was in some cases never delivered to the application. This has been fixed. - Retransmitted segments now contain the correct acknowledgment number and advertised window. - TCP retransmission timeout backoffs are not correctly computed (ala BSD). After a number of retransmissions, TCP now gives up the connection. * TCP connections now are kept on three lists, one for active connections, one for listening connections, and one for connections that are in TIME-WAIT. This greatly speeds up the fast timeout processing for sending delayed ACKs. * TCP now provides proper feedback to the application when a connection has been successfully set up. * More comments have been added to the code. The code has also been somewhat cleaned up. (0.2) Initial public release. ocproxy-1.60/lwip/COPYING000066400000000000000000000031131303453231400151450ustar00rootroot00000000000000/* * Copyright (c) 2001, 2002 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ ocproxy-1.60/lwip/FILES000066400000000000000000000002161303453231400147000ustar00rootroot00000000000000src/ - The source code for the lwIP TCP/IP stack. doc/ - The documentation for lwIP. See also the FILES file in each subdirectory. ocproxy-1.60/lwip/README000066400000000000000000000063601303453231400150010ustar00rootroot00000000000000INTRODUCTION lwIP is a small independent implementation of the TCP/IP protocol suite that has been developed by Adam Dunkels at the Computer and Networks Architectures (CNA) lab at the Swedish Institute of Computer Science (SICS). The focus of the lwIP TCP/IP implementation is to reduce the RAM usage while still having a full scale TCP. This making lwIP suitable for use in embedded systems with tens of kilobytes of free RAM and room for around 40 kilobytes of code ROM. FEATURES * IP (Internet Protocol) including packet forwarding over multiple network interfaces * ICMP (Internet Control Message Protocol) for network maintenance and debugging * IGMP (Internet Group Management Protocol) for multicast traffic management * UDP (User Datagram Protocol) including experimental UDP-lite extensions * TCP (Transmission Control Protocol) with congestion control, RTT estimation and fast recovery/fast retransmit * Specialized raw/native API for enhanced performance * Optional Berkeley-like socket API * DNS (Domain names resolver) * SNMP (Simple Network Management Protocol) * DHCP (Dynamic Host Configuration Protocol) * AUTOIP (for IPv4, conform with RFC 3927) * PPP (Point-to-Point Protocol) * ARP (Address Resolution Protocol) for Ethernet LICENSE lwIP is freely available under a BSD license. DEVELOPMENT lwIP has grown into an excellent TCP/IP stack for embedded devices, and developers using the stack often submit bug fixes, improvements, and additions to the stack to further increase its usefulness. Development of lwIP is hosted on Savannah, a central point for software development, maintenance and distribution. Everyone can help improve lwIP by use of Savannah's interface, CVS and the mailing list. A core team of developers will commit changes to the CVS source tree. The lwIP TCP/IP stack is maintained in the 'lwip' CVS module and contributions (such as platform ports) are in the 'contrib' module. See doc/savannah.txt for details on CVS server access for users and developers. Last night's CVS tar ball can be downloaded from: http://savannah.gnu.org/cvs.backups/lwip.tar.gz [CHANGED - NEEDS FIXING] The current CVS trees are web-browsable: http://savannah.nongnu.org/cgi-bin/viewcvs/lwip/lwip/ http://savannah.nongnu.org/cgi-bin/viewcvs/lwip/contrib/ Submit patches and bugs via the lwIP project page: http://savannah.nongnu.org/projects/lwip/ DOCUMENTATION The original out-dated homepage of lwIP and Adam Dunkels' papers on lwIP are at the official lwIP home page: http://www.sics.se/~adam/lwip/ Self documentation of the source code is regularly extracted from the current CVS sources and is available from this web page: http://www.nongnu.org/lwip/ There is now a constantly growin wiki about lwIP at http://lwip.wikia.com/wiki/LwIP_Wiki Also, there are mailing lists you can subscribe at http://savannah.nongnu.org/mail/?group=lwip plus searchable archives: http://lists.nongnu.org/archive/html/lwip-users/ http://lists.nongnu.org/archive/html/lwip-devel/ Reading Adam's papers, the files in docs/, browsing the source code documentation and browsing the mailing list archives is a good way to become familiar with the design of lwIP. Adam Dunkels Leon Woestenberg ocproxy-1.60/lwip/UPGRADING000066400000000000000000000132571303453231400153670ustar00rootroot00000000000000This file lists major changes between release versions that require ports or applications to be changed. Use it to update a port or an application written for an older version of lwIP to correctly work with newer versions. (CVS HEAD) * [Enter new changes just after this line - do not remove this line] ++ Application changes: * Replaced struct ip_addr by typedef ip_addr_t (struct ip_addr is kept for compatibility to old applications, but will be removed in the future). * Renamed mem_realloc() to mem_trim() to prevent confusion with realloc() +++ Raw API: * Changed the semantics of tcp_close() (since it was rather a shutdown before): Now the application does *NOT* get any calls to the recv callback (aside from NULL/closed) after calling tcp_close() * When calling tcp_abort() from a raw API TCP callback function, make sure you return ERR_ABRT to prevent accessing unallocated memory. (ERR_ABRT now means the applicaiton has called tcp_abort!) +++ Netconn API: * Changed netconn_receive() and netconn_accept() to return err_t, not a pointer to new data/netconn. +++ Socket API: * LWIP_SO_RCVTIMEO: when accept() or recv() time out, they now set errno to EWOULDBLOCK/EAGAIN, not ETIMEDOUT. * Added a minimal version of posix fctl() to have a standardised way to set O_NONBLOCK for nonblocking sockets. +++ all APIs: * correctly implemented SO(F)_REUSEADDR ++ Port changes +++ new files: * Added 4 new files: def.c, timers.c, timers.h, tcp_impl.h: * Moved stack-internal parts of tcp.h to tcp_impl.h, tcp.h now only contains the actual application programmer's API * Separated timer implementation from sys.h/.c, moved to timers.h/.c; Added timer implementation for NO_SYS==1, set NO_SYS_NO_TIMERS==1 if you still want to use your own timer implementation for NO_SYS==0 (as before). +++ sys layer: * Converted mbox- and semaphore-functions to take pointers to sys_mbox_t/ sys_sem_t; * Converted sys_mbox_new/sys_sem_new to take pointers and return err_t; * Added Mutex concept in sys_arch (define LWIP_COMPAT_MUTEX to let sys.h use binary semaphores instead of mutexes - as before) +++ new options: * Don't waste memory when chaining segments, added option TCP_OVERSIZE to prevent creating many small pbufs when calling tcp_write with many small blocks of data. Instead, pbufs are allocated larger than needed and the space is used for later calls to tcp_write. * Added LWIP_NETIF_TX_SINGLE_PBUF to always copy to try to create single pbufs in tcp_write/udp_send. * Added an additional option LWIP_ETHERNET to support ethernet without ARP (necessary for pure PPPoE) * Add MEMP_SEPARATE_POOLS to place memory pools in separate arrays. This may be used to place these pools into user-defined memory by using external declaration. * Added TCP_SNDQUEUELOWAT corresponding to TCP_SNDLOWAT +++ new pools: * Netdb uses a memp pool for allocating memory when getaddrinfo() is called, so MEMP_NUM_NETDB has to be set accordingly. * DNS_LOCAL_HOSTLIST_IS_DYNAMIC uses a memp pool instead of the heap, so MEMP_NUM_LOCALHOSTLIST has to be set accordingly. * Snmp-agent uses a memp pools instead of the heap, so MEMP_NUM_SNMP_* have to be set accordingly. * PPPoE uses a MEMP pool instead of the heap, so MEMP_NUM_PPPOE_INTERFACES has to be set accordingly * Integrated loopif into netif.c - loopif does not have to be created by the port any more, just define LWIP_HAVE_LOOPIF to 1. * Added define LWIP_RAND() for lwip-wide randomization (needs to be defined in cc.h, e.g. used by igmp) * Added printf-formatter X8_F to printf u8_t as hex * The heap now may be moved to user-defined memory by defining LWIP_RAM_HEAP_POINTER as a void pointer to that memory's address * added autoip_set_struct() and dhcp_set_struct() to let autoip and dhcp work with user-allocated structs instead of calling mem_malloc * Added const char* name to mem- and memp-stats for easier debugging. * Calculate the TCP/UDP checksum while copying to only fetch data once: Define LWIP_CHKSUM_COPY to a memcpy-like function that returns the checksum * Added SO_REUSE_RXTOALL to pass received UDP broadcast/multicast packets to more than one pcb. * Changed the semantics of ARP_QUEUEING==0: ARP_QUEUEING now cannot be turned off any more, if this is set to 0, only one packet (the most recent one) is queued (like demanded by RFC 1122). ++ Major bugfixes/improvements * Implemented tcp_shutdown() to only shut down one end of a connection * Implemented shutdown() at socket- and netconn-level * Added errorset support to select() + improved select speed overhead * Merged pppd to v2.3.11 (including some backported bugfixes from 2.4.x) * Added timer implementation for NO_SYS==1 (may be disabled with NO_SYS_NO_TIMERS==1 * Use macros defined in ip_addr.h to work with IP addresses * Implemented many nonblocking socket/netconn functions * Fixed ARP input processing: only add a new entry if a request was directed as us * mem_realloc() to mem_trim() to prevent confusion with realloc() * Some improvements for AutoIP (don't route/forward link-local addresses, don't break existing connections when assigning a routable address) * Correctly handle remote side overrunning our rcv_wnd in ooseq case * Removed packing from ip_addr_t, the packed version is now only used in protocol headers * Corrected PBUF_POOL_BUFSIZE for ports where ETH_PAD_SIZE > 0 * Added support for static ARP table entries (STABLE-1.3.2) * initial version of this file ocproxy-1.60/lwip/VERSION000066400000000000000000000000511303453231400151600ustar00rootroot00000000000000e7f32240917cc912eb6e3e36780ecb3c4a06f264 ocproxy-1.60/lwip/doc/000077500000000000000000000000001303453231400146615ustar00rootroot00000000000000ocproxy-1.60/lwip/doc/FILES000066400000000000000000000006271303453231400154530ustar00rootroot00000000000000savannah.txt - How to obtain the current development source code. contrib.txt - How to contribute to lwIP as a developer. rawapi.txt - The documentation for the core API of lwIP. Also provides an overview about the other APIs and multithreading. snmp_agent.txt - The documentation for the lwIP SNMP agent. sys_arch.txt - The documentation for a system abstraction layer of lwIP. ocproxy-1.60/lwip/doc/contrib.txt000066400000000000000000000056601303453231400170710ustar00rootroot000000000000001 Introduction This document describes some guidelines for people participating in lwIP development. 2 How to contribute to lwIP Here is a short list of suggestions to anybody working with lwIP and trying to contribute bug reports, fixes, enhancements, platform ports etc. First of all as you may already know lwIP is a volunteer project so feedback to fixes or questions might often come late. Hopefully the bug and patch tracking features of Savannah help us not lose users' input. 2.1 Source code style: 1. do not use tabs. 2. indentation is two spaces per level (i.e. per tab). 3. end debug messages with a trailing newline (\n). 4. one space between keyword and opening bracket. 5. no space between function and opening bracket. 6. one space and no newline before opening curly braces of a block. 7. closing curly brace on a single line. 8. spaces surrounding assignment and comparisons. 9. don't initialize static and/or global variables to zero, the compiler takes care of that. 10. use current source code style as further reference. 2.2 Source code documentation style: 1. JavaDoc compliant and Doxygen compatible. 2. Function documentation above functions in .c files, not .h files. (This forces you to synchronize documentation and implementation.) 3. Use current documentation style as further reference. 2.3 Bug reports and patches: 1. Make sure you are reporting bugs or send patches against the latest sources. (From the latest release and/or the current CVS sources.) 2. If you think you found a bug make sure it's not already filed in the bugtracker at Savannah. 3. If you have a fix put the patch on Savannah. If it is a patch that affects both core and arch specific stuff please separate them so that the core can be applied separately while leaving the other patch 'open'. The prefered way is to NOT touch archs you can't test and let maintainers take care of them. This is a good way to see if they are used at all - the same goes for unix netifs except tapif. 4. Do not file a bug and post a fix to it to the patch area. Either a bug report or a patch will be enough. If you correct an existing bug then attach the patch to the bug rather than creating a new entry in the patch area. 5. Patches should be specific to a single change or to related changes.Do not mix bugfixes with spelling and other trivial fixes unless the bugfix is trivial too.Do not reorganize code and rename identifiers in the same patch you change behaviour if not necessary.A patch is easier to read and understand if it's to the point and short than if it's not to the point and long :) so the chances for it to be applied are greater. 2.4 Platform porters: 1. If you have ported lwIP to a platform (an OS, a uC/processor or a combination of these) and you think it could benefit others[1] you might want discuss this on the mailing list. You can also ask for CVS access to submit and maintain your port in the contrib CVS module. ocproxy-1.60/lwip/doc/rawapi.txt000066400000000000000000000500311303453231400167040ustar00rootroot00000000000000Raw TCP/IP interface for lwIP Authors: Adam Dunkels, Leon Woestenberg, Christiaan Simons lwIP provides three Application Program's Interfaces (APIs) for programs to use for communication with the TCP/IP code: * low-level "core" / "callback" or "raw" API. * higher-level "sequential" API. * BSD-style socket API. The sequential API provides a way for ordinary, sequential, programs to use the lwIP stack. It is quite similar to the BSD socket API. The model of execution is based on the blocking open-read-write-close paradigm. Since the TCP/IP stack is event based by nature, the TCP/IP code and the application program must reside in different execution contexts (threads). The socket API is a compatibility API for existing applications, currently it is built on top of the sequential API. It is meant to provide all functions needed to run socket API applications running on other platforms (e.g. unix / windows etc.). However, due to limitations in the specification of this API, there might be incompatibilities that require small modifications of existing programs. ** Threading lwIP started targeting single-threaded environments. When adding multi- threading support, instead of making the core thread-safe, another approach was chosen: there is one main thread running the lwIP core (also known as the "tcpip_thread"). The raw API may only be used from this thread! Application threads using the sequential- or socket API communicate with this main thread through message passing. As such, the list of functions that may be called from other threads or an ISR is very limited! Only functions from these API header files are thread-safe: - api.h - netbuf.h - netdb.h - netifapi.h - sockets.h - sys.h Additionaly, memory (de-)allocation functions may be called from multiple threads (not ISR!) with NO_SYS=0 since they are protected by SYS_LIGHTWEIGHT_PROT and/or semaphores. Only since 1.3.0, if SYS_LIGHTWEIGHT_PROT is set to 1 and LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT is set to 1, pbuf_free() may also be called from another thread or an ISR (since only then, mem_free - for PBUF_RAM - may be called from an ISR: otherwise, the HEAP is only protected by semaphores). ** The remainder of this document discusses the "raw" API. ** The raw TCP/IP interface allows the application program to integrate better with the TCP/IP code. Program execution is event based by having callback functions being called from within the TCP/IP code. The TCP/IP code and the application program both run in the same thread. The sequential API has a much higher overhead and is not very well suited for small systems since it forces a multithreaded paradigm on the application. The raw TCP/IP interface is not only faster in terms of code execution time but is also less memory intensive. The drawback is that program development is somewhat harder and application programs written for the raw TCP/IP interface are more difficult to understand. Still, this is the preferred way of writing applications that should be small in code size and memory usage. Both APIs can be used simultaneously by different application programs. In fact, the sequential API is implemented as an application program using the raw TCP/IP interface. --- Callbacks Program execution is driven by callbacks. Each callback is an ordinary C function that is called from within the TCP/IP code. Every callback function is passed the current TCP or UDP connection state as an argument. Also, in order to be able to keep program specific state, the callback functions are called with a program specified argument that is independent of the TCP/IP state. The function for setting the application connection state is: - void tcp_arg(struct tcp_pcb *pcb, void *arg) Specifies the program specific state that should be passed to all other callback functions. The "pcb" argument is the current TCP connection control block, and the "arg" argument is the argument that will be passed to the callbacks. --- TCP connection setup The functions used for setting up connections is similar to that of the sequential API and of the BSD socket API. A new TCP connection identifier (i.e., a protocol control block - PCB) is created with the tcp_new() function. This PCB can then be either set to listen for new incoming connections or be explicitly connected to another host. - struct tcp_pcb *tcp_new(void) Creates a new connection identifier (PCB). If memory is not available for creating the new pcb, NULL is returned. - err_t tcp_bind(struct tcp_pcb *pcb, ip_addr_t *ipaddr, u16_t port) Binds the pcb to a local IP address and port number. The IP address can be specified as IP_ADDR_ANY in order to bind the connection to all local IP addresses. If another connection is bound to the same port, the function will return ERR_USE, otherwise ERR_OK is returned. - struct tcp_pcb *tcp_listen(struct tcp_pcb *pcb) Commands a pcb to start listening for incoming connections. When an incoming connection is accepted, the function specified with the tcp_accept() function will be called. The pcb will have to be bound to a local port with the tcp_bind() function. The tcp_listen() function returns a new connection identifier, and the one passed as an argument to the function will be deallocated. The reason for this behavior is that less memory is needed for a connection that is listening, so tcp_listen() will reclaim the memory needed for the original connection and allocate a new smaller memory block for the listening connection. tcp_listen() may return NULL if no memory was available for the listening connection. If so, the memory associated with the pcb passed as an argument to tcp_listen() will not be deallocated. - struct tcp_pcb *tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog) Same as tcp_listen, but limits the number of outstanding connections in the listen queue to the value specified by the backlog argument. To use it, your need to set TCP_LISTEN_BACKLOG=1 in your lwipopts.h. - void tcp_accepted(struct tcp_pcb *pcb) Inform lwIP that an incoming connection has been accepted. This would usually be called from the accept callback. This allows lwIP to perform housekeeping tasks, such as allowing further incoming connections to be queued in the listen backlog. ATTENTION: the PCB passed in must be the listening pcb, not the pcb passed into the accept callback! - void tcp_accept(struct tcp_pcb *pcb, err_t (* accept)(void *arg, struct tcp_pcb *newpcb, err_t err)) Specified the callback function that should be called when a new connection arrives on a listening connection. - err_t tcp_connect(struct tcp_pcb *pcb, ip_addr_t *ipaddr, u16_t port, err_t (* connected)(void *arg, struct tcp_pcb *tpcb, err_t err)); Sets up the pcb to connect to the remote host and sends the initial SYN segment which opens the connection. The tcp_connect() function returns immediately; it does not wait for the connection to be properly setup. Instead, it will call the function specified as the fourth argument (the "connected" argument) when the connection is established. If the connection could not be properly established, either because the other host refused the connection or because the other host didn't answer, the "err" callback function of this pcb (registered with tcp_err, see below) will be called. The tcp_connect() function can return ERR_MEM if no memory is available for enqueueing the SYN segment. If the SYN indeed was enqueued successfully, the tcp_connect() function returns ERR_OK. --- Sending TCP data TCP data is sent by enqueueing the data with a call to tcp_write(). When the data is successfully transmitted to the remote host, the application will be notified with a call to a specified callback function. - err_t tcp_write(struct tcp_pcb *pcb, const void *dataptr, u16_t len, u8_t apiflags) Enqueues the data pointed to by the argument dataptr. The length of the data is passed as the len parameter. The apiflags can be one or more of: - TCP_WRITE_FLAG_COPY: indicates whether the new memory should be allocated for the data to be copied into. If this flag is not given, no new memory should be allocated and the data should only be referenced by pointer. This also means that the memory behind dataptr must not change until the data is ACKed by the remote host - TCP_WRITE_FLAG_MORE: indicates that more data follows. If this is given, the PSH flag is set in the last segment created by this call to tcp_write. If this flag is given, the PSH flag is not set. The tcp_write() function will fail and return ERR_MEM if the length of the data exceeds the current send buffer size or if the length of the queue of outgoing segment is larger than the upper limit defined in lwipopts.h. The number of bytes available in the output queue can be retrieved with the tcp_sndbuf() function. The proper way to use this function is to call the function with at most tcp_sndbuf() bytes of data. If the function returns ERR_MEM, the application should wait until some of the currently enqueued data has been successfully received by the other host and try again. - void tcp_sent(struct tcp_pcb *pcb, err_t (* sent)(void *arg, struct tcp_pcb *tpcb, u16_t len)) Specifies the callback function that should be called when data has successfully been received (i.e., acknowledged) by the remote host. The len argument passed to the callback function gives the amount bytes that was acknowledged by the last acknowledgment. --- Receiving TCP data TCP data reception is callback based - an application specified callback function is called when new data arrives. When the application has taken the data, it has to call the tcp_recved() function to indicate that TCP can advertise increase the receive window. - void tcp_recv(struct tcp_pcb *pcb, err_t (* recv)(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)) Sets the callback function that will be called when new data arrives. The callback function will be passed a NULL pbuf to indicate that the remote host has closed the connection. If there are no errors and the callback function is to return ERR_OK, then it must free the pbuf. Otherwise, it must not free the pbuf so that lwIP core code can store it. - void tcp_recved(struct tcp_pcb *pcb, u16_t len) Must be called when the application has received the data. The len argument indicates the length of the received data. --- Application polling When a connection is idle (i.e., no data is either transmitted or received), lwIP will repeatedly poll the application by calling a specified callback function. This can be used either as a watchdog timer for killing connections that have stayed idle for too long, or as a method of waiting for memory to become available. For instance, if a call to tcp_write() has failed because memory wasn't available, the application may use the polling functionality to call tcp_write() again when the connection has been idle for a while. - void tcp_poll(struct tcp_pcb *pcb, err_t (* poll)(void *arg, struct tcp_pcb *tpcb), u8_t interval) Specifies the polling interval and the callback function that should be called to poll the application. The interval is specified in number of TCP coarse grained timer shots, which typically occurs twice a second. An interval of 10 means that the application would be polled every 5 seconds. --- Closing and aborting connections - err_t tcp_close(struct tcp_pcb *pcb) Closes the connection. The function may return ERR_MEM if no memory was available for closing the connection. If so, the application should wait and try again either by using the acknowledgment callback or the polling functionality. If the close succeeds, the function returns ERR_OK. The pcb is deallocated by the TCP code after a call to tcp_close(). - void tcp_abort(struct tcp_pcb *pcb) Aborts the connection by sending a RST (reset) segment to the remote host. The pcb is deallocated. This function never fails. ATTENTION: When calling this from one of the TCP callbacks, make sure you always return ERR_ABRT (and never return ERR_ABRT otherwise or you will risk accessing deallocated memory or memory leaks! If a connection is aborted because of an error, the application is alerted of this event by the err callback. Errors that might abort a connection are when there is a shortage of memory. The callback function to be called is set using the tcp_err() function. - void tcp_err(struct tcp_pcb *pcb, void (* err)(void *arg, err_t err)) The error callback function does not get the pcb passed to it as a parameter since the pcb may already have been deallocated. --- Lower layer TCP interface TCP provides a simple interface to the lower layers of the system. During system initialization, the function tcp_init() has to be called before any other TCP function is called. When the system is running, the two timer functions tcp_fasttmr() and tcp_slowtmr() must be called with regular intervals. The tcp_fasttmr() should be called every TCP_FAST_INTERVAL milliseconds (defined in tcp.h) and tcp_slowtmr() should be called every TCP_SLOW_INTERVAL milliseconds. --- UDP interface The UDP interface is similar to that of TCP, but due to the lower level of complexity of UDP, the interface is significantly simpler. - struct udp_pcb *udp_new(void) Creates a new UDP pcb which can be used for UDP communication. The pcb is not active until it has either been bound to a local address or connected to a remote address. - void udp_remove(struct udp_pcb *pcb) Removes and deallocates the pcb. - err_t udp_bind(struct udp_pcb *pcb, ip_addr_t *ipaddr, u16_t port) Binds the pcb to a local address. The IP-address argument "ipaddr" can be IP_ADDR_ANY to indicate that it should listen to any local IP address. The function currently always return ERR_OK. - err_t udp_connect(struct udp_pcb *pcb, ip_addr_t *ipaddr, u16_t port) Sets the remote end of the pcb. This function does not generate any network traffic, but only set the remote address of the pcb. - err_t udp_disconnect(struct udp_pcb *pcb) Remove the remote end of the pcb. This function does not generate any network traffic, but only removes the remote address of the pcb. - err_t udp_send(struct udp_pcb *pcb, struct pbuf *p) Sends the pbuf p. The pbuf is not deallocated. - void udp_recv(struct udp_pcb *pcb, void (* recv)(void *arg, struct udp_pcb *upcb, struct pbuf *p, ip_addr_t *addr, u16_t port), void *recv_arg) Specifies a callback function that should be called when a UDP datagram is received. --- System initalization A truly complete and generic sequence for initializing the lwip stack cannot be given because it depends on the build configuration (lwipopts.h) and additional initializations for your runtime environment (e.g. timers). We can give you some idea on how to proceed when using the raw API. We assume a configuration using a single Ethernet netif and the UDP and TCP transport layers, IPv4 and the DHCP client. Call these functions in the order of appearance: - stats_init() Clears the structure where runtime statistics are gathered. - sys_init() Not of much use since we set the NO_SYS 1 option in lwipopts.h, to be called for easy configuration changes. - mem_init() Initializes the dynamic memory heap defined by MEM_SIZE. - memp_init() Initializes the memory pools defined by MEMP_NUM_x. - pbuf_init() Initializes the pbuf memory pool defined by PBUF_POOL_SIZE. - etharp_init() Initializes the ARP table and queue. Note: you must call etharp_tmr at a ARP_TMR_INTERVAL (5 seconds) regular interval after this initialization. - ip_init() Doesn't do much, it should be called to handle future changes. - udp_init() Clears the UDP PCB list. - tcp_init() Clears the TCP PCB list and clears some internal TCP timers. Note: you must call tcp_fasttmr() and tcp_slowtmr() at the predefined regular intervals after this initialization. - netif_add(struct netif *netif, ip_addr_t *ipaddr, ip_addr_t *netmask, ip_addr_t *gw, void *state, err_t (* init)(struct netif *netif), err_t (* input)(struct pbuf *p, struct netif *netif)) Adds your network interface to the netif_list. Allocate a struct netif and pass a pointer to this structure as the first argument. Give pointers to cleared ip_addr structures when using DHCP, or fill them with sane numbers otherwise. The state pointer may be NULL. The init function pointer must point to a initialization function for your ethernet netif interface. The following code illustrates it's use. err_t netif_if_init(struct netif *netif) { u8_t i; for(i = 0; i < ETHARP_HWADDR_LEN; i++) netif->hwaddr[i] = some_eth_addr[i]; init_my_eth_device(); return ERR_OK; } For ethernet drivers, the input function pointer must point to the lwip function ethernet_input() declared in "netif/etharp.h". Other drivers must use ip_input() declared in "lwip/ip.h". - netif_set_default(struct netif *netif) Registers the default network interface. - netif_set_up(struct netif *netif) When the netif is fully configured this function must be called. - dhcp_start(struct netif *netif) Creates a new DHCP client for this interface on the first call. Note: you must call dhcp_fine_tmr() and dhcp_coarse_tmr() at the predefined regular intervals after starting the client. You can peek in the netif->dhcp struct for the actual DHCP status. --- Optimalization hints The first thing you want to optimize is the lwip_standard_checksum() routine from src/core/inet.c. You can override this standard function with the #define LWIP_CHKSUM . There are C examples given in inet.c or you might want to craft an assembly function for this. RFC1071 is a good introduction to this subject. Other significant improvements can be made by supplying assembly or inline replacements for htons() and htonl() if you're using a little-endian architecture. #define LWIP_PLATFORM_BYTESWAP 1 #define LWIP_PLATFORM_HTONS(x) #define LWIP_PLATFORM_HTONL(x) Check your network interface driver if it reads at a higher speed than the maximum wire-speed. If the hardware isn't serviced frequently and fast enough buffer overflows are likely to occur. E.g. when using the cs8900 driver, call cs8900if_service(ethif) as frequently as possible. When using an RTOS let the cs8900 interrupt wake a high priority task that services your driver using a binary semaphore or event flag. Some drivers might allow additional tuning to match your application and network. For a production release it is recommended to set LWIP_STATS to 0. Note that speed performance isn't influenced much by simply setting high values to the memory options. For more optimization hints take a look at the lwIP wiki. --- Zero-copy MACs To achieve zero-copy on transmit, the data passed to the raw API must remain unchanged until sent. Because the send- (or write-)functions return when the packets have been enqueued for sending, data must be kept stable after that, too. This implies that PBUF_RAM/PBUF_POOL pbufs passed to raw-API send functions must *not* be reused by the application unless their ref-count is 1. For no-copy pbufs (PBUF_ROM/PBUF_REF), data must be kept unchanged, too, but the stack/driver will/must copy PBUF_REF'ed data when enqueueing, while PBUF_ROM-pbufs are just enqueued (as ROM-data is expected to never change). Also, data passed to tcp_write without the copy-flag must not be changed! Therefore, be careful which type of PBUF you use and if you copy TCP data or not! ocproxy-1.60/lwip/doc/savannah.txt000066400000000000000000000111351303453231400172220ustar00rootroot00000000000000Daily Use Guide for using Savannah for lwIP Table of Contents: 1 - Obtaining lwIP from the CVS repository 2 - Committers/developers CVS access using SSH (to be written) 3 - Merging from DEVEL branch to main trunk (stable branch) 4 - How to release lwIP 1 Obtaining lwIP from the CVS repository ---------------------------------------- To perform an anonymous CVS checkout of the main trunk (this is where bug fixes and incremental enhancements occur), do this: cvs -z3 -d:pserver:anonymous@cvs.sv.gnu.org:/sources/lwip checkout lwip Or, obtain a stable branch (updated with bug fixes only) as follows: cvs -z3 -d:pserver:anonymous@cvs.sv.gnu.org:/sources/lwip checkout \ -r STABLE-0_7 -d lwip-0.7 lwip Or, obtain a specific (fixed) release as follows: cvs -z3 -d:pserver:anonymous@cvs.sv.gnu.org:/sources/lwip checkout \ -r STABLE-0_7_0 -d lwip-0.7.0 lwip 3 Committers/developers CVS access using SSH -------------------------------------------- The Savannah server uses SSH (Secure Shell) protocol 2 authentication and encryption. As such, CVS commits to the server occur through a SSH tunnel for project members. To create a SSH2 key pair in UNIX-like environments, do this: ssh-keygen -t dsa Under Windows, a recommended SSH client is "PuTTY", freely available with good documentation and a graphic user interface. Use its key generator. Now paste the id_dsa.pub contents into your Savannah account public key list. Wait a while so that Savannah can update its configuration (This can take minutes). Try to login using SSH: ssh -v your_login@cvs.sv.gnu.org If it tells you: Authenticating with public key "your_key_name"... Server refused to allocate pty then you could login; Savannah refuses to give you a shell - which is OK, as we are allowed to use SSH for CVS only. Now, you should be able to do this: export CVS_RSH=ssh cvs -z3 -d:ext:your_login@cvs.sv.gnu.org:/sources/lwip co lwip after which you can edit your local files with bug fixes or new features and commit them. Make sure you know what you are doing when using CVS to make changes on the repository. If in doubt, ask on the lwip-members mailing list. (If SSH asks about authenticity of the host, you can check the key fingerprint against http://savannah.nongnu.org/cvs/?group=lwip) 3 Merging from DEVEL branch to main trunk (stable) -------------------------------------------------- Merging is a delicate process in CVS and requires the following disciplined steps in order to prevent conflicts in the future. Conflicts can be hard to solve! Merging from branch A to branch B requires that the A branch has a tag indicating the previous merger. This tag is called 'merged_from_A_to_B'. After merging, the tag is moved in the A branch to remember this merger for future merge actions. IMPORTANT: AFTER COMMITTING A SUCCESFUL MERGE IN THE REPOSITORY, THE TAG MUST BE SET ON THE SOURCE BRANCH OF THE MERGE ACTION (REPLACING EXISTING TAGS WITH THE SAME NAME). Merge all changes in DEVEL since our last merge to main: In the working copy of the main trunk: cvs update -P -jmerged_from_DEVEL_to_main -jDEVEL (This will apply the changes between 'merged_from_DEVEL_to_main' and 'DEVEL' to your work set of files) We can now commit the merge result. cvs commit -R -m "Merged from DEVEL to main." If this worked out OK, we now move the tag in the DEVEL branch to this merge point, so we can use this point for future merges: cvs rtag -F -r DEVEL merged_from_DEVEL_to_main lwip 4 How to release lwIP --------------------- First, checkout a clean copy of the branch to be released. Tag this set with tag name "STABLE-0_6_3". (I use release number 0.6.3 throughout this example). Login CVS using pserver authentication, then export a clean copy of the tagged tree. Export is similar to a checkout, except that the CVS metadata is not created locally. export CVS_RSH=ssh cvs -z3 -d:pserver:anonymous@cvs.sv.gnu.org:/sources/lwip checkout \ -r STABLE-0_6_3 -d lwip-0.6.3 lwip Archive this directory using tar, gzip'd, bzip2'd and zip'd. tar czvf lwip-0.6.3.tar.gz lwip-0.6.3 tar cjvf lwip-0.6.3.tar.bz2 lwip-0.6.3 zip -r lwip-0.6.3.zip lwip-0.6.3 Now, sign the archives with a detached GPG binary signature as follows: gpg -b lwip-0.6.3.tar.gz gpg -b lwip-0.6.3.tar.bz2 gpg -b lwip-0.6.3.zip Upload these files using anonymous FTP: ncftp ftp://savannah.gnu.org/incoming/savannah/lwip ncftp>mput *0.6.3.* Additionally, you may post a news item on Savannah, like this: A new 0.6.3 release is now available here: http://savannah.nongnu.org/files/?group=lwip&highlight=0.6.3 You will have to submit this via the user News interface, then approve this via the Administrator News interface.ocproxy-1.60/lwip/doc/snmp_agent.txt000066400000000000000000000143271303453231400175640ustar00rootroot00000000000000SNMPv1 agent for lwIP Author: Christiaan Simons This is a brief introduction how to use and configure the SNMP agent. Note the agent uses the raw-API UDP interface so you may also want to read rawapi.txt to gain a better understanding of the SNMP message handling. 0 Agent Capabilities ==================== SNMPv1 per RFC1157 This is an old(er) standard but is still widely supported. For SNMPv2c and v3 have a greater complexity and need many more lines of code. IMHO this breaks the idea of "lightweight IP". Note the S in SNMP stands for "Simple". Note that "Simple" is relative. SNMP is simple compared to the complex ISO network management protocols CMIP (Common Management Information Protocol) and CMOT (CMip Over Tcp). MIB II per RFC1213 The standard lwIP stack management information base. This is a required MIB, so this is always enabled. When builing lwIP without TCP, the mib-2.tcp group is omitted. The groups EGP, CMOT and transmission are disabled by default. Most mib-2 objects are not writable except: sysName, sysLocation, sysContact, snmpEnableAuthenTraps. Writing to or changing the ARP and IP address and route tables is not possible. Note lwIP has a very limited notion of IP routing. It currently doen't have a route table and doesn't have a notion of the U,G,H flags. Instead lwIP uses the interface list with only one default interface acting as a single gateway interface (G) for the default route. The agent returns a "virtual table" with the default route 0.0.0.0 for the default interface and network routes (no H) for each network interface in the netif_list. All routes are considered to be up (U). Loading additional MIBs MIBs can only be added in compile-time, not in run-time. There is no MIB compiler thus additional MIBs must be hand coded. Large SNMP message support The packet decoding and encoding routines are designed to use pbuf-chains. Larger payloads than the minimum SNMP requirement of 484 octets are supported if the PBUF_POOL_SIZE and IP_REASS_BUFSIZE are set to match your local requirement. 1 Building the Agent ==================== First of all you'll need to add the following define to your local lwipopts.h: #define LWIP_SNMP 1 and add the source files in lwip/src/core/snmp and some snmp headers in lwip/src/include/lwip to your makefile. Note you'll might need to adapt you network driver to update the mib2 variables for your interface. 2 Running the Agent =================== The following function calls must be made in your program to actually get the SNMP agent running. Before starting the agent you should supply pointers to non-volatile memory for sysContact, sysLocation, and snmpEnableAuthenTraps. You can do this by calling snmp_set_syscontact() snmp_set_syslocation() snmp_set_snmpenableauthentraps() Additionally you may want to set snmp_set_sysdescr() snmp_set_sysobjid() (if you have a private MIB) snmp_set_sysname() Also before starting the agent you need to setup one or more trap destinations using these calls: snmp_trap_dst_enable(); snmp_trap_dst_ip_set(); In the lwIP initialisation sequence call snmp_init() just after the call to udp_init(). Exactly every 10 msec the SNMP uptime timestamp must be updated with snmp_inc_sysuptime(). You should call this from a timer interrupt or a timer signal handler depending on your runtime environment. An alternative way to update the SNMP uptime timestamp is to do a call like snmp_add_sysuptime(100) each 1000ms (which is bigger "step", but call to a lower frequency). Another one is to not call snmp_inc_sysuptime() or snmp_add_sysuptime(), and to define the SNMP_GET_SYSUPTIME(sysuptime) macro. This one is undefined by default in mib2.c. SNMP_GET_SYSUPTIME is called inside snmp_get_sysuptime(u32_t *value), and enable to change "sysuptime" value only when it's queried (any function which need "sysuptime" have to call snmp_get_sysuptime). 3 Private MIBs ============== If want to extend the agent with your own private MIB you'll need to add the following define to your local lwipopts.h: #define SNMP_PRIVATE_MIB 1 You must provide the private_mib.h and associated files yourself. Note we don't have a "MIB compiler" that generates C source from a MIB, so you're required to do some serious coding if you enable this! Note the lwIP enterprise ID (26381) is assigned to the lwIP project, ALL OBJECT IDENTIFIERS LIVING UNDER THIS ID ARE ASSIGNED BY THE lwIP MAINTAINERS! If you need to create your own private MIB you'll need to apply for your own enterprise ID with IANA: http://www.iana.org/numbers.html You can set it by passing a struct snmp_obj_id to the agent using snmp_set_sysobjid(&my_object_id), just before snmp_init(). Note the object identifiers for thes MIB-2 and your private MIB tree must be kept in sorted ascending (lexicographical) order. This to ensure correct getnext operation. An example for a private MIB is part of the "minimal Unix" project: contrib/ports/unix/proj/minimal/lwip_prvmib.c The next chapter gives a more detailed description of the MIB-2 tree and the optional private MIB. 4 The Gory Details ================== 4.0 Object identifiers and the MIB tree. We have three distinct parts for all object identifiers: The prefix .iso.org.dod.internet the middle part .mgmt.mib-2.ip.ipNetToMediaTable.ipNetToMediaEntry.ipNetToMediaPhysAddress and the index part .1.192.168.0.1 Objects located above the .internet hierarchy aren't supported. Currently only the .mgmt sub-tree is available and when the SNMP_PRIVATE_MIB is enabled the .private tree becomes available too. Object identifiers from incoming requests are checked for a matching prefix, middle part and index part or are expanded(*) for GetNext requests with short or inexisting names in the request. (* we call this "expansion" but this also resembles the "auto-completion" operation) The middle part is usually located in ROM (const) to preserve precious RAM on small microcontrollers. However RAM location is possible for a dynamically changing private tree. The index part is handled by functions which in turn use dynamically allocated index trees from RAM. These trees are updated by e.g. the etharp code when new entries are made or removed form the ARP cache. /** @todo more gory details */ ocproxy-1.60/lwip/doc/sys_arch.txt000066400000000000000000000264321303453231400172440ustar00rootroot00000000000000sys_arch interface for lwIP 0.6++ Author: Adam Dunkels The operating system emulation layer provides a common interface between the lwIP code and the underlying operating system kernel. The general idea is that porting lwIP to new architectures requires only small changes to a few header files and a new sys_arch implementation. It is also possible to do a sys_arch implementation that does not rely on any underlying operating system. The sys_arch provides semaphores and mailboxes to lwIP. For the full lwIP functionality, multiple threads support can be implemented in the sys_arch, but this is not required for the basic lwIP functionality. Previous versions of lwIP required the sys_arch to implement timer scheduling as well but as of lwIP 0.5 this is implemented in a higher layer. In addition to the source file providing the functionality of sys_arch, the OS emulation layer must provide several header files defining macros used throughout lwip. The files required and the macros they must define are listed below the sys_arch description. Semaphores can be either counting or binary - lwIP works with both kinds. Mailboxes are used for message passing and can be implemented either as a queue which allows multiple messages to be posted to a mailbox, or as a rendez-vous point where only one message can be posted at a time. lwIP works with both kinds, but the former type will be more efficient. A message in a mailbox is just a pointer, nothing more. Semaphores are represented by the type "sys_sem_t" which is typedef'd in the sys_arch.h file. Mailboxes are equivalently represented by the type "sys_mbox_t". lwIP does not place any restrictions on how sys_sem_t or sys_mbox_t are represented internally. Since lwIP 1.4.0, semaphore and mailbox functions are prototyped in a way that allows both using pointers or actual OS structures to be used. This way, memory required for such types can be either allocated in place (globally or on the stack) or on the heap (allocated internally in the "*_new()" functions). The following functions must be implemented by the sys_arch: - void sys_init(void) Is called to initialize the sys_arch layer. - err_t sys_sem_new(sys_sem_t *sem, u8_t count) Creates a new semaphore. The semaphore is allocated to the memory that 'sem' points to (which can be both a pointer or the actual OS structure). The "count" argument specifies the initial state of the semaphore (which is either 0 or 1). If the semaphore has been created, ERR_OK should be returned. Returning any other error will provide a hint what went wrong, but except for assertions, no real error handling is implemented. - void sys_sem_free(sys_sem_t *sem) Deallocates a semaphore. - void sys_sem_signal(sys_sem_t *sem) Signals a semaphore. - u32_t sys_arch_sem_wait(sys_sem_t *sem, u32_t timeout) Blocks the thread while waiting for the semaphore to be signaled. If the "timeout" argument is non-zero, the thread should only be blocked for the specified time (measured in milliseconds). If the "timeout" argument is zero, the thread should be blocked until the semaphore is signalled. If the timeout argument is non-zero, the return value is the number of milliseconds spent waiting for the semaphore to be signaled. If the semaphore wasn't signaled within the specified time, the return value is SYS_ARCH_TIMEOUT. If the thread didn't have to wait for the semaphore (i.e., it was already signaled), the function may return zero. Notice that lwIP implements a function with a similar name, sys_sem_wait(), that uses the sys_arch_sem_wait() function. - int sys_sem_valid(sys_sem_t *sem) Returns 1 if the semaphore is valid, 0 if it is not valid. When using pointers, a simple way is to check the pointer for != NULL. When directly using OS structures, implementing this may be more complex. This may also be a define, in which case the function is not prototyped. - void sys_sem_set_invalid(sys_sem_t *sem) Invalidate a semaphore so that sys_sem_valid() returns 0. ATTENTION: This does NOT mean that the semaphore shall be deallocated: sys_sem_free() is always called before calling this function! This may also be a define, in which case the function is not prototyped. - err_t sys_mbox_new(sys_mbox_t *mbox, int size) Creates an empty mailbox for maximum "size" elements. Elements stored in mailboxes are pointers. You have to define macros "_MBOX_SIZE" in your lwipopts.h, or ignore this parameter in your implementation and use a default size. If the mailbox has been created, ERR_OK should be returned. Returning any other error will provide a hint what went wrong, but except for assertions, no real error handling is implemented. - void sys_mbox_free(sys_mbox_t *mbox) Deallocates a mailbox. If there are messages still present in the mailbox when the mailbox is deallocated, it is an indication of a programming error in lwIP and the developer should be notified. - void sys_mbox_post(sys_mbox_t *mbox, void *msg) Posts the "msg" to the mailbox. This function have to block until the "msg" is really posted. - err_t sys_mbox_trypost(sys_mbox_t *mbox, void *msg) Try to post the "msg" to the mailbox. Returns ERR_MEM if this one is full, else, ERR_OK if the "msg" is posted. - u32_t sys_arch_mbox_fetch(sys_mbox_t *mbox, void **msg, u32_t timeout) Blocks the thread until a message arrives in the mailbox, but does not block the thread longer than "timeout" milliseconds (similar to the sys_arch_sem_wait() function). If "timeout" is 0, the thread should be blocked until a message arrives. The "msg" argument is a result parameter that is set by the function (i.e., by doing "*msg = ptr"). The "msg" parameter maybe NULL to indicate that the message should be dropped. The return values are the same as for the sys_arch_sem_wait() function: Number of milliseconds spent waiting or SYS_ARCH_TIMEOUT if there was a timeout. Note that a function with a similar name, sys_mbox_fetch(), is implemented by lwIP. - u32_t sys_arch_mbox_tryfetch(sys_mbox_t *mbox, void **msg) This is similar to sys_arch_mbox_fetch, however if a message is not present in the mailbox, it immediately returns with the code SYS_MBOX_EMPTY. On success 0 is returned. To allow for efficient implementations, this can be defined as a function-like macro in sys_arch.h instead of a normal function. For example, a naive implementation could be: #define sys_arch_mbox_tryfetch(mbox,msg) \ sys_arch_mbox_fetch(mbox,msg,1) although this would introduce unnecessary delays. - int sys_mbox_valid(sys_mbox_t *mbox) Returns 1 if the mailbox is valid, 0 if it is not valid. When using pointers, a simple way is to check the pointer for != NULL. When directly using OS structures, implementing this may be more complex. This may also be a define, in which case the function is not prototyped. - void sys_mbox_set_invalid(sys_mbox_t *mbox) Invalidate a mailbox so that sys_mbox_valid() returns 0. ATTENTION: This does NOT mean that the mailbox shall be deallocated: sys_mbox_free() is always called before calling this function! This may also be a define, in which case the function is not prototyped. If threads are supported by the underlying operating system and if such functionality is needed in lwIP, the following function will have to be implemented as well: - sys_thread_t sys_thread_new(char *name, void (* thread)(void *arg), void *arg, int stacksize, int prio) Starts a new thread named "name" with priority "prio" that will begin its execution in the function "thread()". The "arg" argument will be passed as an argument to the thread() function. The stack size to used for this thread is the "stacksize" parameter. The id of the new thread is returned. Both the id and the priority are system dependent. - sys_prot_t sys_arch_protect(void) This optional function does a "fast" critical region protection and returns the previous protection level. This function is only called during very short critical regions. An embedded system which supports ISR-based drivers might want to implement this function by disabling interrupts. Task-based systems might want to implement this by using a mutex or disabling tasking. This function should support recursive calls from the same task or interrupt. In other words, sys_arch_protect() could be called while already protected. In that case the return value indicates that it is already protected. sys_arch_protect() is only required if your port is supporting an operating system. - void sys_arch_unprotect(sys_prot_t pval) This optional function does a "fast" set of critical region protection to the value specified by pval. See the documentation for sys_arch_protect() for more information. This function is only required if your port is supporting an operating system. For some configurations, you also need: - u32_t sys_now(void) This optional function returns the current time in milliseconds (don't care for wraparound, this is only used for time diffs). Not implementing this function means you cannot use some modules (e.g. TCP timestamps, internal timeouts for NO_SYS==1). Note: Be carefull with using mem_malloc() in sys_arch. When malloc() refers to mem_malloc() you can run into a circular function call problem. In mem.c mem_init() tries to allcate a semaphore using mem_malloc, which of course can't be performed when sys_arch uses mem_malloc. ------------------------------------------------------------------------------- Additional files required for the "OS support" emulation layer: ------------------------------------------------------------------------------- cc.h - Architecture environment, some compiler specific, some environment specific (probably should move env stuff to sys_arch.h.) Typedefs for the types used by lwip - u8_t, s8_t, u16_t, s16_t, u32_t, s32_t, mem_ptr_t Compiler hints for packing lwip's structures - PACK_STRUCT_FIELD(x) PACK_STRUCT_STRUCT PACK_STRUCT_BEGIN PACK_STRUCT_END Platform specific diagnostic output - LWIP_PLATFORM_DIAG(x) - non-fatal, print a message. LWIP_PLATFORM_ASSERT(x) - fatal, print message and abandon execution. Portability defines for printf formatters: U16_F, S16_F, X16_F, U32_F, S32_F, X32_F, SZT_F "lightweight" synchronization mechanisms - SYS_ARCH_DECL_PROTECT(x) - declare a protection state variable. SYS_ARCH_PROTECT(x) - enter protection mode. SYS_ARCH_UNPROTECT(x) - leave protection mode. If the compiler does not provide memset() this file must include a definition of it, or include a file which defines it. This file must either include a system-local which defines the standard *nix error codes, or it should #define LWIP_PROVIDE_ERRNO to make lwip/arch.h define the codes which are used throughout. perf.h - Architecture specific performance measurement. Measurement calls made throughout lwip, these can be defined to nothing. PERF_START - start measuring something. PERF_STOP(x) - stop measuring something, and record the result. sys_arch.h - Tied to sys_arch.c Arch dependent types for the following objects: sys_sem_t, sys_mbox_t, sys_thread_t, And, optionally: sys_prot_t Defines to set vars of sys_mbox_t and sys_sem_t to NULL. SYS_MBOX_NULL NULL SYS_SEM_NULL NULL ocproxy-1.60/lwip/src/000077500000000000000000000000001303453231400147035ustar00rootroot00000000000000ocproxy-1.60/lwip/src/FILES000066400000000000000000000007561303453231400155000ustar00rootroot00000000000000api/ - The code for the high-level wrapper API. Not needed if you use the lowel-level call-back/raw API. core/ - The core of the TPC/IP stack; protocol implementations, memory and buffer management, and the low-level raw API. include/ - lwIP include files. netif/ - Generic network interface device drivers are kept here, as well as the ARP module. For more information on the various subdirectories, check the FILES file in each directory. ocproxy-1.60/lwip/src/api/000077500000000000000000000000001303453231400154545ustar00rootroot00000000000000ocproxy-1.60/lwip/src/api/api_lib.c000066400000000000000000000667661303453231400172440ustar00rootroot00000000000000/** * @file * Sequential API External module * */ /* * Copyright (c) 2001-2004 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ /* This is the part of the API that is linked with the application */ #include "lwip/opt.h" #if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */ #include "lwip/api.h" #include "lwip/tcpip.h" #include "lwip/memp.h" #include "lwip/ip.h" #include "lwip/raw.h" #include "lwip/udp.h" #include "lwip/tcp.h" #include #define API_MSG_VAR_REF(name) API_VAR_REF(name) #define API_MSG_VAR_DECLARE(name) API_VAR_DECLARE(struct api_msg, name) #define API_MSG_VAR_ALLOC(name) API_VAR_ALLOC(struct api_msg, MEMP_API_MSG, name) #define API_MSG_VAR_ALLOC_DONTFAIL(name) API_VAR_ALLOC_DONTFAIL(struct api_msg, MEMP_API_MSG, name) #define API_MSG_VAR_FREE(name) API_VAR_FREE(MEMP_API_MSG, name) /** * Create a new netconn (of a specific type) that has a callback function. * The corresponding pcb is also created. * * @param t the type of 'connection' to create (@see enum netconn_type) * @param proto the IP protocol for RAW IP pcbs * @param callback a function to call on status changes (RX available, TX'ed) * @return a newly allocated struct netconn or * NULL on memory error */ struct netconn* netconn_new_with_proto_and_callback(enum netconn_type t, u8_t proto, netconn_callback callback) { struct netconn *conn; API_MSG_VAR_DECLARE(msg); conn = netconn_alloc(t, callback); if (conn != NULL) { err_t err; API_MSG_VAR_ALLOC_DONTFAIL(msg); API_MSG_VAR_REF(msg).msg.msg.n.proto = proto; API_MSG_VAR_REF(msg).msg.conn = conn; TCPIP_APIMSG(&API_MSG_VAR_REF(msg), lwip_netconn_do_newconn, err); API_MSG_VAR_FREE(msg); if (err != ERR_OK) { LWIP_ASSERT("freeing conn without freeing pcb", conn->pcb.tcp == NULL); LWIP_ASSERT("conn has no op_completed", sys_sem_valid(&conn->op_completed)); LWIP_ASSERT("conn has no recvmbox", sys_mbox_valid(&conn->recvmbox)); #if LWIP_TCP LWIP_ASSERT("conn->acceptmbox shouldn't exist", !sys_mbox_valid(&conn->acceptmbox)); #endif /* LWIP_TCP */ sys_sem_free(&conn->op_completed); sys_mbox_free(&conn->recvmbox); memp_free(MEMP_NETCONN, conn); return NULL; } } return conn; } /** * Close a netconn 'connection' and free its resources. * UDP and RAW connection are completely closed, TCP pcbs might still be in a waitstate * after this returns. * * @param conn the netconn to delete * @return ERR_OK if the connection was deleted */ err_t netconn_delete(struct netconn *conn) { API_MSG_VAR_DECLARE(msg); /* No ASSERT here because possible to get a (conn == NULL) if we got an accept error */ if (conn == NULL) { return ERR_OK; } API_MSG_VAR_ALLOC(msg); API_MSG_VAR_REF(msg).function = lwip_netconn_do_delconn; API_MSG_VAR_REF(msg).msg.conn = conn; tcpip_apimsg(&API_MSG_VAR_REF(msg)); API_MSG_VAR_FREE(msg); netconn_free(conn); /* don't care for return value of lwip_netconn_do_delconn since it only calls void functions */ return ERR_OK; } /** * Get the local or remote IP address and port of a netconn. * For RAW netconns, this returns the protocol instead of a port! * * @param conn the netconn to query * @param addr a pointer to which to save the IP address * @param port a pointer to which to save the port (or protocol for RAW) * @param local 1 to get the local IP address, 0 to get the remote one * @return ERR_CONN for invalid connections * ERR_OK if the information was retrieved */ err_t netconn_getaddr(struct netconn *conn, ip_addr_t *addr, u16_t *port, u8_t local) { API_MSG_VAR_DECLARE(msg); err_t err; LWIP_ERROR("netconn_getaddr: invalid conn", (conn != NULL), return ERR_ARG;); LWIP_ERROR("netconn_getaddr: invalid addr", (addr != NULL), return ERR_ARG;); LWIP_ERROR("netconn_getaddr: invalid port", (port != NULL), return ERR_ARG;); API_MSG_VAR_ALLOC(msg); API_MSG_VAR_REF(msg).msg.conn = conn; API_MSG_VAR_REF(msg).msg.msg.ad.local = local; #if LWIP_MPU_COMPATIBLE TCPIP_APIMSG(msg, lwip_netconn_do_getaddr, err); *addr = *ipX_2_ip(&(msg->msg.msg.ad.ipaddr)); *port = msg->msg.msg.ad.port; #else /* LWIP_MPU_COMPATIBLE */ msg.msg.msg.ad.ipaddr = ip_2_ipX(addr); msg.msg.msg.ad.port = port; TCPIP_APIMSG(&msg, lwip_netconn_do_getaddr, err); #endif /* LWIP_MPU_COMPATIBLE */ API_MSG_VAR_FREE(msg); NETCONN_SET_SAFE_ERR(conn, err); return err; } /** * Bind a netconn to a specific local IP address and port. * Binding one netconn twice might not always be checked correctly! * * @param conn the netconn to bind * @param addr the local IP address to bind the netconn to (use IP_ADDR_ANY * to bind to all addresses) * @param port the local port to bind the netconn to (not used for RAW) * @return ERR_OK if bound, any other err_t on failure */ err_t netconn_bind(struct netconn *conn, ip_addr_t *addr, u16_t port) { API_MSG_VAR_DECLARE(msg); err_t err; LWIP_ERROR("netconn_bind: invalid conn", (conn != NULL), return ERR_ARG;); API_MSG_VAR_ALLOC(msg); #if LWIP_MPU_COMPATIBLE if (addr == NULL) { addr = IP_ADDR_ANY; } #endif /* LWIP_MPU_COMPATIBLE */ API_MSG_VAR_REF(msg).msg.conn = conn; API_MSG_VAR_REF(msg).msg.msg.bc.ipaddr = API_MSG_VAR_REF(addr); API_MSG_VAR_REF(msg).msg.msg.bc.port = port; TCPIP_APIMSG(&API_MSG_VAR_REF(msg), lwip_netconn_do_bind, err); API_MSG_VAR_FREE(msg); NETCONN_SET_SAFE_ERR(conn, err); return err; } /** * Connect a netconn to a specific remote IP address and port. * * @param conn the netconn to connect * @param addr the remote IP address to connect to * @param port the remote port to connect to (no used for RAW) * @return ERR_OK if connected, return value of tcp_/udp_/raw_connect otherwise */ err_t netconn_connect(struct netconn *conn, ip_addr_t *addr, u16_t port) { API_MSG_VAR_DECLARE(msg); err_t err; LWIP_ERROR("netconn_connect: invalid conn", (conn != NULL), return ERR_ARG;); API_MSG_VAR_ALLOC(msg); #if LWIP_MPU_COMPATIBLE if (addr == NULL) { addr = IP_ADDR_ANY; } #endif /* LWIP_MPU_COMPATIBLE */ API_MSG_VAR_REF(msg).msg.conn = conn; API_MSG_VAR_REF(msg).msg.msg.bc.ipaddr = API_MSG_VAR_REF(addr); API_MSG_VAR_REF(msg).msg.msg.bc.port = port; #if LWIP_TCP #if (LWIP_UDP || LWIP_RAW) if (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP) #endif /* (LWIP_UDP || LWIP_RAW) */ { /* The TCP version waits for the connect to succeed, so always needs to use message passing. */ API_MSG_VAR_REF(msg).function = lwip_netconn_do_connect; err = tcpip_apimsg(&API_MSG_VAR_REF(msg)); } #endif /* LWIP_TCP */ #if (LWIP_UDP || LWIP_RAW) && LWIP_TCP else #endif /* (LWIP_UDP || LWIP_RAW) && LWIP_TCP */ #if (LWIP_UDP || LWIP_RAW) { /* UDP and RAW only set flags, so we can use core-locking. */ TCPIP_APIMSG(&API_MSG_VAR_REF(msg), lwip_netconn_do_connect, err); } #endif /* (LWIP_UDP || LWIP_RAW) */ API_MSG_VAR_FREE(msg); NETCONN_SET_SAFE_ERR(conn, err); return err; } /** * Disconnect a netconn from its current peer (only valid for UDP netconns). * * @param conn the netconn to disconnect * @return TODO: return value is not set here... */ err_t netconn_disconnect(struct netconn *conn) { API_MSG_VAR_DECLARE(msg); err_t err; LWIP_ERROR("netconn_disconnect: invalid conn", (conn != NULL), return ERR_ARG;); API_MSG_VAR_ALLOC(msg); API_MSG_VAR_REF(msg).msg.conn = conn; TCPIP_APIMSG(&API_MSG_VAR_REF(msg), lwip_netconn_do_disconnect, err); API_MSG_VAR_FREE(msg); NETCONN_SET_SAFE_ERR(conn, err); return err; } /** * Set a TCP netconn into listen mode * * @param conn the tcp netconn to set to listen mode * @param backlog the listen backlog, only used if TCP_LISTEN_BACKLOG==1 * @return ERR_OK if the netconn was set to listen (UDP and RAW netconns * don't return any error (yet?)) */ err_t netconn_listen_with_backlog(struct netconn *conn, u8_t backlog) { #if LWIP_TCP API_MSG_VAR_DECLARE(msg); err_t err; /* This does no harm. If TCP_LISTEN_BACKLOG is off, backlog is unused. */ LWIP_UNUSED_ARG(backlog); LWIP_ERROR("netconn_listen: invalid conn", (conn != NULL), return ERR_ARG;); API_MSG_VAR_ALLOC(msg); API_MSG_VAR_REF(msg).msg.conn = conn; #if TCP_LISTEN_BACKLOG API_MSG_VAR_REF(msg).msg.msg.lb.backlog = backlog; #endif /* TCP_LISTEN_BACKLOG */ TCPIP_APIMSG(&API_MSG_VAR_REF(msg), lwip_netconn_do_listen, err); API_MSG_VAR_FREE(msg); NETCONN_SET_SAFE_ERR(conn, err); return err; #else /* LWIP_TCP */ LWIP_UNUSED_ARG(conn); LWIP_UNUSED_ARG(backlog); return ERR_ARG; #endif /* LWIP_TCP */ } /** * Accept a new connection on a TCP listening netconn. * * @param conn the TCP listen netconn * @param new_conn pointer where the new connection is stored * @return ERR_OK if a new connection has been received or an error * code otherwise */ err_t netconn_accept(struct netconn *conn, struct netconn **new_conn) { #if LWIP_TCP struct netconn *newconn; err_t err; #if TCP_LISTEN_BACKLOG API_MSG_VAR_DECLARE(msg); #endif /* TCP_LISTEN_BACKLOG */ LWIP_ERROR("netconn_accept: invalid pointer", (new_conn != NULL), return ERR_ARG;); *new_conn = NULL; LWIP_ERROR("netconn_accept: invalid conn", (conn != NULL), return ERR_ARG;); LWIP_ERROR("netconn_accept: invalid acceptmbox", sys_mbox_valid(&conn->acceptmbox), return ERR_ARG;); err = conn->last_err; if (ERR_IS_FATAL(err)) { /* don't recv on fatal errors: this might block the application task waiting on acceptmbox forever! */ return err; } #if LWIP_SO_RCVTIMEO if (sys_arch_mbox_fetch(&conn->acceptmbox, (void **)&newconn, conn->recv_timeout) == SYS_ARCH_TIMEOUT) { NETCONN_SET_SAFE_ERR(conn, ERR_TIMEOUT); return ERR_TIMEOUT; } #else sys_arch_mbox_fetch(&conn->acceptmbox, (void **)&newconn, 0); #endif /* LWIP_SO_RCVTIMEO*/ /* Register event with callback */ API_EVENT(conn, NETCONN_EVT_RCVMINUS, 0); if (newconn == NULL) { /* connection has been aborted */ NETCONN_SET_SAFE_ERR(conn, ERR_ABRT); return ERR_ABRT; } #if TCP_LISTEN_BACKLOG /* Let the stack know that we have accepted the connection. */ API_MSG_VAR_ALLOC_DONTFAIL(msg); API_MSG_VAR_REF(msg).msg.conn = conn; /* don't care for the return value of lwip_netconn_do_recv */ TCPIP_APIMSG_NOERR(&API_MSG_VAR_REF(msg), lwip_netconn_do_recv); API_MSG_VAR_FREE(msg); #endif /* TCP_LISTEN_BACKLOG */ *new_conn = newconn; /* don't set conn->last_err: it's only ERR_OK, anyway */ return ERR_OK; #else /* LWIP_TCP */ LWIP_UNUSED_ARG(conn); LWIP_UNUSED_ARG(new_conn); return ERR_ARG; #endif /* LWIP_TCP */ } /** * Receive data: actual implementation that doesn't care whether pbuf or netbuf * is received * * @param conn the netconn from which to receive data * @param new_buf pointer where a new pbuf/netbuf is stored when received data * @return ERR_OK if data has been received, an error code otherwise (timeout, * memory error or another error) */ static err_t netconn_recv_data(struct netconn *conn, void **new_buf) { void *buf = NULL; u16_t len; err_t err; #if LWIP_TCP API_MSG_VAR_DECLARE(msg); #endif /* LWIP_TCP */ LWIP_ERROR("netconn_recv: invalid pointer", (new_buf != NULL), return ERR_ARG;); *new_buf = NULL; LWIP_ERROR("netconn_recv: invalid conn", (conn != NULL), return ERR_ARG;); LWIP_ERROR("netconn_accept: invalid recvmbox", sys_mbox_valid(&conn->recvmbox), return ERR_CONN;); err = conn->last_err; if (ERR_IS_FATAL(err)) { /* don't recv on fatal errors: this might block the application task waiting on recvmbox forever! */ /* @todo: this does not allow us to fetch data that has been put into recvmbox before the fatal error occurred - is that a problem? */ return err; } #if LWIP_SO_RCVTIMEO if (sys_arch_mbox_fetch(&conn->recvmbox, &buf, conn->recv_timeout) == SYS_ARCH_TIMEOUT) { NETCONN_SET_SAFE_ERR(conn, ERR_TIMEOUT); return ERR_TIMEOUT; } #else sys_arch_mbox_fetch(&conn->recvmbox, &buf, 0); #endif /* LWIP_SO_RCVTIMEO*/ #if LWIP_TCP #if (LWIP_UDP || LWIP_RAW) if (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP) #endif /* (LWIP_UDP || LWIP_RAW) */ { if (!netconn_get_noautorecved(conn) || (buf == NULL)) { /* Let the stack know that we have taken the data. */ /* TODO: Speedup: Don't block and wait for the answer here (to prevent multiple thread-switches). */ API_MSG_VAR_ALLOC_DONTFAIL(msg); API_MSG_VAR_REF(msg).msg.conn = conn; if (buf != NULL) { API_MSG_VAR_REF(msg).msg.msg.r.len = ((struct pbuf *)buf)->tot_len; } else { API_MSG_VAR_REF(msg).msg.msg.r.len = 1; } /* don't care for the return value of lwip_netconn_do_recv */ TCPIP_APIMSG_NOERR(&API_MSG_VAR_REF(msg), lwip_netconn_do_recv); API_MSG_VAR_FREE(msg); } /* If we are closed, we indicate that we no longer wish to use the socket */ if (buf == NULL) { API_EVENT(conn, NETCONN_EVT_RCVMINUS, 0); /* Avoid to lose any previous error code */ NETCONN_SET_SAFE_ERR(conn, ERR_CLSD); return ERR_CLSD; } len = ((struct pbuf *)buf)->tot_len; } #endif /* LWIP_TCP */ #if LWIP_TCP && (LWIP_UDP || LWIP_RAW) else #endif /* LWIP_TCP && (LWIP_UDP || LWIP_RAW) */ #if (LWIP_UDP || LWIP_RAW) { LWIP_ASSERT("buf != NULL", buf != NULL); len = netbuf_len((struct netbuf *)buf); } #endif /* (LWIP_UDP || LWIP_RAW) */ #if LWIP_SO_RCVBUF SYS_ARCH_DEC(conn->recv_avail, len); #endif /* LWIP_SO_RCVBUF */ /* Register event with callback */ API_EVENT(conn, NETCONN_EVT_RCVMINUS, len); LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_recv_data: received %p, len=%"U16_F"\n", buf, len)); *new_buf = buf; /* don't set conn->last_err: it's only ERR_OK, anyway */ return ERR_OK; } /** * Receive data (in form of a pbuf) from a TCP netconn * * @param conn the netconn from which to receive data * @param new_buf pointer where a new pbuf is stored when received data * @return ERR_OK if data has been received, an error code otherwise (timeout, * memory error or another error) * ERR_ARG if conn is not a TCP netconn */ err_t netconn_recv_tcp_pbuf(struct netconn *conn, struct pbuf **new_buf) { LWIP_ERROR("netconn_recv: invalid conn", (conn != NULL) && NETCONNTYPE_GROUP(netconn_type(conn)) == NETCONN_TCP, return ERR_ARG;); return netconn_recv_data(conn, (void **)new_buf); } /** * Receive data (in form of a netbuf containing a packet buffer) from a netconn * * @param conn the netconn from which to receive data * @param new_buf pointer where a new netbuf is stored when received data * @return ERR_OK if data has been received, an error code otherwise (timeout, * memory error or another error) */ err_t netconn_recv(struct netconn *conn, struct netbuf **new_buf) { #if LWIP_TCP struct netbuf *buf = NULL; err_t err; #endif /* LWIP_TCP */ LWIP_ERROR("netconn_recv: invalid pointer", (new_buf != NULL), return ERR_ARG;); *new_buf = NULL; LWIP_ERROR("netconn_recv: invalid conn", (conn != NULL), return ERR_ARG;); LWIP_ERROR("netconn_accept: invalid recvmbox", sys_mbox_valid(&conn->recvmbox), return ERR_CONN;); #if LWIP_TCP #if (LWIP_UDP || LWIP_RAW) if (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP) #endif /* (LWIP_UDP || LWIP_RAW) */ { struct pbuf *p = NULL; /* This is not a listening netconn, since recvmbox is set */ buf = (struct netbuf *)memp_malloc(MEMP_NETBUF); if (buf == NULL) { NETCONN_SET_SAFE_ERR(conn, ERR_MEM); return ERR_MEM; } err = netconn_recv_data(conn, (void **)&p); if (err != ERR_OK) { memp_free(MEMP_NETBUF, buf); return err; } LWIP_ASSERT("p != NULL", p != NULL); buf->p = p; buf->ptr = p; buf->port = 0; ipX_addr_set_any(LWIP_IPV6, &buf->addr); *new_buf = buf; /* don't set conn->last_err: it's only ERR_OK, anyway */ return ERR_OK; } #endif /* LWIP_TCP */ #if LWIP_TCP && (LWIP_UDP || LWIP_RAW) else #endif /* LWIP_TCP && (LWIP_UDP || LWIP_RAW) */ { #if (LWIP_UDP || LWIP_RAW) return netconn_recv_data(conn, (void **)new_buf); #endif /* (LWIP_UDP || LWIP_RAW) */ } } /** * TCP: update the receive window: by calling this, the application * tells the stack that it has processed data and is able to accept * new data. * ATTENTION: use with care, this is mainly used for sockets! * Can only be used when calling netconn_set_noautorecved(conn, 1) before. * * @param conn the netconn for which to update the receive window * @param length amount of data processed (ATTENTION: this must be accurate!) */ void netconn_recved(struct netconn *conn, u32_t length) { #if LWIP_TCP if ((conn != NULL) && (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP) && (netconn_get_noautorecved(conn))) { API_MSG_VAR_DECLARE(msg); /* Let the stack know that we have taken the data. */ /* TODO: Speedup: Don't block and wait for the answer here (to prevent multiple thread-switches). */ API_MSG_VAR_ALLOC_DONTFAIL(msg); API_MSG_VAR_REF(msg).msg.conn = conn; API_MSG_VAR_REF(msg).msg.msg.r.len = length; /* don't care for the return value of lwip_netconn_do_recv */ TCPIP_APIMSG_NOERR(&API_MSG_VAR_REF(msg), lwip_netconn_do_recv); API_MSG_VAR_FREE(msg); } #else /* LWIP_TCP */ LWIP_UNUSED_ARG(conn); LWIP_UNUSED_ARG(length); #endif /* LWIP_TCP */ } /** * Send data (in form of a netbuf) to a specific remote IP address and port. * Only to be used for UDP and RAW netconns (not TCP). * * @param conn the netconn over which to send data * @param buf a netbuf containing the data to send * @param addr the remote IP address to which to send the data * @param port the remote port to which to send the data * @return ERR_OK if data was sent, any other err_t on error */ err_t netconn_sendto(struct netconn *conn, struct netbuf *buf, ip_addr_t *addr, u16_t port) { if (buf != NULL) { ipX_addr_set_ipaddr(PCB_ISIPV6(conn->pcb.ip), &buf->addr, addr); buf->port = port; return netconn_send(conn, buf); } return ERR_VAL; } /** * Send data over a UDP or RAW netconn (that is already connected). * * @param conn the UDP or RAW netconn over which to send data * @param buf a netbuf containing the data to send * @return ERR_OK if data was sent, any other err_t on error */ err_t netconn_send(struct netconn *conn, struct netbuf *buf) { API_MSG_VAR_DECLARE(msg); err_t err; LWIP_ERROR("netconn_send: invalid conn", (conn != NULL), return ERR_ARG;); LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_send: sending %"U16_F" bytes\n", buf->p->tot_len)); API_MSG_VAR_ALLOC(msg); API_MSG_VAR_REF(msg).msg.conn = conn; API_MSG_VAR_REF(msg).msg.msg.b = buf; TCPIP_APIMSG(&API_MSG_VAR_REF(msg), lwip_netconn_do_send, err); API_MSG_VAR_FREE(msg); NETCONN_SET_SAFE_ERR(conn, err); return err; } /** * Send data over a TCP netconn. * * @param conn the TCP netconn over which to send data * @param dataptr pointer to the application buffer that contains the data to send * @param size size of the application data to send * @param apiflags combination of following flags : * - NETCONN_COPY: data will be copied into memory belonging to the stack * - NETCONN_MORE: for TCP connection, PSH flag will be set on last segment sent * - NETCONN_DONTBLOCK: only write the data if all dat can be written at once * @param bytes_written pointer to a location that receives the number of written bytes * @return ERR_OK if data was sent, any other err_t on error */ err_t netconn_write_partly(struct netconn *conn, const void *dataptr, size_t size, u8_t apiflags, size_t *bytes_written) { API_MSG_VAR_DECLARE(msg); err_t err; u8_t dontblock; LWIP_ERROR("netconn_write: invalid conn", (conn != NULL), return ERR_ARG;); LWIP_ERROR("netconn_write: invalid conn->type", (NETCONNTYPE_GROUP(conn->type)== NETCONN_TCP), return ERR_VAL;); if (size == 0) { return ERR_OK; } dontblock = netconn_is_nonblocking(conn) || (apiflags & NETCONN_DONTBLOCK); if (dontblock && !bytes_written) { /* This implies netconn_write() cannot be used for non-blocking send, since it has no way to return the number of bytes written. */ return ERR_VAL; } API_MSG_VAR_ALLOC(msg); /* non-blocking write sends as much */ API_MSG_VAR_REF(msg).msg.conn = conn; API_MSG_VAR_REF(msg).msg.msg.w.dataptr = dataptr; API_MSG_VAR_REF(msg).msg.msg.w.apiflags = apiflags; API_MSG_VAR_REF(msg).msg.msg.w.len = size; #if LWIP_SO_SNDTIMEO if (conn->send_timeout != 0) { /* get the time we started, which is later compared to sys_now() + conn->send_timeout */ API_MSG_VAR_REF(msg).msg.msg.w.time_started = sys_now(); } else { API_MSG_VAR_REF(msg).msg.msg.w.time_started = 0; } #endif /* LWIP_SO_SNDTIMEO */ /* For locking the core: this _can_ be delayed on low memory/low send buffer, but if it is, this is done inside api_msg.c:do_write(), so we can use the non-blocking version here. */ TCPIP_APIMSG(&API_MSG_VAR_REF(msg), lwip_netconn_do_write, err); if ((err == ERR_OK) && (bytes_written != NULL)) { if (dontblock #if LWIP_SO_SNDTIMEO || (conn->send_timeout != 0) #endif /* LWIP_SO_SNDTIMEO */ ) { /* nonblocking write: maybe the data has been sent partly */ *bytes_written = API_MSG_VAR_REF(msg).msg.msg.w.len; } else { /* blocking call succeeded: all data has been sent if it */ *bytes_written = size; } } API_MSG_VAR_FREE(msg); NETCONN_SET_SAFE_ERR(conn, err); return err; } /** * Close ot shutdown a TCP netconn (doesn't delete it). * * @param conn the TCP netconn to close or shutdown * @param how fully close or only shutdown one side? * @return ERR_OK if the netconn was closed, any other err_t on error */ static err_t netconn_close_shutdown(struct netconn *conn, u8_t how) { API_MSG_VAR_DECLARE(msg); err_t err; LWIP_ERROR("netconn_close: invalid conn", (conn != NULL), return ERR_ARG;); API_MSG_VAR_ALLOC(msg); API_MSG_VAR_REF(msg).function = lwip_netconn_do_close; API_MSG_VAR_REF(msg).msg.conn = conn; /* shutting down both ends is the same as closing */ API_MSG_VAR_REF(msg).msg.msg.sd.shut = how; /* because of the LWIP_TCPIP_CORE_LOCKING implementation of lwip_netconn_do_close, don't use TCPIP_APIMSG here */ err = tcpip_apimsg(&API_MSG_VAR_REF(msg)); API_MSG_VAR_FREE(msg); NETCONN_SET_SAFE_ERR(conn, err); return err; } /** * Close a TCP netconn (doesn't delete it). * * @param conn the TCP netconn to close * @return ERR_OK if the netconn was closed, any other err_t on error */ err_t netconn_close(struct netconn *conn) { /* shutting down both ends is the same as closing */ return netconn_close_shutdown(conn, NETCONN_SHUT_RDWR); } /** * Shut down one or both sides of a TCP netconn (doesn't delete it). * * @param conn the TCP netconn to shut down * @return ERR_OK if the netconn was closed, any other err_t on error */ err_t netconn_shutdown(struct netconn *conn, u8_t shut_rx, u8_t shut_tx) { return netconn_close_shutdown(conn, (shut_rx ? NETCONN_SHUT_RD : 0) | (shut_tx ? NETCONN_SHUT_WR : 0)); } #if LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) /** * Join multicast groups for UDP netconns. * * @param conn the UDP netconn for which to change multicast addresses * @param multiaddr IP address of the multicast group to join or leave * @param netif_addr the IP address of the network interface on which to send * the igmp message * @param join_or_leave flag whether to send a join- or leave-message * @return ERR_OK if the action was taken, any err_t on error */ err_t netconn_join_leave_group(struct netconn *conn, ip_addr_t *multiaddr, ip_addr_t *netif_addr, enum netconn_igmp join_or_leave) { API_MSG_VAR_DECLARE(msg); err_t err; LWIP_ERROR("netconn_join_leave_group: invalid conn", (conn != NULL), return ERR_ARG;); API_MSG_VAR_ALLOC(msg); #if LWIP_MPU_COMPATIBLE if (multiaddr == NULL) { multiaddr = IP_ADDR_ANY; } if (netif_addr == NULL) { netif_addr = IP_ADDR_ANY; } #endif /* LWIP_MPU_COMPATIBLE */ API_MSG_VAR_REF(msg).msg.conn = conn; API_MSG_VAR_REF(msg).msg.msg.jl.multiaddr = API_MSG_VAR_REF(ip_2_ipX(multiaddr)); API_MSG_VAR_REF(msg).msg.msg.jl.netif_addr = API_MSG_VAR_REF(ip_2_ipX(netif_addr)); API_MSG_VAR_REF(msg).msg.msg.jl.join_or_leave = join_or_leave; TCPIP_APIMSG(&API_MSG_VAR_REF(msg), lwip_netconn_do_join_leave_group, err); API_MSG_VAR_FREE(msg); NETCONN_SET_SAFE_ERR(conn, err); return err; } #endif /* LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) */ #if LWIP_DNS /** * Execute a DNS query, only one IP address is returned * * @param name a string representation of the DNS host name to query * @param addr a preallocated ip_addr_t where to store the resolved IP address * @return ERR_OK: resolving succeeded * ERR_MEM: memory error, try again later * ERR_ARG: dns client not initialized or invalid hostname * ERR_VAL: dns server response was invalid */ err_t netconn_gethostbyname(const char *name, ip_addr_t *addr) { API_VAR_DECLARE(struct dns_api_msg, msg); #if !LWIP_MPU_COMPATIBLE sys_sem_t sem; #endif /* LWIP_MPU_COMPATIBLE */ err_t err; LWIP_ERROR("netconn_gethostbyname: invalid name", (name != NULL), return ERR_ARG;); LWIP_ERROR("netconn_gethostbyname: invalid addr", (addr != NULL), return ERR_ARG;); API_VAR_ALLOC(struct dns_api_msg, MEMP_DNS_API_MSG, msg); #if LWIP_MPU_COMPATIBLE strncpy(API_VAR_REF(msg).name, name, DNS_MAX_NAME_LENGTH-1); API_VAR_REF(msg).name[DNS_MAX_NAME_LENGTH-1] = 0; #else /* LWIP_MPU_COMPATIBLE */ msg.err = &err; msg.sem = &sem; API_VAR_REF(msg).addr = API_VAR_REF(addr); API_VAR_REF(msg).name = name; #endif /* LWIP_MPU_COMPATIBLE */ err = sys_sem_new(API_EXPR_REF(API_VAR_REF(msg).sem), 0); if (err != ERR_OK) { API_VAR_FREE(MEMP_DNS_API_MSG, msg); return err; } tcpip_callback(lwip_netconn_do_gethostbyname, &API_VAR_REF(msg)); sys_sem_wait(API_EXPR_REF(API_VAR_REF(msg).sem)); sys_sem_free(API_EXPR_REF(API_VAR_REF(msg).sem)); #if LWIP_MPU_COMPATIBLE *addr = msg->addr; err = msg->err; #endif /* LWIP_MPU_COMPATIBLE */ API_VAR_FREE(MEMP_DNS_API_MSG, msg); return err; } #endif /* LWIP_DNS*/ #endif /* LWIP_NETCONN */ ocproxy-1.60/lwip/src/api/api_msg.c000066400000000000000000001404271303453231400172470ustar00rootroot00000000000000/** * @file * Sequential API Internal module * */ /* * Copyright (c) 2001-2004 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #include "lwip/opt.h" #if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */ #include "lwip/api_msg.h" #include "lwip/ip.h" #include "lwip/udp.h" #include "lwip/tcp.h" #include "lwip/raw.h" #include "lwip/memp.h" #include "lwip/tcpip.h" #include "lwip/igmp.h" #include "lwip/dns.h" #include "lwip/mld6.h" #include #define SET_NONBLOCKING_CONNECT(conn, val) do { if(val) { \ (conn)->flags |= NETCONN_FLAG_IN_NONBLOCKING_CONNECT; \ } else { \ (conn)->flags &= ~ NETCONN_FLAG_IN_NONBLOCKING_CONNECT; }} while(0) #define IN_NONBLOCKING_CONNECT(conn) (((conn)->flags & NETCONN_FLAG_IN_NONBLOCKING_CONNECT) != 0) /* forward declarations */ #if LWIP_TCP static err_t lwip_netconn_do_writemore(struct netconn *conn); static void lwip_netconn_do_close_internal(struct netconn *conn); #endif #if LWIP_RAW /** * Receive callback function for RAW netconns. * Doesn't 'eat' the packet, only references it and sends it to * conn->recvmbox * * @see raw.h (struct raw_pcb.recv) for parameters and return value */ static u8_t recv_raw(void *arg, struct raw_pcb *pcb, struct pbuf *p, ip_addr_t *addr) { struct pbuf *q; struct netbuf *buf; struct netconn *conn; LWIP_UNUSED_ARG(addr); conn = (struct netconn *)arg; if ((conn != NULL) && sys_mbox_valid(&conn->recvmbox)) { #if LWIP_SO_RCVBUF int recv_avail; SYS_ARCH_GET(conn->recv_avail, recv_avail); if ((recv_avail + (int)(p->tot_len)) > conn->recv_bufsize) { return 0; } #endif /* LWIP_SO_RCVBUF */ /* copy the whole packet into new pbufs */ q = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM); if(q != NULL) { if (pbuf_copy(q, p) != ERR_OK) { pbuf_free(q); q = NULL; } } if (q != NULL) { u16_t len; buf = (struct netbuf *)memp_malloc(MEMP_NETBUF); if (buf == NULL) { pbuf_free(q); return 0; } buf->p = q; buf->ptr = q; ipX_addr_copy(PCB_ISIPV6(pcb), buf->addr, *ipX_current_src_addr()); buf->port = pcb->protocol; len = q->tot_len; if (sys_mbox_trypost(&conn->recvmbox, buf) != ERR_OK) { netbuf_delete(buf); return 0; } else { #if LWIP_SO_RCVBUF SYS_ARCH_INC(conn->recv_avail, len); #endif /* LWIP_SO_RCVBUF */ /* Register event with callback */ API_EVENT(conn, NETCONN_EVT_RCVPLUS, len); } } } return 0; /* do not eat the packet */ } #endif /* LWIP_RAW*/ #if LWIP_UDP /** * Receive callback function for UDP netconns. * Posts the packet to conn->recvmbox or deletes it on memory error. * * @see udp.h (struct udp_pcb.recv) for parameters */ static void recv_udp(void *arg, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port) { struct netbuf *buf; struct netconn *conn; u16_t len; #if LWIP_SO_RCVBUF int recv_avail; #endif /* LWIP_SO_RCVBUF */ LWIP_UNUSED_ARG(pcb); /* only used for asserts... */ LWIP_ASSERT("recv_udp must have a pcb argument", pcb != NULL); LWIP_ASSERT("recv_udp must have an argument", arg != NULL); conn = (struct netconn *)arg; LWIP_ASSERT("recv_udp: recv for wrong pcb!", conn->pcb.udp == pcb); #if LWIP_SO_RCVBUF SYS_ARCH_GET(conn->recv_avail, recv_avail); if ((conn == NULL) || !sys_mbox_valid(&conn->recvmbox) || ((recv_avail + (int)(p->tot_len)) > conn->recv_bufsize)) { #else /* LWIP_SO_RCVBUF */ if ((conn == NULL) || !sys_mbox_valid(&conn->recvmbox)) { #endif /* LWIP_SO_RCVBUF */ pbuf_free(p); return; } buf = (struct netbuf *)memp_malloc(MEMP_NETBUF); if (buf == NULL) { pbuf_free(p); return; } else { buf->p = p; buf->ptr = p; ipX_addr_set_ipaddr(ip_current_is_v6(), &buf->addr, addr); buf->port = port; #if LWIP_NETBUF_RECVINFO { /* get the UDP header - always in the first pbuf, ensured by udp_input */ const struct udp_hdr* udphdr = ipX_next_header_ptr(); #if LWIP_CHECKSUM_ON_COPY buf->flags = NETBUF_FLAG_DESTADDR; #endif /* LWIP_CHECKSUM_ON_COPY */ ipX_addr_set(ip_current_is_v6(), &buf->toaddr, ipX_current_dest_addr()); buf->toport_chksum = udphdr->dest; } #endif /* LWIP_NETBUF_RECVINFO */ } len = p->tot_len; if (sys_mbox_trypost(&conn->recvmbox, buf) != ERR_OK) { netbuf_delete(buf); return; } else { #if LWIP_SO_RCVBUF SYS_ARCH_INC(conn->recv_avail, len); #endif /* LWIP_SO_RCVBUF */ /* Register event with callback */ API_EVENT(conn, NETCONN_EVT_RCVPLUS, len); } } #endif /* LWIP_UDP */ #if LWIP_TCP /** * Receive callback function for TCP netconns. * Posts the packet to conn->recvmbox, but doesn't delete it on errors. * * @see tcp.h (struct tcp_pcb.recv) for parameters and return value */ static err_t recv_tcp(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err) { struct netconn *conn; u16_t len; LWIP_UNUSED_ARG(pcb); LWIP_ASSERT("recv_tcp must have a pcb argument", pcb != NULL); LWIP_ASSERT("recv_tcp must have an argument", arg != NULL); conn = (struct netconn *)arg; if (conn == NULL) { return ERR_VAL; } LWIP_ASSERT("recv_tcp: recv for wrong pcb!", conn->pcb.tcp == pcb); if (!sys_mbox_valid(&conn->recvmbox)) { /* recvmbox already deleted */ if (p != NULL) { tcp_recved(pcb, p->tot_len); pbuf_free(p); } return ERR_OK; } /* Unlike for UDP or RAW pcbs, don't check for available space using recv_avail since that could break the connection (data is already ACKed) */ /* don't overwrite fatal errors! */ NETCONN_SET_SAFE_ERR(conn, err); if (p != NULL) { len = p->tot_len; } else { len = 0; } if (sys_mbox_trypost(&conn->recvmbox, p) != ERR_OK) { /* don't deallocate p: it is presented to us later again from tcp_fasttmr! */ return ERR_MEM; } else { #if LWIP_SO_RCVBUF SYS_ARCH_INC(conn->recv_avail, len); #endif /* LWIP_SO_RCVBUF */ /* Register event with callback */ API_EVENT(conn, NETCONN_EVT_RCVPLUS, len); } return ERR_OK; } /** * Poll callback function for TCP netconns. * Wakes up an application thread that waits for a connection to close * or data to be sent. The application thread then takes the * appropriate action to go on. * * Signals the conn->sem. * netconn_close waits for conn->sem if closing failed. * * @see tcp.h (struct tcp_pcb.poll) for parameters and return value */ static err_t poll_tcp(void *arg, struct tcp_pcb *pcb) { struct netconn *conn = (struct netconn *)arg; LWIP_UNUSED_ARG(pcb); LWIP_ASSERT("conn != NULL", (conn != NULL)); if (conn->state == NETCONN_WRITE) { lwip_netconn_do_writemore(conn); } else if (conn->state == NETCONN_CLOSE) { lwip_netconn_do_close_internal(conn); } /* @todo: implement connect timeout here? */ /* Did a nonblocking write fail before? Then check available write-space. */ if (conn->flags & NETCONN_FLAG_CHECK_WRITESPACE) { /* If the queued byte- or pbuf-count drops below the configured low-water limit, let select mark this pcb as writable again. */ if ((conn->pcb.tcp != NULL) && (tcp_sndbuf(conn->pcb.tcp) > TCP_SNDLOWAT) && (tcp_sndqueuelen(conn->pcb.tcp) < TCP_SNDQUEUELOWAT)) { conn->flags &= ~NETCONN_FLAG_CHECK_WRITESPACE; API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0); } } return ERR_OK; } /** * Sent callback function for TCP netconns. * Signals the conn->sem and calls API_EVENT. * netconn_write waits for conn->sem if send buffer is low. * * @see tcp.h (struct tcp_pcb.sent) for parameters and return value */ static err_t sent_tcp(void *arg, struct tcp_pcb *pcb, u16_t len) { struct netconn *conn = (struct netconn *)arg; LWIP_UNUSED_ARG(pcb); LWIP_ASSERT("conn != NULL", (conn != NULL)); if (conn->state == NETCONN_WRITE) { lwip_netconn_do_writemore(conn); } else if (conn->state == NETCONN_CLOSE) { lwip_netconn_do_close_internal(conn); } if (conn) { /* If the queued byte- or pbuf-count drops below the configured low-water limit, let select mark this pcb as writable again. */ if ((conn->pcb.tcp != NULL) && (tcp_sndbuf(conn->pcb.tcp) > TCP_SNDLOWAT) && (tcp_sndqueuelen(conn->pcb.tcp) < TCP_SNDQUEUELOWAT)) { conn->flags &= ~NETCONN_FLAG_CHECK_WRITESPACE; API_EVENT(conn, NETCONN_EVT_SENDPLUS, len); } } return ERR_OK; } /** * Error callback function for TCP netconns. * Signals conn->sem, posts to all conn mboxes and calls API_EVENT. * The application thread has then to decide what to do. * * @see tcp.h (struct tcp_pcb.err) for parameters */ static void err_tcp(void *arg, err_t err) { struct netconn *conn; enum netconn_state old_state; SYS_ARCH_DECL_PROTECT(lev); conn = (struct netconn *)arg; LWIP_ASSERT("conn != NULL", (conn != NULL)); conn->pcb.tcp = NULL; /* no check since this is always fatal! */ SYS_ARCH_PROTECT(lev); conn->last_err = err; SYS_ARCH_UNPROTECT(lev); /* reset conn->state now before waking up other threads */ old_state = conn->state; conn->state = NETCONN_NONE; /* Notify the user layer about a connection error. Used to signal select. */ API_EVENT(conn, NETCONN_EVT_ERROR, 0); /* Try to release selects pending on 'read' or 'write', too. They will get an error if they actually try to read or write. */ API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0); API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0); /* pass NULL-message to recvmbox to wake up pending recv */ if (sys_mbox_valid(&conn->recvmbox)) { /* use trypost to prevent deadlock */ sys_mbox_trypost(&conn->recvmbox, NULL); } /* pass NULL-message to acceptmbox to wake up pending accept */ if (sys_mbox_valid(&conn->acceptmbox)) { /* use trypost to preven deadlock */ sys_mbox_trypost(&conn->acceptmbox, NULL); } if ((old_state == NETCONN_WRITE) || (old_state == NETCONN_CLOSE) || (old_state == NETCONN_CONNECT)) { /* calling lwip_netconn_do_writemore/lwip_netconn_do_close_internal is not necessary since the pcb has already been deleted! */ int was_nonblocking_connect = IN_NONBLOCKING_CONNECT(conn); SET_NONBLOCKING_CONNECT(conn, 0); if (!was_nonblocking_connect) { /* set error return code */ LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL); conn->current_msg->err = err; conn->current_msg = NULL; /* wake up the waiting task */ sys_sem_signal(&conn->op_completed); } } else { LWIP_ASSERT("conn->current_msg == NULL", conn->current_msg == NULL); } } /** * Setup a tcp_pcb with the correct callback function pointers * and their arguments. * * @param conn the TCP netconn to setup */ static void setup_tcp(struct netconn *conn) { struct tcp_pcb *pcb; pcb = conn->pcb.tcp; tcp_arg(pcb, conn); tcp_recv(pcb, recv_tcp); tcp_sent(pcb, sent_tcp); tcp_poll(pcb, poll_tcp, 4); tcp_err(pcb, err_tcp); } /** * Accept callback function for TCP netconns. * Allocates a new netconn and posts that to conn->acceptmbox. * * @see tcp.h (struct tcp_pcb_listen.accept) for parameters and return value */ static err_t accept_function(void *arg, struct tcp_pcb *newpcb, err_t err) { struct netconn *newconn; struct netconn *conn = (struct netconn *)arg; LWIP_DEBUGF(API_MSG_DEBUG, ("accept_function: newpcb->tate: %s\n", tcp_debug_state_str(newpcb->state))); if (!sys_mbox_valid(&conn->acceptmbox)) { LWIP_DEBUGF(API_MSG_DEBUG, ("accept_function: acceptmbox already deleted\n")); return ERR_VAL; } /* We have to set the callback here even though * the new socket is unknown. conn->socket is marked as -1. */ newconn = netconn_alloc(conn->type, conn->callback); if (newconn == NULL) { return ERR_MEM; } newconn->pcb.tcp = newpcb; setup_tcp(newconn); /* no protection: when creating the pcb, the netconn is not yet known to the application thread */ newconn->last_err = err; if (sys_mbox_trypost(&conn->acceptmbox, newconn) != ERR_OK) { /* When returning != ERR_OK, the pcb is aborted in tcp_process(), so do nothing here! */ /* remove all references to this netconn from the pcb */ struct tcp_pcb* pcb = newconn->pcb.tcp; tcp_arg(pcb, NULL); tcp_recv(pcb, NULL); tcp_sent(pcb, NULL); tcp_poll(pcb, NULL, 4); tcp_err(pcb, NULL); /* remove reference from to the pcb from this netconn */ newconn->pcb.tcp = NULL; /* no need to drain since we know the recvmbox is empty. */ sys_mbox_free(&newconn->recvmbox); sys_mbox_set_invalid(&newconn->recvmbox); netconn_free(newconn); return ERR_MEM; } else { /* Register event with callback */ API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0); } return ERR_OK; } #endif /* LWIP_TCP */ /** * Create a new pcb of a specific type. * Called from lwip_netconn_do_newconn(). * * @param msg the api_msg_msg describing the connection type * @return msg->conn->err, but the return value is currently ignored */ static void pcb_new(struct api_msg_msg *msg) { LWIP_ASSERT("pcb_new: pcb already allocated", msg->conn->pcb.tcp == NULL); /* Allocate a PCB for this connection */ switch(NETCONNTYPE_GROUP(msg->conn->type)) { #if LWIP_RAW case NETCONN_RAW: msg->conn->pcb.raw = raw_new(msg->msg.n.proto); if(msg->conn->pcb.raw != NULL) { raw_recv(msg->conn->pcb.raw, recv_raw, msg->conn); } break; #endif /* LWIP_RAW */ #if LWIP_UDP case NETCONN_UDP: msg->conn->pcb.udp = udp_new(); if(msg->conn->pcb.udp != NULL) { #if LWIP_UDPLITE if (NETCONNTYPE_ISUDPLITE(msg->conn->type)) { udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_UDPLITE); } #endif /* LWIP_UDPLITE */ if (NETCONNTYPE_ISUDPNOCHKSUM(msg->conn->type)) { udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_NOCHKSUM); } udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn); } break; #endif /* LWIP_UDP */ #if LWIP_TCP case NETCONN_TCP: msg->conn->pcb.tcp = tcp_new(); if(msg->conn->pcb.tcp != NULL) { setup_tcp(msg->conn); } break; #endif /* LWIP_TCP */ default: /* Unsupported netconn type, e.g. protocol disabled */ msg->err = ERR_VAL; return; } if (msg->conn->pcb.ip == NULL) { msg->err = ERR_MEM; } #if LWIP_IPV6 else { if (NETCONNTYPE_ISIPV6(msg->conn->type)) { ip_set_v6(msg->conn->pcb.ip, 1); } } #endif /* LWIP_IPV6 */ } /** * Create a new pcb of a specific type inside a netconn. * Called from netconn_new_with_proto_and_callback. * * @param msg the api_msg_msg describing the connection type */ void lwip_netconn_do_newconn(struct api_msg_msg *msg) { msg->err = ERR_OK; if(msg->conn->pcb.tcp == NULL) { pcb_new(msg); } /* Else? This "new" connection already has a PCB allocated. */ /* Is this an error condition? Should it be deleted? */ /* We currently just are happy and return. */ TCPIP_APIMSG_ACK(msg); } /** * Create a new netconn (of a specific type) that has a callback function. * The corresponding pcb is NOT created! * * @param t the type of 'connection' to create (@see enum netconn_type) * @param proto the IP protocol for RAW IP pcbs * @param callback a function to call on status changes (RX available, TX'ed) * @return a newly allocated struct netconn or * NULL on memory error */ struct netconn* netconn_alloc(enum netconn_type t, netconn_callback callback) { struct netconn *conn; int size; conn = (struct netconn *)memp_malloc(MEMP_NETCONN); if (conn == NULL) { return NULL; } conn->last_err = ERR_OK; conn->type = t; conn->pcb.tcp = NULL; /* If all sizes are the same, every compiler should optimize this switch to nothing, */ switch(NETCONNTYPE_GROUP(t)) { #if LWIP_RAW case NETCONN_RAW: size = DEFAULT_RAW_RECVMBOX_SIZE; break; #endif /* LWIP_RAW */ #if LWIP_UDP case NETCONN_UDP: size = DEFAULT_UDP_RECVMBOX_SIZE; break; #endif /* LWIP_UDP */ #if LWIP_TCP case NETCONN_TCP: size = DEFAULT_TCP_RECVMBOX_SIZE; break; #endif /* LWIP_TCP */ default: LWIP_ASSERT("netconn_alloc: undefined netconn_type", 0); goto free_and_return; } if (sys_sem_new(&conn->op_completed, 0) != ERR_OK) { goto free_and_return; } if (sys_mbox_new(&conn->recvmbox, size) != ERR_OK) { sys_sem_free(&conn->op_completed); goto free_and_return; } #if LWIP_TCP sys_mbox_set_invalid(&conn->acceptmbox); #endif conn->state = NETCONN_NONE; #if LWIP_SOCKET /* initialize socket to -1 since 0 is a valid socket */ conn->socket = -1; #endif /* LWIP_SOCKET */ conn->callback = callback; #if LWIP_TCP conn->current_msg = NULL; conn->write_offset = 0; #endif /* LWIP_TCP */ #if LWIP_SO_SNDTIMEO conn->send_timeout = 0; #endif /* LWIP_SO_SNDTIMEO */ #if LWIP_SO_RCVTIMEO conn->recv_timeout = 0; #endif /* LWIP_SO_RCVTIMEO */ #if LWIP_SO_RCVBUF conn->recv_bufsize = RECV_BUFSIZE_DEFAULT; conn->recv_avail = 0; #endif /* LWIP_SO_RCVBUF */ conn->flags = 0; return conn; free_and_return: memp_free(MEMP_NETCONN, conn); return NULL; } /** * Delete a netconn and all its resources. * The pcb is NOT freed (since we might not be in the right thread context do this). * * @param conn the netconn to free */ void netconn_free(struct netconn *conn) { LWIP_ASSERT("PCB must be deallocated outside this function", conn->pcb.tcp == NULL); LWIP_ASSERT("recvmbox must be deallocated before calling this function", !sys_mbox_valid(&conn->recvmbox)); #if LWIP_TCP LWIP_ASSERT("acceptmbox must be deallocated before calling this function", !sys_mbox_valid(&conn->acceptmbox)); #endif /* LWIP_TCP */ sys_sem_free(&conn->op_completed); sys_sem_set_invalid(&conn->op_completed); memp_free(MEMP_NETCONN, conn); } /** * Delete rcvmbox and acceptmbox of a netconn and free the left-over data in * these mboxes * * @param conn the netconn to free * @bytes_drained bytes drained from recvmbox * @accepts_drained pending connections drained from acceptmbox */ static void netconn_drain(struct netconn *conn) { void *mem; #if LWIP_TCP struct pbuf *p; #endif /* LWIP_TCP */ /* This runs in tcpip_thread, so we don't need to lock against rx packets */ /* Delete and drain the recvmbox. */ if (sys_mbox_valid(&conn->recvmbox)) { while (sys_mbox_tryfetch(&conn->recvmbox, &mem) != SYS_MBOX_EMPTY) { #if LWIP_TCP if (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP) { if(mem != NULL) { p = (struct pbuf*)mem; /* pcb might be set to NULL already by err_tcp() */ if (conn->pcb.tcp != NULL) { tcp_recved(conn->pcb.tcp, p->tot_len); } pbuf_free(p); } } else #endif /* LWIP_TCP */ { netbuf_delete((struct netbuf *)mem); } } sys_mbox_free(&conn->recvmbox); sys_mbox_set_invalid(&conn->recvmbox); } /* Delete and drain the acceptmbox. */ #if LWIP_TCP if (sys_mbox_valid(&conn->acceptmbox)) { while (sys_mbox_tryfetch(&conn->acceptmbox, &mem) != SYS_MBOX_EMPTY) { struct netconn *newconn = (struct netconn *)mem; /* Only tcp pcbs have an acceptmbox, so no need to check conn->type */ /* pcb might be set to NULL already by err_tcp() */ if (conn->pcb.tcp != NULL) { tcp_accepted(conn->pcb.tcp); } /* drain recvmbox */ netconn_drain(newconn); if (newconn->pcb.tcp != NULL) { tcp_abort(newconn->pcb.tcp); newconn->pcb.tcp = NULL; } netconn_free(newconn); } sys_mbox_free(&conn->acceptmbox); sys_mbox_set_invalid(&conn->acceptmbox); } #endif /* LWIP_TCP */ } #if LWIP_TCP /** * Internal helper function to close a TCP netconn: since this sometimes * doesn't work at the first attempt, this function is called from multiple * places. * * @param conn the TCP netconn to close */ static void lwip_netconn_do_close_internal(struct netconn *conn) { err_t err; u8_t shut, shut_rx, shut_tx, close; LWIP_ASSERT("invalid conn", (conn != NULL)); LWIP_ASSERT("this is for tcp netconns only", (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP)); LWIP_ASSERT("conn must be in state NETCONN_CLOSE", (conn->state == NETCONN_CLOSE)); LWIP_ASSERT("pcb already closed", (conn->pcb.tcp != NULL)); LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL); shut = conn->current_msg->msg.sd.shut; shut_rx = shut & NETCONN_SHUT_RD; shut_tx = shut & NETCONN_SHUT_WR; /* shutting down both ends is the same as closing */ close = shut == NETCONN_SHUT_RDWR; /* Set back some callback pointers */ if (close) { tcp_arg(conn->pcb.tcp, NULL); } if (conn->pcb.tcp->state == LISTEN) { tcp_accept(conn->pcb.tcp, NULL); } else { /* some callbacks have to be reset if tcp_close is not successful */ if (shut_rx) { tcp_recv(conn->pcb.tcp, NULL); tcp_accept(conn->pcb.tcp, NULL); } if (shut_tx) { tcp_sent(conn->pcb.tcp, NULL); } if (close) { tcp_poll(conn->pcb.tcp, NULL, 4); tcp_err(conn->pcb.tcp, NULL); } } /* Try to close the connection */ if (close) { err = tcp_close(conn->pcb.tcp); } else { err = tcp_shutdown(conn->pcb.tcp, shut_rx, shut_tx); } if (err == ERR_OK) { /* Closing succeeded */ conn->current_msg->err = ERR_OK; conn->current_msg = NULL; conn->state = NETCONN_NONE; if (close) { /* Set back some callback pointers as conn is going away */ conn->pcb.tcp = NULL; /* Trigger select() in socket layer. Make sure everybody notices activity on the connection, error first! */ API_EVENT(conn, NETCONN_EVT_ERROR, 0); } if (shut_rx) { API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0); } if (shut_tx) { API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0); } /* wake up the application task */ sys_sem_signal(&conn->op_completed); } else { /* Closing failed, restore some of the callbacks */ /* Closing of listen pcb will never fail! */ LWIP_ASSERT("Closing a listen pcb may not fail!", (conn->pcb.tcp->state != LISTEN)); tcp_sent(conn->pcb.tcp, sent_tcp); tcp_poll(conn->pcb.tcp, poll_tcp, 4); tcp_err(conn->pcb.tcp, err_tcp); tcp_arg(conn->pcb.tcp, conn); /* don't restore recv callback: we don't want to receive any more data */ } /* If closing didn't succeed, we get called again either from poll_tcp or from sent_tcp */ } #endif /* LWIP_TCP */ /** * Delete the pcb inside a netconn. * Called from netconn_delete. * * @param msg the api_msg_msg pointing to the connection */ void lwip_netconn_do_delconn(struct api_msg_msg *msg) { /* @todo TCP: abort running write/connect? */ if ((msg->conn->state != NETCONN_NONE) && (msg->conn->state != NETCONN_LISTEN) && (msg->conn->state != NETCONN_CONNECT)) { /* this only happens for TCP netconns */ LWIP_ASSERT("NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP", NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP); msg->err = ERR_INPROGRESS; } else { LWIP_ASSERT("blocking connect in progress", (msg->conn->state != NETCONN_CONNECT) || IN_NONBLOCKING_CONNECT(msg->conn)); /* Drain and delete mboxes */ netconn_drain(msg->conn); if (msg->conn->pcb.tcp != NULL) { switch (NETCONNTYPE_GROUP(msg->conn->type)) { #if LWIP_RAW case NETCONN_RAW: raw_remove(msg->conn->pcb.raw); break; #endif /* LWIP_RAW */ #if LWIP_UDP case NETCONN_UDP: msg->conn->pcb.udp->recv_arg = NULL; udp_remove(msg->conn->pcb.udp); break; #endif /* LWIP_UDP */ #if LWIP_TCP case NETCONN_TCP: LWIP_ASSERT("already writing or closing", msg->conn->current_msg == NULL && msg->conn->write_offset == 0); msg->conn->state = NETCONN_CLOSE; msg->msg.sd.shut = NETCONN_SHUT_RDWR; msg->conn->current_msg = msg; lwip_netconn_do_close_internal(msg->conn); /* API_EVENT is called inside lwip_netconn_do_close_internal, before releasing the application thread, so we can return at this point! */ return; #endif /* LWIP_TCP */ default: break; } msg->conn->pcb.tcp = NULL; } /* tcp netconns don't come here! */ /* @todo: this lets select make the socket readable and writable, which is wrong! errfd instead? */ API_EVENT(msg->conn, NETCONN_EVT_RCVPLUS, 0); API_EVENT(msg->conn, NETCONN_EVT_SENDPLUS, 0); } if (sys_sem_valid(&msg->conn->op_completed)) { sys_sem_signal(&msg->conn->op_completed); } } /** * Bind a pcb contained in a netconn * Called from netconn_bind. * * @param msg the api_msg_msg pointing to the connection and containing * the IP address and port to bind to */ void lwip_netconn_do_bind(struct api_msg_msg *msg) { if (ERR_IS_FATAL(msg->conn->last_err)) { msg->err = msg->conn->last_err; } else { msg->err = ERR_VAL; if (msg->conn->pcb.tcp != NULL) { switch (NETCONNTYPE_GROUP(msg->conn->type)) { #if LWIP_RAW case NETCONN_RAW: msg->err = raw_bind(msg->conn->pcb.raw, API_EXPR_REF(msg->msg.bc.ipaddr)); break; #endif /* LWIP_RAW */ #if LWIP_UDP case NETCONN_UDP: msg->err = udp_bind(msg->conn->pcb.udp, API_EXPR_REF(msg->msg.bc.ipaddr), msg->msg.bc.port); break; #endif /* LWIP_UDP */ #if LWIP_TCP case NETCONN_TCP: msg->err = tcp_bind(msg->conn->pcb.tcp, API_EXPR_REF(msg->msg.bc.ipaddr), msg->msg.bc.port); break; #endif /* LWIP_TCP */ default: break; } } } TCPIP_APIMSG_ACK(msg); } #if LWIP_TCP /** * TCP callback function if a connection (opened by tcp_connect/lwip_netconn_do_connect) has * been established (or reset by the remote host). * * @see tcp.h (struct tcp_pcb.connected) for parameters and return values */ static err_t lwip_netconn_do_connected(void *arg, struct tcp_pcb *pcb, err_t err) { struct netconn *conn; int was_blocking; LWIP_UNUSED_ARG(pcb); conn = (struct netconn *)arg; if (conn == NULL) { return ERR_VAL; } LWIP_ASSERT("conn->state == NETCONN_CONNECT", conn->state == NETCONN_CONNECT); LWIP_ASSERT("(conn->current_msg != NULL) || conn->in_non_blocking_connect", (conn->current_msg != NULL) || IN_NONBLOCKING_CONNECT(conn)); if (conn->current_msg != NULL) { conn->current_msg->err = err; } if ((NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP) && (err == ERR_OK)) { setup_tcp(conn); } was_blocking = !IN_NONBLOCKING_CONNECT(conn); SET_NONBLOCKING_CONNECT(conn, 0); conn->current_msg = NULL; conn->state = NETCONN_NONE; if (!was_blocking) { NETCONN_SET_SAFE_ERR(conn, ERR_OK); } API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0); if (was_blocking) { sys_sem_signal(&conn->op_completed); } return ERR_OK; } #endif /* LWIP_TCP */ /** * Connect a pcb contained inside a netconn * Called from netconn_connect. * * @param msg the api_msg_msg pointing to the connection and containing * the IP address and port to connect to */ void lwip_netconn_do_connect(struct api_msg_msg *msg) { if (msg->conn->pcb.tcp == NULL) { /* This may happen when calling netconn_connect() a second time */ msg->err = ERR_CLSD; if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) { /* For TCP, netconn_connect() calls tcpip_apimsg(), so signal op_completed here. */ sys_sem_signal(&msg->conn->op_completed); return; } } else { switch (NETCONNTYPE_GROUP(msg->conn->type)) { #if LWIP_RAW case NETCONN_RAW: msg->err = raw_connect(msg->conn->pcb.raw, API_EXPR_REF(msg->msg.bc.ipaddr)); break; #endif /* LWIP_RAW */ #if LWIP_UDP case NETCONN_UDP: msg->err = udp_connect(msg->conn->pcb.udp, API_EXPR_REF(msg->msg.bc.ipaddr), msg->msg.bc.port); break; #endif /* LWIP_UDP */ #if LWIP_TCP case NETCONN_TCP: /* Prevent connect while doing any other action. */ if (msg->conn->state != NETCONN_NONE) { msg->err = ERR_ISCONN; } else { setup_tcp(msg->conn); msg->err = tcp_connect(msg->conn->pcb.tcp, API_EXPR_REF(msg->msg.bc.ipaddr), msg->msg.bc.port, lwip_netconn_do_connected); if (msg->err == ERR_OK) { u8_t non_blocking = netconn_is_nonblocking(msg->conn); msg->conn->state = NETCONN_CONNECT; SET_NONBLOCKING_CONNECT(msg->conn, non_blocking); if (non_blocking) { msg->err = ERR_INPROGRESS; } else { msg->conn->current_msg = msg; /* sys_sem_signal() is called from lwip_netconn_do_connected (or err_tcp()), * when the connection is established! */ return; } } } /* For TCP, netconn_connect() calls tcpip_apimsg(), so signal op_completed here. */ sys_sem_signal(&msg->conn->op_completed); return; #endif /* LWIP_TCP */ default: LWIP_ERROR("Invalid netconn type", 0, do{ msg->err = ERR_VAL; }while(0)); break; } } /* For all other protocols, netconn_connect() calls TCPIP_APIMSG(), so use TCPIP_APIMSG_ACK() here. */ TCPIP_APIMSG_ACK(msg); } /** * Connect a pcb contained inside a netconn * Only used for UDP netconns. * Called from netconn_disconnect. * * @param msg the api_msg_msg pointing to the connection to disconnect */ void lwip_netconn_do_disconnect(struct api_msg_msg *msg) { #if LWIP_UDP if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_UDP) { udp_disconnect(msg->conn->pcb.udp); msg->err = ERR_OK; } else #endif /* LWIP_UDP */ { msg->err = ERR_VAL; } TCPIP_APIMSG_ACK(msg); } #if LWIP_TCP /** * Set a TCP pcb contained in a netconn into listen mode * Called from netconn_listen. * * @param msg the api_msg_msg pointing to the connection */ void lwip_netconn_do_listen(struct api_msg_msg *msg) { if (ERR_IS_FATAL(msg->conn->last_err)) { msg->err = msg->conn->last_err; } else { msg->err = ERR_CONN; if (msg->conn->pcb.tcp != NULL) { if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) { if (msg->conn->state == NETCONN_NONE) { struct tcp_pcb* lpcb; #if LWIP_IPV6 if ((msg->conn->flags & NETCONN_FLAG_IPV6_V6ONLY) == 0) { #if TCP_LISTEN_BACKLOG lpcb = tcp_listen_dual_with_backlog(msg->conn->pcb.tcp, msg->msg.lb.backlog); #else /* TCP_LISTEN_BACKLOG */ lpcb = tcp_listen_dual(msg->conn->pcb.tcp); #endif /* TCP_LISTEN_BACKLOG */ } else #endif /* LWIP_IPV6 */ { #if TCP_LISTEN_BACKLOG lpcb = tcp_listen_with_backlog(msg->conn->pcb.tcp, msg->msg.lb.backlog); #else /* TCP_LISTEN_BACKLOG */ lpcb = tcp_listen(msg->conn->pcb.tcp); #endif /* TCP_LISTEN_BACKLOG */ } if (lpcb == NULL) { /* in this case, the old pcb is still allocated */ msg->err = ERR_MEM; } else { /* delete the recvmbox and allocate the acceptmbox */ if (sys_mbox_valid(&msg->conn->recvmbox)) { /** @todo: should we drain the recvmbox here? */ sys_mbox_free(&msg->conn->recvmbox); sys_mbox_set_invalid(&msg->conn->recvmbox); } msg->err = ERR_OK; if (!sys_mbox_valid(&msg->conn->acceptmbox)) { msg->err = sys_mbox_new(&msg->conn->acceptmbox, DEFAULT_ACCEPTMBOX_SIZE); } if (msg->err == ERR_OK) { msg->conn->state = NETCONN_LISTEN; msg->conn->pcb.tcp = lpcb; tcp_arg(msg->conn->pcb.tcp, msg->conn); tcp_accept(msg->conn->pcb.tcp, accept_function); } else { /* since the old pcb is already deallocated, free lpcb now */ tcp_close(lpcb); msg->conn->pcb.tcp = NULL; } } } } else { msg->err = ERR_ARG; } } } TCPIP_APIMSG_ACK(msg); } #endif /* LWIP_TCP */ /** * Send some data on a RAW or UDP pcb contained in a netconn * Called from netconn_send * * @param msg the api_msg_msg pointing to the connection */ void lwip_netconn_do_send(struct api_msg_msg *msg) { if (ERR_IS_FATAL(msg->conn->last_err)) { msg->err = msg->conn->last_err; } else { msg->err = ERR_CONN; if (msg->conn->pcb.tcp != NULL) { switch (NETCONNTYPE_GROUP(msg->conn->type)) { #if LWIP_RAW case NETCONN_RAW: if (ipX_addr_isany(PCB_ISIPV6(msg->conn->pcb.ip), &msg->msg.b->addr)) { msg->err = raw_send(msg->conn->pcb.raw, msg->msg.b->p); } else { msg->err = raw_sendto(msg->conn->pcb.raw, msg->msg.b->p, ipX_2_ip(&msg->msg.b->addr)); } break; #endif #if LWIP_UDP case NETCONN_UDP: #if LWIP_CHECKSUM_ON_COPY if (ipX_addr_isany(PCB_ISIPV6(msg->conn->pcb.ip), &msg->msg.b->addr)) { msg->err = udp_send_chksum(msg->conn->pcb.udp, msg->msg.b->p, msg->msg.b->flags & NETBUF_FLAG_CHKSUM, msg->msg.b->toport_chksum); } else { msg->err = udp_sendto_chksum(msg->conn->pcb.udp, msg->msg.b->p, ipX_2_ip(&msg->msg.b->addr), msg->msg.b->port, msg->msg.b->flags & NETBUF_FLAG_CHKSUM, msg->msg.b->toport_chksum); } #else /* LWIP_CHECKSUM_ON_COPY */ if (ipX_addr_isany(PCB_ISIPV6(msg->conn->pcb.ip), &msg->msg.b->addr)) { msg->err = udp_send(msg->conn->pcb.udp, msg->msg.b->p); } else { msg->err = udp_sendto(msg->conn->pcb.udp, msg->msg.b->p, ipX_2_ip(&msg->msg.b->addr), msg->msg.b->port); } #endif /* LWIP_CHECKSUM_ON_COPY */ break; #endif /* LWIP_UDP */ default: break; } } } TCPIP_APIMSG_ACK(msg); } #if LWIP_TCP /** * Indicate data has been received from a TCP pcb contained in a netconn * Called from netconn_recv * * @param msg the api_msg_msg pointing to the connection */ void lwip_netconn_do_recv(struct api_msg_msg *msg) { msg->err = ERR_OK; if (msg->conn->pcb.tcp != NULL) { if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) { #if TCP_LISTEN_BACKLOG if (msg->conn->pcb.tcp->state == LISTEN) { tcp_accepted(msg->conn->pcb.tcp); } else #endif /* TCP_LISTEN_BACKLOG */ { u32_t remaining = msg->msg.r.len; do { u16_t recved = (remaining > 0xffff) ? 0xffff : (u16_t)remaining; tcp_recved(msg->conn->pcb.tcp, recved); remaining -= recved; }while(remaining != 0); } } } TCPIP_APIMSG_ACK(msg); } /** * See if more data needs to be written from a previous call to netconn_write. * Called initially from lwip_netconn_do_write. If the first call can't send all data * (because of low memory or empty send-buffer), this function is called again * from sent_tcp() or poll_tcp() to send more data. If all data is sent, the * blocking application thread (waiting in netconn_write) is released. * * @param conn netconn (that is currently in state NETCONN_WRITE) to process * @return ERR_OK * ERR_MEM if LWIP_TCPIP_CORE_LOCKING=1 and sending hasn't yet finished */ static err_t lwip_netconn_do_writemore(struct netconn *conn) { err_t err; void *dataptr; u16_t len, available; u8_t write_finished = 0; size_t diff; u8_t dontblock; u8_t apiflags; LWIP_ASSERT("conn != NULL", conn != NULL); LWIP_ASSERT("conn->state == NETCONN_WRITE", (conn->state == NETCONN_WRITE)); LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL); LWIP_ASSERT("conn->pcb.tcp != NULL", conn->pcb.tcp != NULL); LWIP_ASSERT("conn->write_offset < conn->current_msg->msg.w.len", conn->write_offset < conn->current_msg->msg.w.len); dontblock = netconn_is_nonblocking(conn) || (conn->current_msg->msg.w.apiflags & NETCONN_DONTBLOCK); apiflags = conn->current_msg->msg.w.apiflags; #if LWIP_SO_SNDTIMEO if ((conn->send_timeout != 0) && ((s32_t)(sys_now() - conn->current_msg->msg.w.time_started) >= conn->send_timeout)) { write_finished = 1; if (conn->write_offset == 0) { /* nothing has been written */ err = ERR_WOULDBLOCK; conn->current_msg->msg.w.len = 0; } else { /* partial write */ err = ERR_OK; conn->current_msg->msg.w.len = conn->write_offset; } } else #endif /* LWIP_SO_SNDTIMEO */ { dataptr = (u8_t*)conn->current_msg->msg.w.dataptr + conn->write_offset; diff = conn->current_msg->msg.w.len - conn->write_offset; if (diff > 0xffffUL) { /* max_u16_t */ len = 0xffff; #if LWIP_TCPIP_CORE_LOCKING conn->flags |= NETCONN_FLAG_WRITE_DELAYED; #endif apiflags |= TCP_WRITE_FLAG_MORE; } else { len = (u16_t)diff; } available = tcp_sndbuf(conn->pcb.tcp); if (available < len) { /* don't try to write more than sendbuf */ len = available; if (dontblock){ if (!len) { err = ERR_WOULDBLOCK; goto err_mem; } } else { #if LWIP_TCPIP_CORE_LOCKING conn->flags |= NETCONN_FLAG_WRITE_DELAYED; #endif apiflags |= TCP_WRITE_FLAG_MORE; } } LWIP_ASSERT("lwip_netconn_do_writemore: invalid length!", ((conn->write_offset + len) <= conn->current_msg->msg.w.len)); err = tcp_write(conn->pcb.tcp, dataptr, len, apiflags); /* if OK or memory error, check available space */ if ((err == ERR_OK) || (err == ERR_MEM)) { err_mem: if (dontblock && (len < conn->current_msg->msg.w.len)) { /* non-blocking write did not write everything: mark the pcb non-writable and let poll_tcp check writable space to mark the pcb writable again */ API_EVENT(conn, NETCONN_EVT_SENDMINUS, len); conn->flags |= NETCONN_FLAG_CHECK_WRITESPACE; } else if ((tcp_sndbuf(conn->pcb.tcp) <= TCP_SNDLOWAT) || (tcp_sndqueuelen(conn->pcb.tcp) >= TCP_SNDQUEUELOWAT)) { /* The queued byte- or pbuf-count exceeds the configured low-water limit, let select mark this pcb as non-writable. */ API_EVENT(conn, NETCONN_EVT_SENDMINUS, len); } } if (err == ERR_OK) { conn->write_offset += len; if ((conn->write_offset == conn->current_msg->msg.w.len) || dontblock) { /* return sent length */ conn->current_msg->msg.w.len = conn->write_offset; /* everything was written */ write_finished = 1; conn->write_offset = 0; } tcp_output(conn->pcb.tcp); } else if ((err == ERR_MEM) && !dontblock) { /* If ERR_MEM, we wait for sent_tcp or poll_tcp to be called we do NOT return to the application thread, since ERR_MEM is only a temporary error! */ /* tcp_write returned ERR_MEM, try tcp_output anyway */ tcp_output(conn->pcb.tcp); #if LWIP_TCPIP_CORE_LOCKING conn->flags |= NETCONN_FLAG_WRITE_DELAYED; #endif } else { /* On errors != ERR_MEM, we don't try writing any more but return the error to the application thread. */ write_finished = 1; conn->current_msg->msg.w.len = 0; } } if (write_finished) { /* everything was written: set back connection state and back to application task */ conn->current_msg->err = err; conn->current_msg = NULL; conn->state = NETCONN_NONE; #if LWIP_TCPIP_CORE_LOCKING if ((conn->flags & NETCONN_FLAG_WRITE_DELAYED) != 0) #endif { sys_sem_signal(&conn->op_completed); } } #if LWIP_TCPIP_CORE_LOCKING else return ERR_MEM; #endif return ERR_OK; } #endif /* LWIP_TCP */ /** * Send some data on a TCP pcb contained in a netconn * Called from netconn_write * * @param msg the api_msg_msg pointing to the connection */ void lwip_netconn_do_write(struct api_msg_msg *msg) { if (ERR_IS_FATAL(msg->conn->last_err)) { msg->err = msg->conn->last_err; } else { if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) { #if LWIP_TCP if (msg->conn->state != NETCONN_NONE) { /* netconn is connecting, closing or in blocking write */ msg->err = ERR_INPROGRESS; } else if (msg->conn->pcb.tcp != NULL) { msg->conn->state = NETCONN_WRITE; /* set all the variables used by lwip_netconn_do_writemore */ LWIP_ASSERT("already writing or closing", msg->conn->current_msg == NULL && msg->conn->write_offset == 0); LWIP_ASSERT("msg->msg.w.len != 0", msg->msg.w.len != 0); msg->conn->current_msg = msg; msg->conn->write_offset = 0; #if LWIP_TCPIP_CORE_LOCKING msg->conn->flags &= ~NETCONN_FLAG_WRITE_DELAYED; if (lwip_netconn_do_writemore(msg->conn) != ERR_OK) { LWIP_ASSERT("state!", msg->conn->state == NETCONN_WRITE); UNLOCK_TCPIP_CORE(); sys_arch_sem_wait(&msg->conn->op_completed, 0); LOCK_TCPIP_CORE(); LWIP_ASSERT("state!", msg->conn->state == NETCONN_NONE); } #else /* LWIP_TCPIP_CORE_LOCKING */ lwip_netconn_do_writemore(msg->conn); #endif /* LWIP_TCPIP_CORE_LOCKING */ /* for both cases: if lwip_netconn_do_writemore was called, don't ACK the APIMSG since lwip_netconn_do_writemore ACKs it! */ return; } else { msg->err = ERR_CONN; } #else /* LWIP_TCP */ msg->err = ERR_VAL; #endif /* LWIP_TCP */ #if (LWIP_UDP || LWIP_RAW) } else { msg->err = ERR_VAL; #endif /* (LWIP_UDP || LWIP_RAW) */ } } TCPIP_APIMSG_ACK(msg); } /** * Return a connection's local or remote address * Called from netconn_getaddr * * @param msg the api_msg_msg pointing to the connection */ void lwip_netconn_do_getaddr(struct api_msg_msg *msg) { if (msg->conn->pcb.ip != NULL) { if (msg->msg.ad.local) { ipX_addr_copy(PCB_ISIPV6(msg->conn->pcb.ip), API_EXPR_DEREF(msg->msg.ad.ipaddr), msg->conn->pcb.ip->local_ip); } else { ipX_addr_copy(PCB_ISIPV6(msg->conn->pcb.ip), API_EXPR_DEREF(msg->msg.ad.ipaddr), msg->conn->pcb.ip->remote_ip); } msg->err = ERR_OK; switch (NETCONNTYPE_GROUP(msg->conn->type)) { #if LWIP_RAW case NETCONN_RAW: if (msg->msg.ad.local) { API_EXPR_DEREF(msg->msg.ad.port) = msg->conn->pcb.raw->protocol; } else { /* return an error as connecting is only a helper for upper layers */ msg->err = ERR_CONN; } break; #endif /* LWIP_RAW */ #if LWIP_UDP case NETCONN_UDP: if (msg->msg.ad.local) { API_EXPR_DEREF(msg->msg.ad.port) = msg->conn->pcb.udp->local_port; } else { if ((msg->conn->pcb.udp->flags & UDP_FLAGS_CONNECTED) == 0) { msg->err = ERR_CONN; } else { API_EXPR_DEREF(msg->msg.ad.port) = msg->conn->pcb.udp->remote_port; } } break; #endif /* LWIP_UDP */ #if LWIP_TCP case NETCONN_TCP: if ((msg->msg.ad.local == 0) && ((msg->conn->pcb.tcp->state == CLOSED) || (msg->conn->pcb.tcp->state == LISTEN))) { /* pcb is not connected and remote name is requested */ msg->err = ERR_CONN; } else { API_EXPR_DEREF(msg->msg.ad.port) = (msg->msg.ad.local ? msg->conn->pcb.tcp->local_port : msg->conn->pcb.tcp->remote_port); } break; #endif /* LWIP_TCP */ default: LWIP_ASSERT("invalid netconn_type", 0); break; } } else { msg->err = ERR_CONN; } TCPIP_APIMSG_ACK(msg); } /** * Close a TCP pcb contained in a netconn * Called from netconn_close * * @param msg the api_msg_msg pointing to the connection */ void lwip_netconn_do_close(struct api_msg_msg *msg) { #if LWIP_TCP /* @todo: abort running write/connect? */ if ((msg->conn->state != NETCONN_NONE) && (msg->conn->state != NETCONN_LISTEN)) { /* this only happens for TCP netconns */ LWIP_ASSERT("NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP", NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP); msg->err = ERR_INPROGRESS; } else if ((msg->conn->pcb.tcp != NULL) && (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP)) { if ((msg->msg.sd.shut != NETCONN_SHUT_RDWR) && (msg->conn->state == NETCONN_LISTEN)) { /* LISTEN doesn't support half shutdown */ msg->err = ERR_CONN; } else { if (msg->msg.sd.shut & NETCONN_SHUT_RD) { /* Drain and delete mboxes */ netconn_drain(msg->conn); } LWIP_ASSERT("already writing or closing", msg->conn->current_msg == NULL && msg->conn->write_offset == 0); msg->conn->state = NETCONN_CLOSE; msg->conn->current_msg = msg; lwip_netconn_do_close_internal(msg->conn); /* for tcp netconns, lwip_netconn_do_close_internal ACKs the message */ return; } } else #endif /* LWIP_TCP */ { msg->err = ERR_VAL; } sys_sem_signal(&msg->conn->op_completed); } #if LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) /** * Join multicast groups for UDP netconns. * Called from netconn_join_leave_group * * @param msg the api_msg_msg pointing to the connection */ void lwip_netconn_do_join_leave_group(struct api_msg_msg *msg) { if (ERR_IS_FATAL(msg->conn->last_err)) { msg->err = msg->conn->last_err; } else { if (msg->conn->pcb.tcp != NULL) { if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_UDP) { #if LWIP_UDP #if LWIP_IPV6 && LWIP_IPV6_MLD if (PCB_ISIPV6(msg->conn->pcb.udp)) { if (msg->msg.jl.join_or_leave == NETCONN_JOIN) { msg->err = mld6_joingroup(ipX_2_ip6(API_EXPR_REF(msg->msg.jl.netif_addr)), ipX_2_ip6(API_EXPR_REF(msg->msg.jl.multiaddr))); } else { msg->err = mld6_leavegroup(ipX_2_ip6(API_EXPR_REF(msg->msg.jl.netif_addr)), ipX_2_ip6(API_EXPR_REF(msg->msg.jl.multiaddr))); } } else #endif /* LWIP_IPV6 && LWIP_IPV6_MLD */ { #if LWIP_IGMP if (msg->msg.jl.join_or_leave == NETCONN_JOIN) { msg->err = igmp_joingroup(ipX_2_ip(API_EXPR_REF(msg->msg.jl.netif_addr)), ipX_2_ip(API_EXPR_REF(msg->msg.jl.multiaddr))); } else { msg->err = igmp_leavegroup(ipX_2_ip(API_EXPR_REF(msg->msg.jl.netif_addr)), ipX_2_ip(API_EXPR_REF(msg->msg.jl.multiaddr))); } #endif /* LWIP_IGMP */ } #endif /* LWIP_UDP */ #if (LWIP_TCP || LWIP_RAW) } else { msg->err = ERR_VAL; #endif /* (LWIP_TCP || LWIP_RAW) */ } } else { msg->err = ERR_CONN; } } TCPIP_APIMSG_ACK(msg); } #endif /* LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) */ #if LWIP_DNS /** * Callback function that is called when DNS name is resolved * (or on timeout). A waiting application thread is waked up by * signaling the semaphore. */ static void lwip_netconn_do_dns_found(const char *name, ip_addr_t *ipaddr, void *arg) { struct dns_api_msg *msg = (struct dns_api_msg*)arg; LWIP_ASSERT("DNS response for wrong host name", strcmp(msg->name, name) == 0); LWIP_UNUSED_ARG(name); if (ipaddr == NULL) { /* timeout or memory error */ API_EXPR_DEREF(msg->err) = ERR_VAL; } else { /* address was resolved */ API_EXPR_DEREF(msg->err) = ERR_OK; API_EXPR_DEREF(msg->addr) = *ipaddr; } /* wake up the application task waiting in netconn_gethostbyname */ sys_sem_signal(API_EXPR_REF(msg->sem)); } /** * Execute a DNS query * Called from netconn_gethostbyname * * @param arg the dns_api_msg pointing to the query */ void lwip_netconn_do_gethostbyname(void *arg) { struct dns_api_msg *msg = (struct dns_api_msg*)arg; API_EXPR_DEREF(msg->err) = dns_gethostbyname(msg->name, API_EXPR_REF(msg->addr), lwip_netconn_do_dns_found, msg); if (API_EXPR_DEREF(msg->err) != ERR_INPROGRESS) { /* on error or immediate success, wake up the application * task waiting in netconn_gethostbyname */ sys_sem_signal(API_EXPR_REF(msg->sem)); } } #endif /* LWIP_DNS */ #endif /* LWIP_NETCONN */ ocproxy-1.60/lwip/src/api/err.c000066400000000000000000000056411303453231400164160ustar00rootroot00000000000000/** * @file * Error Management module * */ /* * Copyright (c) 2001-2004 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #include "lwip/err.h" #ifdef LWIP_DEBUG static const char *err_strerr[] = { "Ok.", /* ERR_OK 0 */ "Out of memory error.", /* ERR_MEM -1 */ "Buffer error.", /* ERR_BUF -2 */ "Timeout.", /* ERR_TIMEOUT -3 */ "Routing problem.", /* ERR_RTE -4 */ "Operation in progress.", /* ERR_INPROGRESS -5 */ "Illegal value.", /* ERR_VAL -6 */ "Operation would block.", /* ERR_WOULDBLOCK -7 */ "Address in use.", /* ERR_USE -8 */ "Already connected.", /* ERR_ISCONN -9 */ "Connection aborted.", /* ERR_ABRT -10 */ "Connection reset.", /* ERR_RST -11 */ "Connection closed.", /* ERR_CLSD -12 */ "Not connected.", /* ERR_CONN -13 */ "Illegal argument.", /* ERR_ARG -14 */ "Low-level netif error.", /* ERR_IF -15 */ }; /** * Convert an lwip internal error to a string representation. * * @param err an lwip internal err_t * @return a string representation for err */ const char * lwip_strerr(err_t err) { return err_strerr[-err]; } #endif /* LWIP_DEBUG */ ocproxy-1.60/lwip/src/api/netbuf.c000066400000000000000000000155101303453231400171050ustar00rootroot00000000000000/** * @file * Network buffer management * */ /* * Copyright (c) 2001-2004 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #include "lwip/opt.h" #if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */ #include "lwip/netbuf.h" #include "lwip/memp.h" #include /** * Create (allocate) and initialize a new netbuf. * The netbuf doesn't yet contain a packet buffer! * * @return a pointer to a new netbuf * NULL on lack of memory */ struct netbuf *netbuf_new(void) { struct netbuf *buf; buf = (struct netbuf *)memp_malloc(MEMP_NETBUF); if (buf != NULL) { buf->p = NULL; buf->ptr = NULL; ipX_addr_set_any(LWIP_IPV6, &buf->addr); buf->port = 0; #if LWIP_NETBUF_RECVINFO || LWIP_CHECKSUM_ON_COPY #if LWIP_CHECKSUM_ON_COPY buf->flags = 0; #endif /* LWIP_CHECKSUM_ON_COPY */ buf->toport_chksum = 0; #if LWIP_NETBUF_RECVINFO ipX_addr_set_any(LWIP_IPV6, &buf->toaddr); #endif /* LWIP_NETBUF_RECVINFO */ #endif /* LWIP_NETBUF_RECVINFO || LWIP_CHECKSUM_ON_COPY */ return buf; } else { return NULL; } } /** * Deallocate a netbuf allocated by netbuf_new(). * * @param buf pointer to a netbuf allocated by netbuf_new() */ void netbuf_delete(struct netbuf *buf) { if (buf != NULL) { if (buf->p != NULL) { pbuf_free(buf->p); buf->p = buf->ptr = NULL; } memp_free(MEMP_NETBUF, buf); } } /** * Allocate memory for a packet buffer for a given netbuf. * * @param buf the netbuf for which to allocate a packet buffer * @param size the size of the packet buffer to allocate * @return pointer to the allocated memory * NULL if no memory could be allocated */ void * netbuf_alloc(struct netbuf *buf, u16_t size) { LWIP_ERROR("netbuf_alloc: invalid buf", (buf != NULL), return NULL;); /* Deallocate any previously allocated memory. */ if (buf->p != NULL) { pbuf_free(buf->p); } buf->p = pbuf_alloc(PBUF_TRANSPORT, size, PBUF_RAM); if (buf->p == NULL) { return NULL; } LWIP_ASSERT("check that first pbuf can hold size", (buf->p->len >= size)); buf->ptr = buf->p; return buf->p->payload; } /** * Free the packet buffer included in a netbuf * * @param buf pointer to the netbuf which contains the packet buffer to free */ void netbuf_free(struct netbuf *buf) { LWIP_ERROR("netbuf_free: invalid buf", (buf != NULL), return;); if (buf->p != NULL) { pbuf_free(buf->p); } buf->p = buf->ptr = NULL; } /** * Let a netbuf reference existing (non-volatile) data. * * @param buf netbuf which should reference the data * @param dataptr pointer to the data to reference * @param size size of the data * @return ERR_OK if data is referenced * ERR_MEM if data couldn't be referenced due to lack of memory */ err_t netbuf_ref(struct netbuf *buf, const void *dataptr, u16_t size) { LWIP_ERROR("netbuf_ref: invalid buf", (buf != NULL), return ERR_ARG;); if (buf->p != NULL) { pbuf_free(buf->p); } buf->p = pbuf_alloc(PBUF_TRANSPORT, 0, PBUF_REF); if (buf->p == NULL) { buf->ptr = NULL; return ERR_MEM; } buf->p->payload = (void*)dataptr; buf->p->len = buf->p->tot_len = size; buf->ptr = buf->p; return ERR_OK; } /** * Chain one netbuf to another (@see pbuf_chain) * * @param head the first netbuf * @param tail netbuf to chain after head, freed by this function, may not be reference after returning */ void netbuf_chain(struct netbuf *head, struct netbuf *tail) { LWIP_ERROR("netbuf_ref: invalid head", (head != NULL), return;); LWIP_ERROR("netbuf_chain: invalid tail", (tail != NULL), return;); pbuf_cat(head->p, tail->p); head->ptr = head->p; memp_free(MEMP_NETBUF, tail); } /** * Get the data pointer and length of the data inside a netbuf. * * @param buf netbuf to get the data from * @param dataptr pointer to a void pointer where to store the data pointer * @param len pointer to an u16_t where the length of the data is stored * @return ERR_OK if the information was retreived, * ERR_BUF on error. */ err_t netbuf_data(struct netbuf *buf, void **dataptr, u16_t *len) { LWIP_ERROR("netbuf_data: invalid buf", (buf != NULL), return ERR_ARG;); LWIP_ERROR("netbuf_data: invalid dataptr", (dataptr != NULL), return ERR_ARG;); LWIP_ERROR("netbuf_data: invalid len", (len != NULL), return ERR_ARG;); if (buf->ptr == NULL) { return ERR_BUF; } *dataptr = buf->ptr->payload; *len = buf->ptr->len; return ERR_OK; } /** * Move the current data pointer of a packet buffer contained in a netbuf * to the next part. * The packet buffer itself is not modified. * * @param buf the netbuf to modify * @return -1 if there is no next part * 1 if moved to the next part but now there is no next part * 0 if moved to the next part and there are still more parts */ s8_t netbuf_next(struct netbuf *buf) { LWIP_ERROR("netbuf_free: invalid buf", (buf != NULL), return -1;); if (buf->ptr->next == NULL) { return -1; } buf->ptr = buf->ptr->next; if (buf->ptr->next == NULL) { return 1; } return 0; } /** * Move the current data pointer of a packet buffer contained in a netbuf * to the beginning of the packet. * The packet buffer itself is not modified. * * @param buf the netbuf to modify */ void netbuf_first(struct netbuf *buf) { LWIP_ERROR("netbuf_free: invalid buf", (buf != NULL), return;); buf->ptr = buf->p; } #endif /* LWIP_NETCONN */ ocproxy-1.60/lwip/src/api/netdb.c000066400000000000000000000253761303453231400167310ustar00rootroot00000000000000/** * @file * API functions for name resolving * */ /* * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Simon Goldschmidt * */ #include "lwip/netdb.h" #if LWIP_DNS && LWIP_SOCKET #include "lwip/err.h" #include "lwip/mem.h" #include "lwip/memp.h" #include "lwip/ip_addr.h" #include "lwip/api.h" #include "lwip/dns.h" #include #include /** helper struct for gethostbyname_r to access the char* buffer */ struct gethostbyname_r_helper { ip_addr_t *addr_list[2]; ip_addr_t addr; char *aliases; }; /** h_errno is exported in netdb.h for access by applications. */ #if LWIP_DNS_API_DECLARE_H_ERRNO int h_errno; #endif /* LWIP_DNS_API_DECLARE_H_ERRNO */ /** define "hostent" variables storage: 0 if we use a static (but unprotected) * set of variables for lwip_gethostbyname, 1 if we use a local storage */ #ifndef LWIP_DNS_API_HOSTENT_STORAGE #define LWIP_DNS_API_HOSTENT_STORAGE 0 #endif /** define "hostent" variables storage */ #if LWIP_DNS_API_HOSTENT_STORAGE #define HOSTENT_STORAGE #else #define HOSTENT_STORAGE static #endif /* LWIP_DNS_API_STATIC_HOSTENT */ /** * Returns an entry containing addresses of address family AF_INET * for the host with name name. * Due to dns_gethostbyname limitations, only one address is returned. * * @param name the hostname to resolve * @return an entry containing addresses of address family AF_INET * for the host with name name */ struct hostent* lwip_gethostbyname(const char *name) { err_t err; ip_addr_t addr; /* buffer variables for lwip_gethostbyname() */ HOSTENT_STORAGE struct hostent s_hostent; HOSTENT_STORAGE char *s_aliases; HOSTENT_STORAGE ip_addr_t s_hostent_addr; HOSTENT_STORAGE ip_addr_t *s_phostent_addr[2]; /* query host IP address */ err = netconn_gethostbyname(name, &addr); if (err != ERR_OK) { LWIP_DEBUGF(DNS_DEBUG, ("lwip_gethostbyname(%s) failed, err=%d\n", name, err)); h_errno = HOST_NOT_FOUND; return NULL; } /* fill hostent */ s_hostent_addr = addr; s_phostent_addr[0] = &s_hostent_addr; s_phostent_addr[1] = NULL; s_hostent.h_name = (char*)name; s_aliases = NULL; s_hostent.h_aliases = &s_aliases; s_hostent.h_addrtype = AF_INET; s_hostent.h_length = sizeof(ip_addr_t); s_hostent.h_addr_list = (char**)&s_phostent_addr; #if DNS_DEBUG /* dump hostent */ LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_name == %s\n", s_hostent.h_name)); LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_aliases == %p\n", s_hostent.h_aliases)); /* h_aliases are always empty */ LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addrtype == %d\n", s_hostent.h_addrtype)); LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_length == %d\n", s_hostent.h_length)); LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addr_list == %p\n", s_hostent.h_addr_list)); if (s_hostent.h_addr_list != NULL) { u8_t idx; for ( idx=0; s_hostent.h_addr_list[idx]; idx++) { LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addr_list[%i] == %p\n", idx, s_hostent.h_addr_list[idx])); LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addr_list[%i]-> == %s\n", idx, ip_ntoa((ip_addr_t*)s_hostent.h_addr_list[idx]))); } } #endif /* DNS_DEBUG */ #if LWIP_DNS_API_HOSTENT_STORAGE /* this function should return the "per-thread" hostent after copy from s_hostent */ return sys_thread_hostent(&s_hostent); #else return &s_hostent; #endif /* LWIP_DNS_API_HOSTENT_STORAGE */ } /** * Thread-safe variant of lwip_gethostbyname: instead of using a static * buffer, this function takes buffer and errno pointers as arguments * and uses these for the result. * * @param name the hostname to resolve * @param ret pre-allocated struct where to store the result * @param buf pre-allocated buffer where to store additional data * @param buflen the size of buf * @param result pointer to a hostent pointer that is set to ret on success * and set to zero on error * @param h_errnop pointer to an int where to store errors (instead of modifying * the global h_errno) * @return 0 on success, non-zero on error, additional error information * is stored in *h_errnop instead of h_errno to be thread-safe */ int lwip_gethostbyname_r(const char *name, struct hostent *ret, char *buf, size_t buflen, struct hostent **result, int *h_errnop) { err_t err; struct gethostbyname_r_helper *h; char *hostname; size_t namelen; int lh_errno; if (h_errnop == NULL) { /* ensure h_errnop is never NULL */ h_errnop = &lh_errno; } if (result == NULL) { /* not all arguments given */ *h_errnop = EINVAL; return -1; } /* first thing to do: set *result to nothing */ *result = NULL; if ((name == NULL) || (ret == NULL) || (buf == NULL)) { /* not all arguments given */ *h_errnop = EINVAL; return -1; } namelen = strlen(name); if (buflen < (sizeof(struct gethostbyname_r_helper) + namelen + 1 + (MEM_ALIGNMENT - 1))) { /* buf can't hold the data needed + a copy of name */ *h_errnop = ERANGE; return -1; } h = (struct gethostbyname_r_helper*)LWIP_MEM_ALIGN(buf); hostname = ((char*)h) + sizeof(struct gethostbyname_r_helper); /* query host IP address */ err = netconn_gethostbyname(name, &h->addr); if (err != ERR_OK) { LWIP_DEBUGF(DNS_DEBUG, ("lwip_gethostbyname(%s) failed, err=%d\n", name, err)); *h_errnop = HOST_NOT_FOUND; return -1; } /* copy the hostname into buf */ MEMCPY(hostname, name, namelen); hostname[namelen] = 0; /* fill hostent */ h->addr_list[0] = &h->addr; h->addr_list[1] = NULL; h->aliases = NULL; ret->h_name = hostname; ret->h_aliases = &h->aliases; ret->h_addrtype = AF_INET; ret->h_length = sizeof(ip_addr_t); ret->h_addr_list = (char**)&h->addr_list; /* set result != NULL */ *result = ret; /* return success */ return 0; } /** * Frees one or more addrinfo structures returned by getaddrinfo(), along with * any additional storage associated with those structures. If the ai_next field * of the structure is not null, the entire list of structures is freed. * * @param ai struct addrinfo to free */ void lwip_freeaddrinfo(struct addrinfo *ai) { struct addrinfo *next; while (ai != NULL) { next = ai->ai_next; memp_free(MEMP_NETDB, ai); ai = next; } } /** * Translates the name of a service location (for example, a host name) and/or * a service name and returns a set of socket addresses and associated * information to be used in creating a socket with which to address the * specified service. * Memory for the result is allocated internally and must be freed by calling * lwip_freeaddrinfo()! * * Due to a limitation in dns_gethostbyname, only the first address of a * host is returned. * Also, service names are not supported (only port numbers)! * * @param nodename descriptive name or address string of the host * (may be NULL -> local address) * @param servname port number as string of NULL * @param hints structure containing input values that set socktype and protocol * @param res pointer to a pointer where to store the result (set to NULL on failure) * @return 0 on success, non-zero on failure */ int lwip_getaddrinfo(const char *nodename, const char *servname, const struct addrinfo *hints, struct addrinfo **res) { err_t err; ip_addr_t addr; struct addrinfo *ai; struct sockaddr_in *sa = NULL; int port_nr = 0; size_t total_size; size_t namelen = 0; if (res == NULL) { return EAI_FAIL; } *res = NULL; if ((nodename == NULL) && (servname == NULL)) { return EAI_NONAME; } if (servname != NULL) { /* service name specified: convert to port number * @todo?: currently, only ASCII integers (port numbers) are supported! */ port_nr = atoi(servname); if ((port_nr <= 0) || (port_nr > 0xffff)) { return EAI_SERVICE; } } if (nodename != NULL) { /* service location specified, try to resolve */ err = netconn_gethostbyname(nodename, &addr); if (err != ERR_OK) { return EAI_FAIL; } } else { /* service location specified, use loopback address */ ip_addr_set_loopback(&addr); } total_size = sizeof(struct addrinfo) + sizeof(struct sockaddr_in); if (nodename != NULL) { namelen = strlen(nodename); LWIP_ASSERT("namelen is too long", (namelen + 1) <= (mem_size_t)-1); total_size += namelen + 1; } /* If this fails, please report to lwip-devel! :-) */ LWIP_ASSERT("total_size <= NETDB_ELEM_SIZE: please report this!", total_size <= NETDB_ELEM_SIZE); ai = (struct addrinfo *)memp_malloc(MEMP_NETDB); if (ai == NULL) { return EAI_MEMORY; } memset(ai, 0, total_size); sa = (struct sockaddr_in*)((u8_t*)ai + sizeof(struct addrinfo)); /* set up sockaddr */ inet_addr_from_ipaddr(&sa->sin_addr, &addr); sa->sin_family = AF_INET; sa->sin_len = sizeof(struct sockaddr_in); sa->sin_port = htons((u16_t)port_nr); /* set up addrinfo */ ai->ai_family = AF_INET; if (hints != NULL) { /* copy socktype & protocol from hints if specified */ ai->ai_socktype = hints->ai_socktype; ai->ai_protocol = hints->ai_protocol; } if (nodename != NULL) { /* copy nodename to canonname if specified */ ai->ai_canonname = ((char*)ai + sizeof(struct addrinfo) + sizeof(struct sockaddr_in)); MEMCPY(ai->ai_canonname, nodename, namelen); ai->ai_canonname[namelen] = 0; } ai->ai_addrlen = sizeof(struct sockaddr_in); ai->ai_addr = (struct sockaddr*)sa; *res = ai; return 0; } #endif /* LWIP_DNS && LWIP_SOCKET */ ocproxy-1.60/lwip/src/api/netifapi.c000066400000000000000000000144601303453231400174240ustar00rootroot00000000000000/** * @file * Network Interface Sequential API module * */ /* * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * */ #include "lwip/opt.h" #if LWIP_NETIF_API /* don't build if not configured for use in lwipopts.h */ #include "lwip/netifapi.h" #include "lwip/tcpip.h" #include "lwip/memp.h" #define NETIFAPI_VAR_REF(name) API_VAR_REF(name) #define NETIFAPI_VAR_DECLARE(name) API_VAR_DECLARE(struct netifapi_msg, name) #define NETIFAPI_VAR_ALLOC(name) API_VAR_ALLOC(struct netifapi_msg, MEMP_NETIFAPI_MSG, name) #define NETIFAPI_VAR_FREE(name) API_VAR_FREE(MEMP_NETIFAPI_MSG, name) /** * Call netif_add() inside the tcpip_thread context. */ static void netifapi_do_netif_add(struct netifapi_msg_msg *msg) { if (!netif_add( msg->netif, API_EXPR_REF(msg->msg.add.ipaddr), API_EXPR_REF(msg->msg.add.netmask), API_EXPR_REF(msg->msg.add.gw), msg->msg.add.state, msg->msg.add.init, msg->msg.add.input)) { msg->err = ERR_IF; } else { msg->err = ERR_OK; } TCPIP_NETIFAPI_ACK(msg); } /** * Call netif_set_addr() inside the tcpip_thread context. */ static void netifapi_do_netif_set_addr(struct netifapi_msg_msg *msg) { netif_set_addr( msg->netif, API_EXPR_REF(msg->msg.add.ipaddr), API_EXPR_REF(msg->msg.add.netmask), API_EXPR_REF(msg->msg.add.gw)); msg->err = ERR_OK; TCPIP_NETIFAPI_ACK(msg); } /** * Call the "errtfunc" (or the "voidfunc" if "errtfunc" is NULL) inside the * tcpip_thread context. */ static void netifapi_do_netif_common(struct netifapi_msg_msg *msg) { if (msg->msg.common.errtfunc != NULL) { msg->err = msg->msg.common.errtfunc(msg->netif); } else { msg->err = ERR_OK; msg->msg.common.voidfunc(msg->netif); } TCPIP_NETIFAPI_ACK(msg); } /** * Call netif_add() in a thread-safe way by running that function inside the * tcpip_thread context. * * @note for params @see netif_add() */ err_t netifapi_netif_add(struct netif *netif, ip_addr_t *ipaddr, ip_addr_t *netmask, ip_addr_t *gw, void *state, netif_init_fn init, netif_input_fn input) { err_t err; NETIFAPI_VAR_DECLARE(msg); NETIFAPI_VAR_ALLOC(msg); #if LWIP_MPU_COMPATIBLE if (ipaddr == NULL) { ipaddr = IP_ADDR_ANY; } if (netmask == NULL) { netmask = IP_ADDR_ANY; } if (gw == NULL) { gw = IP_ADDR_ANY; } #endif /* LWIP_MPU_COMPATIBLE */ NETIFAPI_VAR_REF(msg).function = netifapi_do_netif_add; NETIFAPI_VAR_REF(msg).msg.netif = netif; NETIFAPI_VAR_REF(msg).msg.msg.add.ipaddr = NETIFAPI_VAR_REF(ipaddr); NETIFAPI_VAR_REF(msg).msg.msg.add.netmask = NETIFAPI_VAR_REF(netmask); NETIFAPI_VAR_REF(msg).msg.msg.add.gw = NETIFAPI_VAR_REF(gw); NETIFAPI_VAR_REF(msg).msg.msg.add.state = state; NETIFAPI_VAR_REF(msg).msg.msg.add.init = init; NETIFAPI_VAR_REF(msg).msg.msg.add.input = input; TCPIP_NETIFAPI(&API_VAR_REF(msg)); err = NETIFAPI_VAR_REF(msg).msg.err; NETIFAPI_VAR_FREE(msg); return err; } /** * Call netif_set_addr() in a thread-safe way by running that function inside the * tcpip_thread context. * * @note for params @see netif_set_addr() */ err_t netifapi_netif_set_addr(struct netif *netif, ip_addr_t *ipaddr, ip_addr_t *netmask, ip_addr_t *gw) { err_t err; NETIFAPI_VAR_DECLARE(msg); NETIFAPI_VAR_ALLOC(msg); #if LWIP_MPU_COMPATIBLE if (ipaddr == NULL) { ipaddr = IP_ADDR_ANY; } if (netmask == NULL) { netmask = IP_ADDR_ANY; } if (gw == NULL) { gw = IP_ADDR_ANY; } #endif /* LWIP_MPU_COMPATIBLE */ NETIFAPI_VAR_REF(msg).function = netifapi_do_netif_set_addr; NETIFAPI_VAR_REF(msg).msg.netif = netif; NETIFAPI_VAR_REF(msg).msg.msg.add.ipaddr = NETIFAPI_VAR_REF(ipaddr); NETIFAPI_VAR_REF(msg).msg.msg.add.netmask = NETIFAPI_VAR_REF(netmask); NETIFAPI_VAR_REF(msg).msg.msg.add.gw = NETIFAPI_VAR_REF(gw); TCPIP_NETIFAPI(&API_VAR_REF(msg)); err = NETIFAPI_VAR_REF(msg).msg.err; NETIFAPI_VAR_FREE(msg); return err; } /** * call the "errtfunc" (or the "voidfunc" if "errtfunc" is NULL) in a thread-safe * way by running that function inside the tcpip_thread context. * * @note use only for functions where there is only "netif" parameter. */ err_t netifapi_netif_common(struct netif *netif, netifapi_void_fn voidfunc, netifapi_errt_fn errtfunc) { err_t err; NETIFAPI_VAR_DECLARE(msg); NETIFAPI_VAR_ALLOC(msg); NETIFAPI_VAR_REF(msg).function = netifapi_do_netif_common; NETIFAPI_VAR_REF(msg).msg.netif = netif; NETIFAPI_VAR_REF(msg).msg.msg.common.voidfunc = voidfunc; NETIFAPI_VAR_REF(msg).msg.msg.common.errtfunc = errtfunc; TCPIP_NETIFAPI(&API_VAR_REF(msg)); err = NETIFAPI_VAR_REF(msg).msg.err; NETIFAPI_VAR_FREE(msg); return err; } #endif /* LWIP_NETIF_API */ ocproxy-1.60/lwip/src/api/pppapi.c000066400000000000000000000263731303453231400171240ustar00rootroot00000000000000/** * @file * Point To Point Protocol Sequential API module * */ /* * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * */ #include "lwip/opt.h" #if LWIP_PPP_API /* don't build if not configured for use in lwipopts.h */ #include "lwip/pppapi.h" #include "lwip/tcpip.h" /** * Call ppp_new() inside the tcpip_thread context. */ static void pppapi_do_ppp_new(struct pppapi_msg_msg *msg) { msg->ppp = ppp_new(); TCPIP_PPPAPI_ACK(msg); } /** * Call ppp_new() in a thread-safe way by running that function inside the * tcpip_thread context. */ ppp_pcb *pppapi_new(void) { struct pppapi_msg msg; msg.function = pppapi_do_ppp_new; TCPIP_PPPAPI(&msg); return msg.msg.ppp; } /** * Call ppp_set_default() inside the tcpip_thread context. */ static void pppapi_do_ppp_set_default(struct pppapi_msg_msg *msg) { ppp_set_default(msg->ppp); TCPIP_PPPAPI_ACK(msg); } /** * Call ppp_set_default() in a thread-safe way by running that function inside the * tcpip_thread context. */ void pppapi_set_default(ppp_pcb *pcb) { struct pppapi_msg msg; msg.function = pppapi_do_ppp_set_default; msg.msg.ppp = pcb; TCPIP_PPPAPI(&msg); } /** * Call ppp_set_auth() inside the tcpip_thread context. */ static void pppapi_do_ppp_set_auth(struct pppapi_msg_msg *msg) { ppp_set_auth(msg->ppp, msg->msg.setauth.authtype, msg->msg.setauth.user, msg->msg.setauth.passwd); TCPIP_PPPAPI_ACK(msg); } /** * Call ppp_set_auth() in a thread-safe way by running that function inside the * tcpip_thread context. */ void pppapi_set_auth(ppp_pcb *pcb, u8_t authtype, char *user, char *passwd) { struct pppapi_msg msg; msg.function = pppapi_do_ppp_set_auth; msg.msg.ppp = pcb; msg.msg.msg.setauth.authtype = authtype; msg.msg.msg.setauth.user = user; msg.msg.msg.setauth.passwd = passwd; TCPIP_PPPAPI(&msg); } #if PPP_NOTIFY_PHASE /** * Call ppp_set_notify_phase_callback() inside the tcpip_thread context. */ static void pppapi_do_ppp_set_notify_phase_callback(struct pppapi_msg_msg *msg) { ppp_set_notify_phase_callback(msg->ppp, msg->msg.setnotifyphasecb.notify_phase_cb); TCPIP_PPPAPI_ACK(msg); } /** * Call ppp_set_notify_phase_callback() in a thread-safe way by running that function inside the * tcpip_thread context. */ void pppapi_set_notify_phase_callback(ppp_pcb *pcb, ppp_notify_phase_cb_fn notify_phase_cb) { struct pppapi_msg msg; msg.function = pppapi_do_ppp_set_notify_phase_callback; msg.msg.ppp = pcb; msg.msg.msg.setnotifyphasecb.notify_phase_cb = notify_phase_cb; TCPIP_PPPAPI(&msg); } #endif /* PPP_NOTIFY_PHASE */ #if PPPOS_SUPPORT /** * Call ppp_over_serial_create() inside the tcpip_thread context. */ static void pppapi_do_ppp_over_serial_create(struct pppapi_msg_msg *msg) { msg->err = ppp_over_serial_create(msg->ppp, msg->msg.serialcreate.fd, msg->msg.serialcreate.link_status_cb, msg->msg.serialcreate.ctx_cb); TCPIP_PPPAPI_ACK(msg); } /** * Call ppp_over_serial_create() in a thread-safe way by running that function inside the * tcpip_thread context. */ int pppapi_over_serial_create(ppp_pcb *pcb, sio_fd_t fd, ppp_link_status_cb_fn link_status_cb, void *ctx_cb) { struct pppapi_msg msg; msg.function = pppapi_do_ppp_over_serial_create; msg.msg.ppp = pcb; msg.msg.msg.serialcreate.fd = fd; msg.msg.msg.serialcreate.link_status_cb = link_status_cb; msg.msg.msg.serialcreate.ctx_cb = ctx_cb; TCPIP_PPPAPI(&msg); return msg.msg.err; } #endif /* PPPOS_SUPPORT */ #if PPPOE_SUPPORT /** * Call ppp_over_ethernet_create() inside the tcpip_thread context. */ static void pppapi_do_ppp_over_ethernet_create(struct pppapi_msg_msg *msg) { msg->err = ppp_over_ethernet_create(msg->ppp, msg->msg.ethernetcreate.ethif, msg->msg.ethernetcreate.service_name, msg->msg.ethernetcreate.concentrator_name, msg->msg.ethernetcreate.link_status_cb, msg->msg.ethernetcreate.ctx_cb); TCPIP_PPPAPI_ACK(msg); } /** * Call ppp_over_ethernet_create() in a thread-safe way by running that function inside the * tcpip_thread context. */ int pppapi_over_ethernet_create(ppp_pcb *pcb, struct netif *ethif, const char *service_name, const char *concentrator_name, ppp_link_status_cb_fn link_status_cb, void *ctx_cb) { struct pppapi_msg msg; msg.function = pppapi_do_ppp_over_ethernet_create; msg.msg.ppp = pcb; msg.msg.msg.ethernetcreate.ethif = ethif; msg.msg.msg.ethernetcreate.service_name = service_name; msg.msg.msg.ethernetcreate.concentrator_name = concentrator_name; msg.msg.msg.ethernetcreate.link_status_cb = link_status_cb; msg.msg.msg.ethernetcreate.ctx_cb = ctx_cb; TCPIP_PPPAPI(&msg); return msg.msg.err; } #endif /* PPPOE_SUPPORT */ #if PPPOL2TP_SUPPORT /** * Call ppp_over_l2tp_create() inside the tcpip_thread context. */ static void pppapi_do_ppp_over_l2tp_create(struct pppapi_msg_msg *msg) { msg->err = ppp_over_l2tp_create(msg->ppp, msg->msg.l2tpcreate.netif, msg->msg.l2tpcreate.ipaddr, msg->msg.l2tpcreate.port, #if PPPOL2TP_AUTH_SUPPORT msg->msg.l2tpcreate.secret, msg->msg.l2tpcreate.secret_len, #else /* PPPOL2TP_AUTH_SUPPORT */ NULL, #endif /* PPPOL2TP_AUTH_SUPPORT */ msg->msg.l2tpcreate.link_status_cb, msg->msg.l2tpcreate.ctx_cb); TCPIP_PPPAPI_ACK(msg); } /** * Call ppp_over_l2tp_create() in a thread-safe way by running that function inside the * tcpip_thread context. */ int pppapi_over_l2tp_create(ppp_pcb *pcb, struct netif *netif, ip_addr_t *ipaddr, u16_t port, u8_t *secret, u8_t secret_len, ppp_link_status_cb_fn link_status_cb, void *ctx_cb) { struct pppapi_msg msg; msg.function = pppapi_do_ppp_over_l2tp_create; msg.msg.ppp = pcb; msg.msg.msg.l2tpcreate.netif = netif; msg.msg.msg.l2tpcreate.ipaddr = ipaddr; msg.msg.msg.l2tpcreate.port = port; #if PPPOL2TP_AUTH_SUPPORT msg.msg.msg.l2tpcreate.secret = secret; msg.msg.msg.l2tpcreate.secret_len = secret_len; #endif /* PPPOL2TP_AUTH_SUPPORT */ msg.msg.msg.l2tpcreate.link_status_cb = link_status_cb; msg.msg.msg.l2tpcreate.ctx_cb = ctx_cb; TCPIP_PPPAPI(&msg); return msg.msg.err; } #endif /* PPPOL2TP_SUPPORT */ /** * Call ppp_open() inside the tcpip_thread context. */ static void pppapi_do_ppp_open(struct pppapi_msg_msg *msg) { msg->err = ppp_open(msg->ppp, msg->msg.open.holdoff); TCPIP_PPPAPI_ACK(msg); } /** * Call ppp_open() in a thread-safe way by running that function inside the * tcpip_thread context. */ int pppapi_open(ppp_pcb *pcb, u16_t holdoff) { struct pppapi_msg msg; msg.function = pppapi_do_ppp_open; msg.msg.ppp = pcb; msg.msg.msg.open.holdoff = holdoff; TCPIP_PPPAPI(&msg); return msg.msg.err; } /** * Call ppp_close() inside the tcpip_thread context. */ static void pppapi_do_ppp_close(struct pppapi_msg_msg *msg) { msg->err = ppp_close(msg->ppp); TCPIP_PPPAPI_ACK(msg); } /** * Call ppp_close() in a thread-safe way by running that function inside the * tcpip_thread context. */ int pppapi_close(ppp_pcb *pcb) { struct pppapi_msg msg; msg.function = pppapi_do_ppp_close; msg.msg.ppp = pcb; TCPIP_PPPAPI(&msg); return msg.msg.err; } /** * Call ppp_sighup() inside the tcpip_thread context. */ static void pppapi_do_ppp_sighup(struct pppapi_msg_msg *msg) { ppp_sighup(msg->ppp); TCPIP_PPPAPI_ACK(msg); } /** * Call ppp_sighup() in a thread-safe way by running that function inside the * tcpip_thread context. */ void pppapi_sighup(ppp_pcb *pcb) { struct pppapi_msg msg; msg.function = pppapi_do_ppp_sighup; msg.msg.ppp = pcb; TCPIP_PPPAPI(&msg); } /** * Call ppp_delete() inside the tcpip_thread context. */ static void pppapi_do_ppp_delete(struct pppapi_msg_msg *msg) { msg->err = ppp_delete(msg->ppp); TCPIP_PPPAPI_ACK(msg); } /** * Call ppp_delete() in a thread-safe way by running that function inside the * tcpip_thread context. */ int pppapi_delete(ppp_pcb *pcb) { struct pppapi_msg msg; msg.function = pppapi_do_ppp_delete; msg.msg.ppp = pcb; TCPIP_PPPAPI(&msg); return msg.msg.err; } /** * Call ppp_ioctl() inside the tcpip_thread context. */ static void pppapi_do_ppp_ioctl(struct pppapi_msg_msg *msg) { msg->err = ppp_ioctl(msg->ppp, msg->msg.ioctl.cmd, msg->msg.ioctl.arg); TCPIP_PPPAPI_ACK(msg); } /** * Call ppp_ioctl() in a thread-safe way by running that function inside the * tcpip_thread context. */ int pppapi_ioctl(ppp_pcb *pcb, int cmd, void *arg) { struct pppapi_msg msg; msg.function = pppapi_do_ppp_ioctl; msg.msg.ppp = pcb; msg.msg.msg.ioctl.cmd = cmd; msg.msg.msg.ioctl.arg = arg; TCPIP_PPPAPI(&msg); return msg.msg.err; } #if LWIP_NETIF_STATUS_CALLBACK /** * Call ppp_set_netif_statuscallback() inside the tcpip_thread context. */ static void pppapi_do_ppp_set_netif_statuscallback(struct pppapi_msg_msg *msg) { ppp_set_netif_statuscallback(msg->ppp, msg->msg.netifstatuscallback.status_callback); TCPIP_PPPAPI_ACK(msg); } /** * Call ppp_set_netif_statuscallback() in a thread-safe way by running that function inside the * tcpip_thread context. */ void pppapi_set_netif_statuscallback(ppp_pcb *pcb, netif_status_callback_fn status_callback) { struct pppapi_msg msg; msg.function = pppapi_do_ppp_set_netif_statuscallback; msg.msg.ppp = pcb; msg.msg.msg.netifstatuscallback.status_callback = status_callback; TCPIP_PPPAPI(&msg); } #endif /* LWIP_NETIF_STATUS_CALLBACK */ #if LWIP_NETIF_LINK_CALLBACK /** * Call ppp_set_netif_linkcallback() inside the tcpip_thread context. */ static void pppapi_do_ppp_set_netif_linkcallback(struct pppapi_msg_msg *msg) { ppp_set_netif_linkcallback(msg->ppp, msg->msg.netiflinkcallback.link_callback); TCPIP_PPPAPI_ACK(msg); } /** * Call ppp_set_netif_linkcallback() in a thread-safe way by running that function inside the * tcpip_thread context. */ void pppapi_set_netif_linkcallback(ppp_pcb *pcb, netif_status_callback_fn link_callback) { struct pppapi_msg msg; msg.function = pppapi_do_ppp_set_netif_linkcallback; msg.msg.ppp = pcb; msg.msg.msg.netiflinkcallback.link_callback = link_callback; TCPIP_PPPAPI(&msg); } #endif /* LWIP_NETIF_LINK_CALLBACK */ #endif /* LWIP_PPP_API */ ocproxy-1.60/lwip/src/api/sockets.c000066400000000000000000002363741303453231400173120ustar00rootroot00000000000000/** * @file * Sockets BSD-Like API module * */ /* * Copyright (c) 2001-2004 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * * Improved by Marc Boucher and David Haas * */ #include "lwip/opt.h" #if LWIP_SOCKET /* don't build if not configured for use in lwipopts.h */ #include "lwip/sockets.h" #include "lwip/api.h" #include "lwip/sys.h" #include "lwip/igmp.h" #include "lwip/inet.h" #include "lwip/tcp.h" #include "lwip/raw.h" #include "lwip/udp.h" #include "lwip/tcpip.h" #include "lwip/memp.h" #include "lwip/pbuf.h" #if LWIP_CHECKSUM_ON_COPY #include "lwip/inet_chksum.h" #endif #include #define IP4ADDR_PORT_TO_SOCKADDR(sin, ipXaddr, port) do { \ (sin)->sin_len = sizeof(struct sockaddr_in); \ (sin)->sin_family = AF_INET; \ (sin)->sin_port = htons((port)); \ inet_addr_from_ipaddr(&(sin)->sin_addr, ipX_2_ip(ipXaddr)); \ memset((sin)->sin_zero, 0, SIN_ZERO_LEN); }while(0) #define SOCKADDR4_TO_IP4ADDR_PORT(sin, ipXaddr, port) do { \ inet_addr_to_ipaddr(ipX_2_ip(ipXaddr), &((sin)->sin_addr)); \ (port) = ntohs((sin)->sin_port); }while(0) #if LWIP_IPV6 #define IS_SOCK_ADDR_LEN_VALID(namelen) (((namelen) == sizeof(struct sockaddr_in)) || \ ((namelen) == sizeof(struct sockaddr_in6))) #define IS_SOCK_ADDR_TYPE_VALID(name) (((name)->sa_family == AF_INET) || \ ((name)->sa_family == AF_INET6)) #define SOCK_ADDR_TYPE_MATCH(name, sock) \ ((((name)->sa_family == AF_INET) && !(NETCONNTYPE_ISIPV6((sock)->conn->type))) || \ (((name)->sa_family == AF_INET6) && (NETCONNTYPE_ISIPV6((sock)->conn->type)))) #define IP6ADDR_PORT_TO_SOCKADDR(sin6, ipXaddr, port) do { \ (sin6)->sin6_len = sizeof(struct sockaddr_in6); \ (sin6)->sin6_family = AF_INET6; \ (sin6)->sin6_port = htons((port)); \ (sin6)->sin6_flowinfo = 0; \ inet6_addr_from_ip6addr(&(sin6)->sin6_addr, ipX_2_ip6(ipXaddr)); }while(0) #define IPXADDR_PORT_TO_SOCKADDR(isipv6, sockaddr, ipXaddr, port) do { \ if (isipv6) { \ IP6ADDR_PORT_TO_SOCKADDR((struct sockaddr_in6*)(void*)(sockaddr), ipXaddr, port); \ } else { \ IP4ADDR_PORT_TO_SOCKADDR((struct sockaddr_in*)(void*)(sockaddr), ipXaddr, port); \ } } while(0) #define SOCKADDR6_TO_IP6ADDR_PORT(sin6, ipXaddr, port) do { \ inet6_addr_to_ip6addr(ipX_2_ip6(ipXaddr), &((sin6)->sin6_addr)); \ (port) = ntohs((sin6)->sin6_port); }while(0) #define SOCKADDR_TO_IPXADDR_PORT(isipv6, sockaddr, ipXaddr, port) do { \ if (isipv6) { \ SOCKADDR6_TO_IP6ADDR_PORT((struct sockaddr_in6*)(void*)(sockaddr), ipXaddr, port); \ } else { \ SOCKADDR4_TO_IP4ADDR_PORT((struct sockaddr_in*)(void*)(sockaddr), ipXaddr, port); \ } } while(0) #define DOMAIN_TO_NETCONN_TYPE(domain, type) (((domain) == AF_INET) ? \ (type) : (enum netconn_type)((type) | NETCONN_TYPE_IPV6)) #else /* LWIP_IPV6 */ #define IS_SOCK_ADDR_LEN_VALID(namelen) ((namelen) == sizeof(struct sockaddr_in)) #define IS_SOCK_ADDR_TYPE_VALID(name) ((name)->sa_family == AF_INET) #define SOCK_ADDR_TYPE_MATCH(name, sock) 1 #define IPXADDR_PORT_TO_SOCKADDR(isipv6, sockaddr, ipXaddr, port) \ IP4ADDR_PORT_TO_SOCKADDR((struct sockaddr_in*)(void*)(sockaddr), ipXaddr, port) #define SOCKADDR_TO_IPXADDR_PORT(isipv6, sockaddr, ipXaddr, port) \ SOCKADDR4_TO_IP4ADDR_PORT((struct sockaddr_in*)(void*)(sockaddr), ipXaddr, port) #define DOMAIN_TO_NETCONN_TYPE(domain, netconn_type) (netconn_type) #endif /* LWIP_IPV6 */ #define IS_SOCK_ADDR_TYPE_VALID_OR_UNSPEC(name) (((name)->sa_family == AF_UNSPEC) || \ IS_SOCK_ADDR_TYPE_VALID(name)) #define SOCK_ADDR_TYPE_MATCH_OR_UNSPEC(name, sock) (((name)->sa_family == AF_UNSPEC) || \ SOCK_ADDR_TYPE_MATCH(name, sock)) #define IS_SOCK_ADDR_ALIGNED(name) ((((mem_ptr_t)(name)) % 4) == 0) #define LWIP_SETGETSOCKOPT_DATA_VAR_REF(name) API_VAR_REF(name) #define LWIP_SETGETSOCKOPT_DATA_VAR_DECLARE(name) API_VAR_DECLARE(struct lwip_setgetsockopt_data, name) #define LWIP_SETGETSOCKOPT_DATA_VAR_FREE(name) API_VAR_FREE(MEMP_SOCKET_SETGETSOCKOPT_DATA, name) #if LWIP_MPU_COMPATIBLE #define LWIP_SETGETSOCKOPT_DATA_VAR_ALLOC(name, sock) do { \ name = (struct lwip_setgetsockopt_data *)memp_malloc(MEMP_SOCKET_SETGETSOCKOPT_DATA); \ if (name == NULL) { \ sock_set_errno(sock, ERR_MEM); \ return -1; \ } }while(0) #else /* LWIP_MPU_COMPATIBLE */ #define LWIP_SETGETSOCKOPT_DATA_VAR_ALLOC(name, sock) #endif /* LWIP_MPU_COMPATIBLE */ #define NUM_SOCKETS MEMP_NUM_NETCONN /** Contains all internal pointers and states used for a socket */ struct lwip_sock { /** sockets currently are built on netconns, each socket has one netconn */ struct netconn *conn; /** data that was left from the previous read */ void *lastdata; /** offset in the data that was left from the previous read */ u16_t lastoffset; /** number of times data was received, set by event_callback(), tested by the receive and select functions */ s16_t rcvevent; /** number of times data was ACKed (free send buffer), set by event_callback(), tested by select */ u16_t sendevent; /** error happened for this socket, set by event_callback(), tested by select */ u16_t errevent; /** last error that occurred on this socket */ int err; /** counter of how many threads are waiting for this socket using select */ int select_waiting; }; /** Description for a task waiting in select */ struct lwip_select_cb { /** Pointer to the next waiting task */ struct lwip_select_cb *next; /** Pointer to the previous waiting task */ struct lwip_select_cb *prev; /** readset passed to select */ fd_set *readset; /** writeset passed to select */ fd_set *writeset; /** unimplemented: exceptset passed to select */ fd_set *exceptset; /** don't signal the same semaphore twice: set to 1 when signalled */ int sem_signalled; /** semaphore to wake up a task waiting for select */ sys_sem_t sem; }; /** A struct sockaddr replacement that has the same alignment as sockaddr_in/ * sockaddr_in6 if instantiated. */ union sockaddr_aligned { struct sockaddr sa; #if LWIP_IPV6 struct sockaddr_in6 sin6; #endif /* LWIP_IPV6 */ struct sockaddr_in sin; }; /** The global array of available sockets */ static struct lwip_sock sockets[NUM_SOCKETS]; /** The global list of tasks waiting for select */ static struct lwip_select_cb *select_cb_list; /** This counter is increased from lwip_select when the list is chagned and checked in event_callback to see if it has changed. */ static volatile int select_cb_ctr; /** Table to quickly map an lwIP error (err_t) to a socket error * by using -err as an index */ static const int err_to_errno_table[] = { 0, /* ERR_OK 0 No error, everything OK. */ ENOMEM, /* ERR_MEM -1 Out of memory error. */ ENOBUFS, /* ERR_BUF -2 Buffer error. */ EWOULDBLOCK, /* ERR_TIMEOUT -3 Timeout */ EHOSTUNREACH, /* ERR_RTE -4 Routing problem. */ EINPROGRESS, /* ERR_INPROGRESS -5 Operation in progress */ EINVAL, /* ERR_VAL -6 Illegal value. */ EWOULDBLOCK, /* ERR_WOULDBLOCK -7 Operation would block. */ EADDRINUSE, /* ERR_USE -8 Address in use. */ EALREADY, /* ERR_ISCONN -9 Already connected. */ ECONNABORTED, /* ERR_ABRT -10 Connection aborted. */ ECONNRESET, /* ERR_RST -11 Connection reset. */ ENOTCONN, /* ERR_CLSD -12 Connection closed. */ ENOTCONN, /* ERR_CONN -13 Not connected. */ EIO, /* ERR_ARG -14 Illegal argument. */ -1, /* ERR_IF -15 Low-level netif error */ }; #define ERR_TO_ERRNO_TABLE_SIZE \ (sizeof(err_to_errno_table)/sizeof(err_to_errno_table[0])) #define err_to_errno(err) \ ((unsigned)(-(err)) < ERR_TO_ERRNO_TABLE_SIZE ? \ err_to_errno_table[-(err)] : EIO) #if LWIP_SOCKET_SET_ERRNO #ifndef set_errno #define set_errno(err) do { if (err) { errno = (err); } } while(0) #endif #else /* LWIP_SOCKET_SET_ERRNO */ #define set_errno(err) #endif /* LWIP_SOCKET_SET_ERRNO */ #define sock_set_errno(sk, e) do { \ sk->err = (e); \ set_errno(sk->err); \ } while (0) /* Forward delcaration of some functions */ static void event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len); static void lwip_getsockopt_internal(void *arg); static void lwip_setsockopt_internal(void *arg); /** * Initialize this module. This function has to be called before any other * functions in this module! */ void lwip_socket_init(void) { } /** * Map a externally used socket index to the internal socket representation. * * @param s externally used socket index * @return struct lwip_sock for the socket or NULL if not found */ static struct lwip_sock * get_socket(int s) { struct lwip_sock *sock; if ((s < 0) || (s >= NUM_SOCKETS)) { LWIP_DEBUGF(SOCKETS_DEBUG, ("get_socket(%d): invalid\n", s)); set_errno(EBADF); return NULL; } sock = &sockets[s]; if (!sock->conn) { LWIP_DEBUGF(SOCKETS_DEBUG, ("get_socket(%d): not active\n", s)); set_errno(EBADF); return NULL; } return sock; } /** * Same as get_socket but doesn't set errno * * @param s externally used socket index * @return struct lwip_sock for the socket or NULL if not found */ static struct lwip_sock * tryget_socket(int s) { if ((s < 0) || (s >= NUM_SOCKETS)) { return NULL; } if (!sockets[s].conn) { return NULL; } return &sockets[s]; } /** * Allocate a new socket for a given netconn. * * @param newconn the netconn for which to allocate a socket * @param accepted 1 if socket has been created by accept(), * 0 if socket has been created by socket() * @return the index of the new socket; -1 on error */ static int alloc_socket(struct netconn *newconn, int accepted) { int i; SYS_ARCH_DECL_PROTECT(lev); /* allocate a new socket identifier */ for (i = 0; i < NUM_SOCKETS; ++i) { /* Protect socket array */ SYS_ARCH_PROTECT(lev); if (!sockets[i].conn) { sockets[i].conn = newconn; /* The socket is not yet known to anyone, so no need to protect after having marked it as used. */ SYS_ARCH_UNPROTECT(lev); sockets[i].lastdata = NULL; sockets[i].lastoffset = 0; sockets[i].rcvevent = 0; /* TCP sendbuf is empty, but the socket is not yet writable until connected * (unless it has been created by accept()). */ sockets[i].sendevent = (NETCONNTYPE_GROUP(newconn->type) == NETCONN_TCP ? (accepted != 0) : 1); sockets[i].errevent = 0; sockets[i].err = 0; sockets[i].select_waiting = 0; return i; } SYS_ARCH_UNPROTECT(lev); } return -1; } /** Free a socket. The socket's netconn must have been * delete before! * * @param sock the socket to free * @param is_tcp != 0 for TCP sockets, used to free lastdata */ static void free_socket(struct lwip_sock *sock, int is_tcp) { void *lastdata; SYS_ARCH_DECL_PROTECT(lev); lastdata = sock->lastdata; sock->lastdata = NULL; sock->lastoffset = 0; sock->err = 0; /* Protect socket array */ SYS_ARCH_PROTECT(lev); sock->conn = NULL; SYS_ARCH_UNPROTECT(lev); /* don't use 'sock' after this line, as another task might have allocated it */ if (lastdata != NULL) { if (is_tcp) { pbuf_free((struct pbuf *)lastdata); } else { netbuf_delete((struct netbuf *)lastdata); } } } /* Below this, the well-known socket functions are implemented. * Use google.com or opengroup.org to get a good description :-) * * Exceptions are documented! */ int lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen) { struct lwip_sock *sock, *nsock; struct netconn *newconn; ipX_addr_t naddr; u16_t port = 0; int newsock; err_t err; SYS_ARCH_DECL_PROTECT(lev); LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d)...\n", s)); sock = get_socket(s); if (!sock) { return -1; } if (netconn_is_nonblocking(sock->conn) && (sock->rcvevent <= 0)) { LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): returning EWOULDBLOCK\n", s)); sock_set_errno(sock, EWOULDBLOCK); return -1; } /* wait for a new connection */ err = netconn_accept(sock->conn, &newconn); if (err != ERR_OK) { LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): netconn_acept failed, err=%d\n", s, err)); if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) { sock_set_errno(sock, EOPNOTSUPP); return EOPNOTSUPP; } sock_set_errno(sock, err_to_errno(err)); return -1; } LWIP_ASSERT("newconn != NULL", newconn != NULL); /* Prevent automatic window updates, we do this on our own! */ netconn_set_noautorecved(newconn, 1); /* Note that POSIX only requires us to check addr is non-NULL. addrlen must * not be NULL if addr is valid. */ if (addr != NULL) { union sockaddr_aligned tempaddr; /* get the IP address and port of the remote host */ err = netconn_peer(newconn, ipX_2_ip(&naddr), &port); if (err != ERR_OK) { LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): netconn_peer failed, err=%d\n", s, err)); netconn_delete(newconn); sock_set_errno(sock, err_to_errno(err)); return -1; } LWIP_ASSERT("addr valid but addrlen NULL", addrlen != NULL); IPXADDR_PORT_TO_SOCKADDR(NETCONNTYPE_ISIPV6(newconn->type), &tempaddr, &naddr, port); if (*addrlen > tempaddr.sa.sa_len) { *addrlen = tempaddr.sa.sa_len; } MEMCPY(addr, &tempaddr, *addrlen); } newsock = alloc_socket(newconn, 1); if (newsock == -1) { netconn_delete(newconn); sock_set_errno(sock, ENFILE); return -1; } LWIP_ASSERT("invalid socket index", (newsock >= 0) && (newsock < NUM_SOCKETS)); LWIP_ASSERT("newconn->callback == event_callback", newconn->callback == event_callback); nsock = &sockets[newsock]; /* See event_callback: If data comes in right away after an accept, even * though the server task might not have created a new socket yet. * In that case, newconn->socket is counted down (newconn->socket--), * so nsock->rcvevent is >= 1 here! */ SYS_ARCH_PROTECT(lev); nsock->rcvevent += (s16_t)(-1 - newconn->socket); newconn->socket = newsock; SYS_ARCH_UNPROTECT(lev); LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d) returning new sock=%d", s, newsock)); if (addr != NULL) { LWIP_DEBUGF(SOCKETS_DEBUG, (" addr=")); ipX_addr_debug_print(NETCONNTYPE_ISIPV6(newconn->type), SOCKETS_DEBUG, &naddr); LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F"\n", port)); } sock_set_errno(sock, 0); return newsock; } int lwip_bind(int s, const struct sockaddr *name, socklen_t namelen) { struct lwip_sock *sock; ipX_addr_t local_addr; u16_t local_port; err_t err; sock = get_socket(s); if (!sock) { return -1; } if (!SOCK_ADDR_TYPE_MATCH(name, sock)) { /* sockaddr does not match socket type (IPv4/IPv6) */ sock_set_errno(sock, err_to_errno(ERR_VAL)); return -1; } /* check size, familiy and alignment of 'name' */ LWIP_ERROR("lwip_bind: invalid address", (IS_SOCK_ADDR_LEN_VALID(namelen) && IS_SOCK_ADDR_TYPE_VALID(name) && IS_SOCK_ADDR_ALIGNED(name)), sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;); LWIP_UNUSED_ARG(namelen); SOCKADDR_TO_IPXADDR_PORT((name->sa_family == AF_INET6), name, &local_addr, local_port); LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d, addr=", s)); ipX_addr_debug_print(name->sa_family == AF_INET6, SOCKETS_DEBUG, &local_addr); LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", local_port)); err = netconn_bind(sock->conn, ipX_2_ip(&local_addr), local_port); if (err != ERR_OK) { LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d) failed, err=%d\n", s, err)); sock_set_errno(sock, err_to_errno(err)); return -1; } LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d) succeeded\n", s)); sock_set_errno(sock, 0); return 0; } int lwip_close(int s) { struct lwip_sock *sock; int is_tcp = 0; LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_close(%d)\n", s)); sock = get_socket(s); if (!sock) { return -1; } if(sock->conn != NULL) { is_tcp = NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP; } else { LWIP_ASSERT("sock->lastdata == NULL", sock->lastdata == NULL); } netconn_delete(sock->conn); free_socket(sock, is_tcp); set_errno(0); return 0; } int lwip_connect(int s, const struct sockaddr *name, socklen_t namelen) { struct lwip_sock *sock; err_t err; sock = get_socket(s); if (!sock) { return -1; } if (!SOCK_ADDR_TYPE_MATCH_OR_UNSPEC(name, sock)) { /* sockaddr does not match socket type (IPv4/IPv6) */ sock_set_errno(sock, err_to_errno(ERR_VAL)); return -1; } LWIP_UNUSED_ARG(namelen); if (name->sa_family == AF_UNSPEC) { LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, AF_UNSPEC)\n", s)); err = netconn_disconnect(sock->conn); } else { ipX_addr_t remote_addr; u16_t remote_port; /* check size, familiy and alignment of 'name' */ LWIP_ERROR("lwip_connect: invalid address", IS_SOCK_ADDR_LEN_VALID(namelen) && IS_SOCK_ADDR_TYPE_VALID_OR_UNSPEC(name) && IS_SOCK_ADDR_ALIGNED(name), sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;); SOCKADDR_TO_IPXADDR_PORT((name->sa_family == AF_INET6), name, &remote_addr, remote_port); LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, addr=", s)); ipX_addr_debug_print(name->sa_family == AF_INET6, SOCKETS_DEBUG, &remote_addr); LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", remote_port)); err = netconn_connect(sock->conn, ipX_2_ip(&remote_addr), remote_port); } if (err != ERR_OK) { LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d) failed, err=%d\n", s, err)); sock_set_errno(sock, err_to_errno(err)); return -1; } LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d) succeeded\n", s)); sock_set_errno(sock, 0); return 0; } /** * Set a socket into listen mode. * The socket may not have been used for another connection previously. * * @param s the socket to set to listening mode * @param backlog (ATTENTION: needs TCP_LISTEN_BACKLOG=1) * @return 0 on success, non-zero on failure */ int lwip_listen(int s, int backlog) { struct lwip_sock *sock; err_t err; LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_listen(%d, backlog=%d)\n", s, backlog)); sock = get_socket(s); if (!sock) { return -1; } /* limit the "backlog" parameter to fit in an u8_t */ backlog = LWIP_MIN(LWIP_MAX(backlog, 0), 0xff); err = netconn_listen_with_backlog(sock->conn, (u8_t)backlog); if (err != ERR_OK) { LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_listen(%d) failed, err=%d\n", s, err)); if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) { sock_set_errno(sock, EOPNOTSUPP); return -1; } sock_set_errno(sock, err_to_errno(err)); return -1; } sock_set_errno(sock, 0); return 0; } int lwip_recvfrom(int s, void *mem, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen) { struct lwip_sock *sock; void *buf = NULL; struct pbuf *p; u16_t buflen, copylen; int off = 0; u8_t done = 0; err_t err; LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d, %p, %"SZT_F", 0x%x, ..)\n", s, mem, len, flags)); sock = get_socket(s); if (!sock) { return -1; } do { LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: top while sock->lastdata=%p\n", sock->lastdata)); /* Check if there is data left from the last recv operation. */ if (sock->lastdata) { buf = sock->lastdata; } else { /* If this is non-blocking call, then check first */ if (((flags & MSG_DONTWAIT) || netconn_is_nonblocking(sock->conn)) && (sock->rcvevent <= 0)) { if (off > 0) { /* update receive window */ netconn_recved(sock->conn, (u32_t)off); /* already received data, return that */ sock_set_errno(sock, 0); return off; } LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): returning EWOULDBLOCK\n", s)); sock_set_errno(sock, EWOULDBLOCK); return -1; } /* No data was left from the previous operation, so we try to get some from the network. */ if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) { err = netconn_recv_tcp_pbuf(sock->conn, (struct pbuf **)&buf); } else { err = netconn_recv(sock->conn, (struct netbuf **)&buf); } LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: netconn_recv err=%d, netbuf=%p\n", err, buf)); if (err != ERR_OK) { if (off > 0) { /* update receive window */ netconn_recved(sock->conn, (u32_t)off); /* already received data, return that */ sock_set_errno(sock, 0); return off; } /* We should really do some error checking here. */ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): buf == NULL, error is \"%s\"!\n", s, lwip_strerr(err))); sock_set_errno(sock, err_to_errno(err)); if (err == ERR_CLSD) { return 0; } else { return -1; } } LWIP_ASSERT("buf != NULL", buf != NULL); sock->lastdata = buf; } if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) { p = (struct pbuf *)buf; } else { p = ((struct netbuf *)buf)->p; } buflen = p->tot_len; LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: buflen=%"U16_F" len=%"SZT_F" off=%d sock->lastoffset=%"U16_F"\n", buflen, len, off, sock->lastoffset)); buflen -= sock->lastoffset; if (len > buflen) { copylen = buflen; } else { copylen = (u16_t)len; } /* copy the contents of the received buffer into the supplied memory pointer mem */ pbuf_copy_partial(p, (u8_t*)mem + off, copylen, sock->lastoffset); off += copylen; if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) { LWIP_ASSERT("invalid copylen, len would underflow", len >= copylen); len -= copylen; if ( (len <= 0) || (p->flags & PBUF_FLAG_PUSH) || (sock->rcvevent <= 0) || ((flags & MSG_PEEK)!=0)) { done = 1; } } else { done = 1; } /* Check to see from where the data was.*/ if (done) { #if !SOCKETS_DEBUG if (from && fromlen) #endif /* !SOCKETS_DEBUG */ { u16_t port; ipX_addr_t tmpaddr; ipX_addr_t *fromaddr; union sockaddr_aligned saddr; LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): addr=", s)); if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) { fromaddr = &tmpaddr; /* @todo: this does not work for IPv6, yet */ netconn_getaddr(sock->conn, ipX_2_ip(fromaddr), &port, 0); } else { port = netbuf_fromport((struct netbuf *)buf); fromaddr = netbuf_fromaddr_ipX((struct netbuf *)buf); } IPXADDR_PORT_TO_SOCKADDR(NETCONNTYPE_ISIPV6(netconn_type(sock->conn)), &saddr, fromaddr, port); ipX_addr_debug_print(NETCONNTYPE_ISIPV6(netconn_type(sock->conn)), SOCKETS_DEBUG, fromaddr); LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F" len=%d\n", port, off)); #if SOCKETS_DEBUG if (from && fromlen) #endif /* SOCKETS_DEBUG */ { if (*fromlen > saddr.sa.sa_len) { *fromlen = saddr.sa.sa_len; } MEMCPY(from, &saddr, *fromlen); } } } /* If we don't peek the incoming message... */ if ((flags & MSG_PEEK) == 0) { /* If this is a TCP socket, check if there is data left in the buffer. If so, it should be saved in the sock structure for next time around. */ if ((NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) && (buflen - copylen > 0)) { sock->lastdata = buf; sock->lastoffset += copylen; LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: lastdata now netbuf=%p\n", buf)); } else { sock->lastdata = NULL; sock->lastoffset = 0; LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: deleting netbuf=%p\n", buf)); if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) { pbuf_free((struct pbuf *)buf); } else { netbuf_delete((struct netbuf *)buf); } } } } while (!done); if ((off > 0) && (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP)) { /* update receive window */ netconn_recved(sock->conn, (u32_t)off); } sock_set_errno(sock, 0); return off; } int lwip_read(int s, void *mem, size_t len) { return lwip_recvfrom(s, mem, len, 0, NULL, NULL); } int lwip_recv(int s, void *mem, size_t len, int flags) { return lwip_recvfrom(s, mem, len, flags, NULL, NULL); } int lwip_send(int s, const void *data, size_t size, int flags) { struct lwip_sock *sock; err_t err; u8_t write_flags; size_t written; LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d, data=%p, size=%"SZT_F", flags=0x%x)\n", s, data, size, flags)); sock = get_socket(s); if (!sock) { return -1; } if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) { #if (LWIP_UDP || LWIP_RAW) return lwip_sendto(s, data, size, flags, NULL, 0); #else /* (LWIP_UDP || LWIP_RAW) */ sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1; #endif /* (LWIP_UDP || LWIP_RAW) */ } write_flags = NETCONN_COPY | ((flags & MSG_MORE) ? NETCONN_MORE : 0) | ((flags & MSG_DONTWAIT) ? NETCONN_DONTBLOCK : 0); written = 0; err = netconn_write_partly(sock->conn, data, size, write_flags, &written); LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d) err=%d written=%"SZT_F"\n", s, err, written)); sock_set_errno(sock, err_to_errno(err)); return (err == ERR_OK ? (int)written : -1); } int lwip_sendto(int s, const void *data, size_t size, int flags, const struct sockaddr *to, socklen_t tolen) { struct lwip_sock *sock; err_t err; u16_t short_size; u16_t remote_port; #if !LWIP_TCPIP_CORE_LOCKING struct netbuf buf; #endif sock = get_socket(s); if (!sock) { return -1; } if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) { #if LWIP_TCP return lwip_send(s, data, size, flags); #else /* LWIP_TCP */ LWIP_UNUSED_ARG(flags); sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1; #endif /* LWIP_TCP */ } if ((to != NULL) && !SOCK_ADDR_TYPE_MATCH(to, sock)) { /* sockaddr does not match socket type (IPv4/IPv6) */ sock_set_errno(sock, err_to_errno(ERR_VAL)); return -1; } /* @todo: split into multiple sendto's? */ LWIP_ASSERT("lwip_sendto: size must fit in u16_t", size <= 0xffff); short_size = (u16_t)size; LWIP_ERROR("lwip_sendto: invalid address", (((to == NULL) && (tolen == 0)) || (IS_SOCK_ADDR_LEN_VALID(tolen) && IS_SOCK_ADDR_TYPE_VALID(to) && IS_SOCK_ADDR_ALIGNED(to))), sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;); LWIP_UNUSED_ARG(tolen); #if LWIP_TCPIP_CORE_LOCKING /* Special speedup for fast UDP/RAW sending: call the raw API directly instead of using the netconn functions. */ { struct pbuf* p; ipX_addr_t *remote_addr; ipX_addr_t remote_addr_tmp; #if LWIP_NETIF_TX_SINGLE_PBUF p = pbuf_alloc(PBUF_TRANSPORT, short_size, PBUF_RAM); if (p != NULL) { #if LWIP_CHECKSUM_ON_COPY u16_t chksum = 0; if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_RAW) { chksum = LWIP_CHKSUM_COPY(p->payload, data, short_size); } else #endif /* LWIP_CHECKSUM_ON_COPY */ MEMCPY(p->payload, data, size); #else /* LWIP_NETIF_TX_SINGLE_PBUF */ p = pbuf_alloc(PBUF_TRANSPORT, short_size, PBUF_REF); if (p != NULL) { p->payload = (void*)data; #endif /* LWIP_NETIF_TX_SINGLE_PBUF */ if (to != NULL) { SOCKADDR_TO_IPXADDR_PORT(to->sa_family == AF_INET6, to, &remote_addr_tmp, remote_port); remote_addr = &remote_addr_tmp; } else { remote_addr = &sock->conn->pcb.ip->remote_ip; #if LWIP_UDP if (NETCONNTYPE_GROUP(sock->conn->type) == NETCONN_UDP) { remote_port = sock->conn->pcb.udp->remote_port; } else #endif /* LWIP_UDP */ { remote_port = 0; } } LOCK_TCPIP_CORE(); if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_RAW) { #if LWIP_RAW err = sock->conn->last_err = raw_sendto(sock->conn->pcb.raw, p, ipX_2_ip(remote_addr)); #else /* LWIP_RAW */ err = ERR_ARG; #endif /* LWIP_RAW */ } #if LWIP_UDP && LWIP_RAW else #endif /* LWIP_UDP && LWIP_RAW */ { #if LWIP_UDP #if LWIP_CHECKSUM_ON_COPY && LWIP_NETIF_TX_SINGLE_PBUF err = sock->conn->last_err = udp_sendto_chksum(sock->conn->pcb.udp, p, ipX_2_ip(remote_addr), remote_port, 1, chksum); #else /* LWIP_CHECKSUM_ON_COPY && LWIP_NETIF_TX_SINGLE_PBUF */ err = sock->conn->last_err = udp_sendto(sock->conn->pcb.udp, p, ipX_2_ip(remote_addr), remote_port); #endif /* LWIP_CHECKSUM_ON_COPY && LWIP_NETIF_TX_SINGLE_PBUF */ #else /* LWIP_UDP */ err = ERR_ARG; #endif /* LWIP_UDP */ } UNLOCK_TCPIP_CORE(); pbuf_free(p); } else { err = ERR_MEM; } } #else /* LWIP_TCPIP_CORE_LOCKING */ /* initialize a buffer */ buf.p = buf.ptr = NULL; #if LWIP_CHECKSUM_ON_COPY buf.flags = 0; #endif /* LWIP_CHECKSUM_ON_COPY */ if (to) { SOCKADDR_TO_IPXADDR_PORT((to->sa_family) == AF_INET6, to, &buf.addr, remote_port); } else { remote_port = 0; ipX_addr_set_any(NETCONNTYPE_ISIPV6(netconn_type(sock->conn)), &buf.addr); } netbuf_fromport(&buf) = remote_port; LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_sendto(%d, data=%p, short_size=%"U16_F", flags=0x%x to=", s, data, short_size, flags)); ipX_addr_debug_print(NETCONNTYPE_ISIPV6(netconn_type(sock->conn)), SOCKETS_DEBUG, &buf.addr); LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F"\n", remote_port)); /* make the buffer point to the data that should be sent */ #if LWIP_NETIF_TX_SINGLE_PBUF /* Allocate a new netbuf and copy the data into it. */ if (netbuf_alloc(&buf, short_size) == NULL) { err = ERR_MEM; } else { #if LWIP_CHECKSUM_ON_COPY if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_RAW) { u16_t chksum = LWIP_CHKSUM_COPY(buf.p->payload, data, short_size); netbuf_set_chksum(&buf, chksum); err = ERR_OK; } else #endif /* LWIP_CHECKSUM_ON_COPY */ { err = netbuf_take(&buf, data, short_size); } } #else /* LWIP_NETIF_TX_SINGLE_PBUF */ err = netbuf_ref(&buf, data, short_size); #endif /* LWIP_NETIF_TX_SINGLE_PBUF */ if (err == ERR_OK) { /* send the data */ err = netconn_send(sock->conn, &buf); } /* deallocated the buffer */ netbuf_free(&buf); #endif /* LWIP_TCPIP_CORE_LOCKING */ sock_set_errno(sock, err_to_errno(err)); return (err == ERR_OK ? short_size : -1); } int lwip_socket(int domain, int type, int protocol) { struct netconn *conn; int i; #if !LWIP_IPV6 LWIP_UNUSED_ARG(domain); /* @todo: check this */ #endif /* LWIP_IPV6 */ /* create a netconn */ switch (type) { case SOCK_RAW: conn = netconn_new_with_proto_and_callback(DOMAIN_TO_NETCONN_TYPE(domain, NETCONN_RAW), (u8_t)protocol, event_callback); LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_RAW, %d) = ", domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol)); break; case SOCK_DGRAM: conn = netconn_new_with_callback(DOMAIN_TO_NETCONN_TYPE(domain, ((protocol == IPPROTO_UDPLITE) ? NETCONN_UDPLITE : NETCONN_UDP)) , event_callback); LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_DGRAM, %d) = ", domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol)); break; case SOCK_STREAM: conn = netconn_new_with_callback(DOMAIN_TO_NETCONN_TYPE(domain, NETCONN_TCP), event_callback); LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_STREAM, %d) = ", domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol)); if (conn != NULL) { /* Prevent automatic window updates, we do this on our own! */ netconn_set_noautorecved(conn, 1); } break; default: LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%d, %d/UNKNOWN, %d) = -1\n", domain, type, protocol)); set_errno(EINVAL); return -1; } if (!conn) { LWIP_DEBUGF(SOCKETS_DEBUG, ("-1 / ENOBUFS (could not create netconn)\n")); set_errno(ENOBUFS); return -1; } i = alloc_socket(conn, 0); if (i == -1) { netconn_delete(conn); set_errno(ENFILE); return -1; } conn->socket = i; LWIP_DEBUGF(SOCKETS_DEBUG, ("%d\n", i)); set_errno(0); return i; } int lwip_write(int s, const void *data, size_t size) { return lwip_send(s, data, size, 0); } /** * Go through the readset and writeset lists and see which socket of the sockets * set in the sets has events. On return, readset, writeset and exceptset have * the sockets enabled that had events. * * exceptset is not used for now!!! * * @param maxfdp1 the highest socket index in the sets * @param readset_in: set of sockets to check for read events * @param writeset_in: set of sockets to check for write events * @param exceptset_in: set of sockets to check for error events * @param readset_out: set of sockets that had read events * @param writeset_out: set of sockets that had write events * @param exceptset_out: set os sockets that had error events * @return number of sockets that had events (read/write/exception) (>= 0) */ static int lwip_selscan(int maxfdp1, fd_set *readset_in, fd_set *writeset_in, fd_set *exceptset_in, fd_set *readset_out, fd_set *writeset_out, fd_set *exceptset_out) { int i, nready = 0; fd_set lreadset, lwriteset, lexceptset; struct lwip_sock *sock; SYS_ARCH_DECL_PROTECT(lev); FD_ZERO(&lreadset); FD_ZERO(&lwriteset); FD_ZERO(&lexceptset); /* Go through each socket in each list to count number of sockets which currently match */ for(i = 0; i < maxfdp1; i++) { void* lastdata = NULL; s16_t rcvevent = 0; u16_t sendevent = 0; u16_t errevent = 0; /* First get the socket's status (protected)... */ SYS_ARCH_PROTECT(lev); sock = tryget_socket(i); if (sock != NULL) { lastdata = sock->lastdata; rcvevent = sock->rcvevent; sendevent = sock->sendevent; errevent = sock->errevent; } SYS_ARCH_UNPROTECT(lev); /* ... then examine it: */ /* See if netconn of this socket is ready for read */ if (readset_in && FD_ISSET(i, readset_in) && ((lastdata != NULL) || (rcvevent > 0))) { FD_SET(i, &lreadset); LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for reading\n", i)); nready++; } /* See if netconn of this socket is ready for write */ if (writeset_in && FD_ISSET(i, writeset_in) && (sendevent != 0)) { FD_SET(i, &lwriteset); LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for writing\n", i)); nready++; } /* See if netconn of this socket had an error */ if (exceptset_in && FD_ISSET(i, exceptset_in) && (errevent != 0)) { FD_SET(i, &lexceptset); LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for exception\n", i)); nready++; } } /* copy local sets to the ones provided as arguments */ *readset_out = lreadset; *writeset_out = lwriteset; *exceptset_out = lexceptset; LWIP_ASSERT("nready >= 0", nready >= 0); return nready; } /** * Processing exceptset is not yet implemented. */ int lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset, struct timeval *timeout) { u32_t waitres = 0; int nready; fd_set lreadset, lwriteset, lexceptset; u32_t msectimeout; struct lwip_select_cb select_cb; err_t err; int i; SYS_ARCH_DECL_PROTECT(lev); LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select(%d, %p, %p, %p, tvsec=%"S32_F" tvusec=%"S32_F")\n", maxfdp1, (void *)readset, (void *) writeset, (void *) exceptset, timeout ? (s32_t)timeout->tv_sec : (s32_t)-1, timeout ? (s32_t)timeout->tv_usec : (s32_t)-1)); /* Go through each socket in each list to count number of sockets which currently match */ nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset); /* If we don't have any current events, then suspend if we are supposed to */ if (!nready) { if (timeout && timeout->tv_sec == 0 && timeout->tv_usec == 0) { LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: no timeout, returning 0\n")); /* This is OK as the local fdsets are empty and nready is zero, or we would have returned earlier. */ goto return_copy_fdsets; } /* None ready: add our semaphore to list: We don't actually need any dynamic memory. Our entry on the list is only valid while we are in this function, so it's ok to use local variables. */ select_cb.next = NULL; select_cb.prev = NULL; select_cb.readset = readset; select_cb.writeset = writeset; select_cb.exceptset = exceptset; select_cb.sem_signalled = 0; err = sys_sem_new(&select_cb.sem, 0); if (err != ERR_OK) { /* failed to create semaphore */ set_errno(ENOMEM); return -1; } /* Protect the select_cb_list */ SYS_ARCH_PROTECT(lev); /* Put this select_cb on top of list */ select_cb.next = select_cb_list; if (select_cb_list != NULL) { select_cb_list->prev = &select_cb; } select_cb_list = &select_cb; /* Increasing this counter tells even_callback that the list has changed. */ select_cb_ctr++; /* Now we can safely unprotect */ SYS_ARCH_UNPROTECT(lev); /* Increase select_waiting for each socket we are interested in */ for(i = 0; i < maxfdp1; i++) { if ((readset && FD_ISSET(i, readset)) || (writeset && FD_ISSET(i, writeset)) || (exceptset && FD_ISSET(i, exceptset))) { struct lwip_sock *sock = tryget_socket(i); LWIP_ASSERT("sock != NULL", sock != NULL); SYS_ARCH_PROTECT(lev); sock->select_waiting++; LWIP_ASSERT("sock->select_waiting > 0", sock->select_waiting > 0); SYS_ARCH_UNPROTECT(lev); } } /* Call lwip_selscan again: there could have been events between the last scan (whithout us on the list) and putting us on the list! */ nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset); if (!nready) { /* Still none ready, just wait to be woken */ if (timeout == 0) { /* Wait forever */ msectimeout = 0; } else { msectimeout = ((timeout->tv_sec * 1000) + ((timeout->tv_usec + 500)/1000)); if (msectimeout == 0) { /* Wait 1ms at least (0 means wait forever) */ msectimeout = 1; } } waitres = sys_arch_sem_wait(&select_cb.sem, msectimeout); } /* Increase select_waiting for each socket we are interested in */ for(i = 0; i < maxfdp1; i++) { if ((readset && FD_ISSET(i, readset)) || (writeset && FD_ISSET(i, writeset)) || (exceptset && FD_ISSET(i, exceptset))) { struct lwip_sock *sock = tryget_socket(i); LWIP_ASSERT("sock != NULL", sock != NULL); SYS_ARCH_PROTECT(lev); sock->select_waiting--; LWIP_ASSERT("sock->select_waiting >= 0", sock->select_waiting >= 0); SYS_ARCH_UNPROTECT(lev); } } /* Take us off the list */ SYS_ARCH_PROTECT(lev); if (select_cb.next != NULL) { select_cb.next->prev = select_cb.prev; } if (select_cb_list == &select_cb) { LWIP_ASSERT("select_cb.prev == NULL", select_cb.prev == NULL); select_cb_list = select_cb.next; } else { LWIP_ASSERT("select_cb.prev != NULL", select_cb.prev != NULL); select_cb.prev->next = select_cb.next; } /* Increasing this counter tells even_callback that the list has changed. */ select_cb_ctr++; SYS_ARCH_UNPROTECT(lev); sys_sem_free(&select_cb.sem); if (waitres == SYS_ARCH_TIMEOUT) { /* Timeout */ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: timeout expired\n")); /* This is OK as the local fdsets are empty and nready is zero, or we would have returned earlier. */ goto return_copy_fdsets; } /* See what's set */ nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset); } LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: nready=%d\n", nready)); return_copy_fdsets: set_errno(0); if (readset) { *readset = lreadset; } if (writeset) { *writeset = lwriteset; } if (exceptset) { *exceptset = lexceptset; } return nready; } /** * Callback registered in the netconn layer for each socket-netconn. * Processes recvevent (data available) and wakes up tasks waiting for select. */ static void event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len) { int s; struct lwip_sock *sock; struct lwip_select_cb *scb; int last_select_cb_ctr; SYS_ARCH_DECL_PROTECT(lev); LWIP_UNUSED_ARG(len); /* Get socket */ if (conn) { s = conn->socket; if (s < 0) { /* Data comes in right away after an accept, even though * the server task might not have created a new socket yet. * Just count down (or up) if that's the case and we * will use the data later. Note that only receive events * can happen before the new socket is set up. */ SYS_ARCH_PROTECT(lev); if (conn->socket < 0) { if (evt == NETCONN_EVT_RCVPLUS) { conn->socket--; } SYS_ARCH_UNPROTECT(lev); return; } s = conn->socket; SYS_ARCH_UNPROTECT(lev); } sock = get_socket(s); if (!sock) { return; } } else { return; } SYS_ARCH_PROTECT(lev); /* Set event as required */ switch (evt) { case NETCONN_EVT_RCVPLUS: sock->rcvevent++; break; case NETCONN_EVT_RCVMINUS: sock->rcvevent--; break; case NETCONN_EVT_SENDPLUS: sock->sendevent = 1; break; case NETCONN_EVT_SENDMINUS: sock->sendevent = 0; break; case NETCONN_EVT_ERROR: sock->errevent = 1; break; default: LWIP_ASSERT("unknown event", 0); break; } if (sock->select_waiting == 0) { /* noone is waiting for this socket, no need to check select_cb_list */ SYS_ARCH_UNPROTECT(lev); return; } /* Now decide if anyone is waiting for this socket */ /* NOTE: This code goes through the select_cb_list list multiple times ONLY IF a select was actually waiting. We go through the list the number of waiting select calls + 1. This list is expected to be small. */ /* At this point, SYS_ARCH is still protected! */ again: for (scb = select_cb_list; scb != NULL; scb = scb->next) { if (scb->sem_signalled == 0) { /* semaphore not signalled yet */ int do_signal = 0; /* Test this select call for our socket */ if (sock->rcvevent > 0) { if (scb->readset && FD_ISSET(s, scb->readset)) { do_signal = 1; } } if (sock->sendevent != 0) { if (!do_signal && scb->writeset && FD_ISSET(s, scb->writeset)) { do_signal = 1; } } if (sock->errevent != 0) { if (!do_signal && scb->exceptset && FD_ISSET(s, scb->exceptset)) { do_signal = 1; } } if (do_signal) { scb->sem_signalled = 1; /* Don't call SYS_ARCH_UNPROTECT() before signaling the semaphore, as this might lead to the select thread taking itself off the list, invalidagin the semaphore. */ sys_sem_signal(&scb->sem); } } /* unlock interrupts with each step */ last_select_cb_ctr = select_cb_ctr; SYS_ARCH_UNPROTECT(lev); /* this makes sure interrupt protection time is short */ SYS_ARCH_PROTECT(lev); if (last_select_cb_ctr != select_cb_ctr) { /* someone has changed select_cb_list, restart at the beginning */ goto again; } } SYS_ARCH_UNPROTECT(lev); } /** * Unimplemented: Close one end of a full-duplex connection. * Currently, the full connection is closed. */ int lwip_shutdown(int s, int how) { struct lwip_sock *sock; err_t err; u8_t shut_rx = 0, shut_tx = 0; LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_shutdown(%d, how=%d)\n", s, how)); sock = get_socket(s); if (!sock) { return -1; } if (sock->conn != NULL) { if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) { sock_set_errno(sock, EOPNOTSUPP); return -1; } } else { sock_set_errno(sock, ENOTCONN); return -1; } if (how == SHUT_RD) { shut_rx = 1; } else if (how == SHUT_WR) { shut_tx = 1; } else if(how == SHUT_RDWR) { shut_rx = 1; shut_tx = 1; } else { sock_set_errno(sock, EINVAL); return -1; } err = netconn_shutdown(sock->conn, shut_rx, shut_tx); sock_set_errno(sock, err_to_errno(err)); return (err == ERR_OK ? 0 : -1); } static int lwip_getaddrname(int s, struct sockaddr *name, socklen_t *namelen, u8_t local) { struct lwip_sock *sock; union sockaddr_aligned saddr; ipX_addr_t naddr; u16_t port; err_t err; sock = get_socket(s); if (!sock) { return -1; } /* get the IP address and port */ /* @todo: this does not work for IPv6, yet */ err = netconn_getaddr(sock->conn, ipX_2_ip(&naddr), &port, local); if (err != ERR_OK) { sock_set_errno(sock, err_to_errno(err)); return -1; } IPXADDR_PORT_TO_SOCKADDR(NETCONNTYPE_ISIPV6(netconn_type(sock->conn)), &saddr, &naddr, port); LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getaddrname(%d, addr=", s)); ipX_addr_debug_print(NETCONNTYPE_ISIPV6(netconn_type(sock->conn)), SOCKETS_DEBUG, &naddr); LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", port)); if (*namelen > saddr.sa.sa_len) { *namelen = saddr.sa.sa_len; } MEMCPY(name, &saddr, *namelen); sock_set_errno(sock, 0); return 0; } int lwip_getpeername(int s, struct sockaddr *name, socklen_t *namelen) { return lwip_getaddrname(s, name, namelen, 0); } int lwip_getsockname(int s, struct sockaddr *name, socklen_t *namelen) { return lwip_getaddrname(s, name, namelen, 1); } int lwip_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen) { err_t err = ERR_OK; struct lwip_sock *sock = get_socket(s); LWIP_SETGETSOCKOPT_DATA_VAR_DECLARE(data); if (!sock) { return -1; } if ((NULL == optval) || (NULL == optlen)) { sock_set_errno(sock, EFAULT); return -1; } /* Do length and type checks for the various options first, to keep it readable. */ switch (level) { /* Level: SOL_SOCKET */ case SOL_SOCKET: switch (optname) { case SO_ACCEPTCONN: case SO_BROADCAST: /* UNIMPL case SO_DEBUG: */ /* UNIMPL case SO_DONTROUTE: */ case SO_ERROR: case SO_KEEPALIVE: /* UNIMPL case SO_CONTIMEO: */ #if LWIP_SO_SNDTIMEO case SO_SNDTIMEO: #endif /* LWIP_SO_SNDTIMEO */ #if LWIP_SO_RCVTIMEO case SO_RCVTIMEO: #endif /* LWIP_SO_RCVTIMEO */ #if LWIP_SO_RCVBUF case SO_RCVBUF: #endif /* LWIP_SO_RCVBUF */ /* UNIMPL case SO_OOBINLINE: */ /* UNIMPL case SO_SNDBUF: */ /* UNIMPL case SO_RCVLOWAT: */ /* UNIMPL case SO_SNDLOWAT: */ #if SO_REUSE case SO_REUSEADDR: case SO_REUSEPORT: #endif /* SO_REUSE */ case SO_TYPE: /* UNIMPL case SO_USELOOPBACK: */ if (*optlen < sizeof(int)) { err = EINVAL; } break; case SO_NO_CHECK: if (*optlen < sizeof(int)) { err = EINVAL; } #if LWIP_UDP if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_UDP || ((udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_UDPLITE) != 0)) { /* this flag is only available for UDP, not for UDP lite */ err = EAFNOSUPPORT; } #endif /* LWIP_UDP */ break; default: LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, UNIMPL: optname=0x%x, ..)\n", s, optname)); err = ENOPROTOOPT; } /* switch (optname) */ break; /* Level: IPPROTO_IP */ case IPPROTO_IP: switch (optname) { /* UNIMPL case IP_HDRINCL: */ /* UNIMPL case IP_RCVDSTADDR: */ /* UNIMPL case IP_RCVIF: */ case IP_TTL: case IP_TOS: if (*optlen < sizeof(int)) { err = EINVAL; } break; #if LWIP_IGMP case IP_MULTICAST_TTL: if (*optlen < sizeof(u8_t)) { err = EINVAL; } break; case IP_MULTICAST_IF: if (*optlen < sizeof(struct in_addr)) { err = EINVAL; } break; case IP_MULTICAST_LOOP: if (*optlen < sizeof(u8_t)) { err = EINVAL; } if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_UDP) { err = EAFNOSUPPORT; } break; #endif /* LWIP_IGMP */ default: LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, UNIMPL: optname=0x%x, ..)\n", s, optname)); err = ENOPROTOOPT; } /* switch (optname) */ break; #if LWIP_TCP /* Level: IPPROTO_TCP */ case IPPROTO_TCP: if (*optlen < sizeof(int)) { err = EINVAL; break; } /* If this is no TCP socket, ignore any options. */ if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) return 0; switch (optname) { case TCP_NODELAY: case TCP_KEEPALIVE: #if LWIP_TCP_KEEPALIVE case TCP_KEEPIDLE: case TCP_KEEPINTVL: case TCP_KEEPCNT: #endif /* LWIP_TCP_KEEPALIVE */ break; default: LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, UNIMPL: optname=0x%x, ..)\n", s, optname)); err = ENOPROTOOPT; } /* switch (optname) */ break; #endif /* LWIP_TCP */ #if LWIP_IPV6 /* Level: IPPROTO_IPV6 */ case IPPROTO_IPV6: switch (optname) { case IPV6_V6ONLY: if (*optlen < sizeof(int)) { err = EINVAL; } /* @todo: this does not work for datagram sockets, yet */ if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) return 0; break; default: LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IPV6, UNIMPL: optname=0x%x, ..)\n", s, optname)); err = ENOPROTOOPT; } /* switch (optname) */ break; #endif /* LWIP_IPV6 */ #if LWIP_UDP && LWIP_UDPLITE /* Level: IPPROTO_UDPLITE */ case IPPROTO_UDPLITE: if (*optlen < sizeof(int)) { err = EINVAL; break; } /* If this is no UDP lite socket, ignore any options. */ if (!NETCONNTYPE_ISUDPLITE(netconn_type(sock->conn))) { return 0; } switch (optname) { case UDPLITE_SEND_CSCOV: case UDPLITE_RECV_CSCOV: break; default: LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UNIMPL: optname=0x%x, ..)\n", s, optname)); err = ENOPROTOOPT; } /* switch (optname) */ break; #endif /* LWIP_UDP && LWIP_UDPLITE*/ /* Level: IPPROTO_RAW */ case IPPROTO_RAW: switch (optname) { #if LWIP_IPV6 case IPV6_CHECKSUM: if (*optlen < sizeof(int)) { err = EINVAL; break; } #endif /* LWIP_IPV6 */ default: LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_RAW, UNIMPL: optname=0x%x, ..)\n", s, optname)); err = ENOPROTOOPT; } /* switch (optname) */ break; /* UNDEFINED LEVEL */ default: LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, level=0x%x, UNIMPL: optname=0x%x, ..)\n", s, level, optname)); err = ENOPROTOOPT; } /* switch */ if (err != ERR_OK) { sock_set_errno(sock, err); return -1; } /* Now do the actual option processing */ LWIP_SETGETSOCKOPT_DATA_VAR_ALLOC(data, sock); LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).sock = sock; #ifdef LWIP_DEBUG LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).s = s; #endif /* LWIP_DEBUG */ LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).level = level; LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optname = optname; LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optval = optval; LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optlen = optlen; LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).err = err; tcpip_callback(lwip_getsockopt_internal, &LWIP_SETGETSOCKOPT_DATA_VAR_REF(data)); sys_arch_sem_wait(&sock->conn->op_completed, 0); /* maybe lwip_getsockopt_internal has changed err */ err = LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).err; LWIP_SETGETSOCKOPT_DATA_VAR_FREE(data); sock_set_errno(sock, err); return err ? -1 : 0; } static void lwip_getsockopt_internal(void *arg) { struct lwip_sock *sock; #ifdef LWIP_DEBUG int s; #endif /* LWIP_DEBUG */ int level, optname; void *optval; struct lwip_setgetsockopt_data *data; LWIP_ASSERT("arg != NULL", arg != NULL); data = (struct lwip_setgetsockopt_data*)arg; sock = data->sock; #ifdef LWIP_DEBUG s = data->s; #endif /* LWIP_DEBUG */ level = data->level; optname = data->optname; optval = data->optval; switch (level) { /* Level: SOL_SOCKET */ case SOL_SOCKET: switch (optname) { /* The option flags */ case SO_ACCEPTCONN: case SO_BROADCAST: /* UNIMPL case SO_DEBUG: */ /* UNIMPL case SO_DONTROUTE: */ case SO_KEEPALIVE: /* UNIMPL case SO_OOBINCLUDE: */ #if SO_REUSE case SO_REUSEADDR: case SO_REUSEPORT: #endif /* SO_REUSE */ /*case SO_USELOOPBACK: UNIMPL */ *(int*)optval = ip_get_option(sock->conn->pcb.ip, optname); LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, optname=0x%x, ..) = %s\n", s, optname, (*(int*)optval?"on":"off"))); break; case SO_TYPE: switch (NETCONNTYPE_GROUP(netconn_type(sock->conn))) { case NETCONN_RAW: *(int*)optval = SOCK_RAW; break; case NETCONN_TCP: *(int*)optval = SOCK_STREAM; break; case NETCONN_UDP: *(int*)optval = SOCK_DGRAM; break; default: /* unrecognized socket type */ *(int*)optval = netconn_type(sock->conn); LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, SO_TYPE): unrecognized socket type %d\n", s, *(int *)optval)); } /* switch (netconn_type(sock->conn)) */ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, SO_TYPE) = %d\n", s, *(int *)optval)); break; case SO_ERROR: /* only overwrite ERR_OK or tempoary errors */ if ((sock->err == 0) || (sock->err == EINPROGRESS)) { sock_set_errno(sock, err_to_errno(sock->conn->last_err)); } *(int *)optval = sock->err; sock->err = 0; LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, SO_ERROR) = %d\n", s, *(int *)optval)); break; #if LWIP_SO_SNDTIMEO case SO_SNDTIMEO: *(int *)optval = netconn_get_sendtimeout(sock->conn); break; #endif /* LWIP_SO_SNDTIMEO */ #if LWIP_SO_RCVTIMEO case SO_RCVTIMEO: *(int *)optval = netconn_get_recvtimeout(sock->conn); break; #endif /* LWIP_SO_RCVTIMEO */ #if LWIP_SO_RCVBUF case SO_RCVBUF: *(int *)optval = netconn_get_recvbufsize(sock->conn); break; #endif /* LWIP_SO_RCVBUF */ #if LWIP_UDP case SO_NO_CHECK: *(int*)optval = (udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_NOCHKSUM) ? 1 : 0; break; #endif /* LWIP_UDP*/ default: LWIP_ASSERT("unhandled optname", 0); break; } /* switch (optname) */ break; /* Level: IPPROTO_IP */ case IPPROTO_IP: switch (optname) { case IP_TTL: *(int*)optval = sock->conn->pcb.ip->ttl; LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_TTL) = %d\n", s, *(int *)optval)); break; case IP_TOS: *(int*)optval = sock->conn->pcb.ip->tos; LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_TOS) = %d\n", s, *(int *)optval)); break; #if LWIP_IGMP case IP_MULTICAST_TTL: *(u8_t*)optval = sock->conn->pcb.ip->ttl; LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_TTL) = %d\n", s, *(int *)optval)); break; case IP_MULTICAST_IF: inet_addr_from_ipaddr((struct in_addr*)optval, &sock->conn->pcb.udp->multicast_ip); LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_IF) = 0x%"X32_F"\n", s, *(u32_t *)optval)); break; case IP_MULTICAST_LOOP: if ((sock->conn->pcb.udp->flags & UDP_FLAGS_MULTICAST_LOOP) != 0) { *(u8_t*)optval = 1; } else { *(u8_t*)optval = 0; } LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_LOOP) = %d\n", s, *(int *)optval)); break; #endif /* LWIP_IGMP */ default: LWIP_ASSERT("unhandled optname", 0); break; } /* switch (optname) */ break; #if LWIP_TCP /* Level: IPPROTO_TCP */ case IPPROTO_TCP: switch (optname) { case TCP_NODELAY: *(int*)optval = tcp_nagle_disabled(sock->conn->pcb.tcp); LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_NODELAY) = %s\n", s, (*(int*)optval)?"on":"off") ); break; case TCP_KEEPALIVE: *(int*)optval = (int)sock->conn->pcb.tcp->keep_idle; LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, TCP_KEEPALIVE) = %d\n", s, *(int *)optval)); break; #if LWIP_TCP_KEEPALIVE case TCP_KEEPIDLE: *(int*)optval = (int)(sock->conn->pcb.tcp->keep_idle/1000); LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, TCP_KEEPIDLE) = %d\n", s, *(int *)optval)); break; case TCP_KEEPINTVL: *(int*)optval = (int)(sock->conn->pcb.tcp->keep_intvl/1000); LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, TCP_KEEPINTVL) = %d\n", s, *(int *)optval)); break; case TCP_KEEPCNT: *(int*)optval = (int)sock->conn->pcb.tcp->keep_cnt; LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, TCP_KEEPCNT) = %d\n", s, *(int *)optval)); break; #endif /* LWIP_TCP_KEEPALIVE */ default: LWIP_ASSERT("unhandled optname", 0); break; } /* switch (optname) */ break; #endif /* LWIP_TCP */ #if LWIP_IPV6 /* Level: IPPROTO_IPV6 */ case IPPROTO_IPV6: switch (optname) { case IPV6_V6ONLY: *(int*)optval = ((sock->conn->flags & NETCONN_FLAG_IPV6_V6ONLY) ? 1 : 0); LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IPV6, IPV6_V6ONLY) = %d\n", s, *(int *)optval)); break; default: LWIP_ASSERT("unhandled optname", 0); break; } /* switch (optname) */ break; #endif /* LWIP_IPV6 */ #if LWIP_UDP && LWIP_UDPLITE /* Level: IPPROTO_UDPLITE */ case IPPROTO_UDPLITE: switch (optname) { case UDPLITE_SEND_CSCOV: *(int*)optval = sock->conn->pcb.udp->chksum_len_tx; LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UDPLITE_SEND_CSCOV) = %d\n", s, (*(int*)optval)) ); break; case UDPLITE_RECV_CSCOV: *(int*)optval = sock->conn->pcb.udp->chksum_len_rx; LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UDPLITE_RECV_CSCOV) = %d\n", s, (*(int*)optval)) ); break; default: LWIP_ASSERT("unhandled optname", 0); break; } /* switch (optname) */ break; #endif /* LWIP_UDP */ /* Level: IPPROTO_RAW */ case IPPROTO_RAW: switch (optname) { #if LWIP_IPV6 case IPV6_CHECKSUM: if (sock->conn->pcb.raw->chksum_reqd == 0) { *(int *)optval = -1; } else { *(int *)optval = sock->conn->pcb.raw->chksum_offset; } LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_RAW, IPV6_CHECKSUM) = %d\n", s, (*(int*)optval)) ); break; #endif /* LWIP_IPV6 */ default: LWIP_ASSERT("unhandled optname", 0); break; } /* switch (optname) */ break; default: LWIP_ASSERT("unhandled level", 0); break; } /* switch (level) */ sys_sem_signal(&sock->conn->op_completed); } int lwip_setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen) { struct lwip_sock *sock = get_socket(s); err_t err = ERR_OK; LWIP_SETGETSOCKOPT_DATA_VAR_DECLARE(data); if (!sock) { return -1; } if (NULL == optval) { sock_set_errno(sock, EFAULT); return -1; } /* Do length and type checks for the various options first, to keep it readable. */ switch (level) { /* Level: SOL_SOCKET */ case SOL_SOCKET: switch (optname) { case SO_BROADCAST: /* UNIMPL case SO_DEBUG: */ /* UNIMPL case SO_DONTROUTE: */ case SO_KEEPALIVE: /* UNIMPL case case SO_CONTIMEO: */ #if LWIP_SO_SNDTIMEO case SO_SNDTIMEO: #endif /* LWIP_SO_SNDTIMEO */ #if LWIP_SO_RCVTIMEO case SO_RCVTIMEO: #endif /* LWIP_SO_RCVTIMEO */ #if LWIP_SO_RCVBUF case SO_RCVBUF: #endif /* LWIP_SO_RCVBUF */ /* UNIMPL case SO_OOBINLINE: */ /* UNIMPL case SO_SNDBUF: */ /* UNIMPL case SO_RCVLOWAT: */ /* UNIMPL case SO_SNDLOWAT: */ #if SO_REUSE case SO_REUSEADDR: case SO_REUSEPORT: #endif /* SO_REUSE */ /* UNIMPL case SO_USELOOPBACK: */ if (optlen < sizeof(int)) { err = EINVAL; } break; case SO_NO_CHECK: if (optlen < sizeof(int)) { err = EINVAL; } #if LWIP_UDP if ((NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_UDP) || ((udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_UDPLITE) != 0)) { /* this flag is only available for UDP, not for UDP lite */ err = EAFNOSUPPORT; } #endif /* LWIP_UDP */ break; default: LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, SOL_SOCKET, UNIMPL: optname=0x%x, ..)\n", s, optname)); err = ENOPROTOOPT; } /* switch (optname) */ break; /* Level: IPPROTO_IP */ case IPPROTO_IP: switch (optname) { /* UNIMPL case IP_HDRINCL: */ /* UNIMPL case IP_RCVDSTADDR: */ /* UNIMPL case IP_RCVIF: */ case IP_TTL: case IP_TOS: if (optlen < sizeof(int)) { err = EINVAL; } break; #if LWIP_IGMP case IP_MULTICAST_TTL: if (optlen < sizeof(u8_t)) { err = EINVAL; } if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_UDP) { err = EAFNOSUPPORT; } break; case IP_MULTICAST_IF: if (optlen < sizeof(struct in_addr)) { err = EINVAL; } if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_UDP) { err = EAFNOSUPPORT; } break; case IP_MULTICAST_LOOP: if (optlen < sizeof(u8_t)) { err = EINVAL; } if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_UDP) { err = EAFNOSUPPORT; } break; case IP_ADD_MEMBERSHIP: case IP_DROP_MEMBERSHIP: if (optlen < sizeof(struct ip_mreq)) { err = EINVAL; } if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_UDP) { err = EAFNOSUPPORT; } break; #endif /* LWIP_IGMP */ default: LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, UNIMPL: optname=0x%x, ..)\n", s, optname)); err = ENOPROTOOPT; } /* switch (optname) */ break; #if LWIP_TCP /* Level: IPPROTO_TCP */ case IPPROTO_TCP: if (optlen < sizeof(int)) { err = EINVAL; break; } /* If this is no TCP socket, ignore any options. */ if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) return 0; switch (optname) { case TCP_NODELAY: case TCP_KEEPALIVE: #if LWIP_TCP_KEEPALIVE case TCP_KEEPIDLE: case TCP_KEEPINTVL: case TCP_KEEPCNT: #endif /* LWIP_TCP_KEEPALIVE */ break; default: LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, UNIMPL: optname=0x%x, ..)\n", s, optname)); err = ENOPROTOOPT; } /* switch (optname) */ break; #endif /* LWIP_TCP */ #if LWIP_IPV6 /* Level: IPPROTO_IPV6 */ case IPPROTO_IPV6: switch (optname) { case IPV6_V6ONLY: if (optlen < sizeof(int)) { err = EINVAL; } /* @todo: this does not work for datagram sockets, yet */ if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) { return 0; } break; case IPV6_CHECKSUM: err = EINVAL; break; default: LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IPV6, UNIMPL: optname=0x%x, ..)\n", s, optname)); err = ENOPROTOOPT; } /* switch (optname) */ break; case IPPROTO_ICMPV6: switch (optname) { case IPV6_CHECKSUM: err = EINVAL; break; default: LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_ICMPV6, UNIMPL: optname=0x%x, ..)\n", s, optname)); err = ENOPROTOOPT; } /* switch (optname) */ break; #endif /* LWIP_IPV6 */ #if LWIP_UDP && LWIP_UDPLITE /* Level: IPPROTO_UDPLITE */ case IPPROTO_UDPLITE: if (optlen < sizeof(int)) { err = EINVAL; break; } /* If this is no UDP lite socket, ignore any options. */ if (!NETCONNTYPE_ISUDPLITE(netconn_type(sock->conn))) { return 0; } switch (optname) { case UDPLITE_SEND_CSCOV: case UDPLITE_RECV_CSCOV: break; default: LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UNIMPL: optname=0x%x, ..)\n", s, optname)); err = ENOPROTOOPT; } /* switch (optname) */ break; #endif /* LWIP_UDP && LWIP_UDPLITE */ /* Level: IPPROTO_RAW */ case IPPROTO_RAW: switch (optname) { #if LWIP_IPV6 case IPV6_CHECKSUM: /* Per RFC3542, odd offsets are not allowed */ if ((*(int *)optval > 0) && (*(int *)optval & 1)) { err = EINVAL; } break; #endif /* LWIP_IPV6 */ default: LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_RAW, UNIMPL: optname=0x%x, ..)\n", s, optname)); err = ENOPROTOOPT; } /* switch (optname) */ break; /* UNDEFINED LEVEL */ default: LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, level=0x%x, UNIMPL: optname=0x%x, ..)\n", s, level, optname)); err = ENOPROTOOPT; } /* switch (level) */ if (err != ERR_OK) { sock_set_errno(sock, err); return -1; } /* Now do the actual option processing */ LWIP_SETGETSOCKOPT_DATA_VAR_ALLOC(data, sock); LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).sock = sock; #ifdef LWIP_DEBUG LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).s = s; #endif /* LWIP_DEBUG */ LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).level = level; LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optname = optname; LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optval = (void*)optval; LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optlen = &optlen; LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).err = err; tcpip_callback(lwip_setsockopt_internal, &LWIP_SETGETSOCKOPT_DATA_VAR_REF(data)); sys_arch_sem_wait(&sock->conn->op_completed, 0); /* maybe lwip_setsockopt_internal has changed err */ err = LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).err; LWIP_SETGETSOCKOPT_DATA_VAR_FREE(data); sock_set_errno(sock, err); return err ? -1 : 0; } static void lwip_setsockopt_internal(void *arg) { struct lwip_sock *sock; #ifdef LWIP_DEBUG int s; #endif /* LWIP_DEBUG */ int level, optname; const void *optval; struct lwip_setgetsockopt_data *data; LWIP_ASSERT("arg != NULL", arg != NULL); data = (struct lwip_setgetsockopt_data*)arg; sock = data->sock; #ifdef LWIP_DEBUG s = data->s; #endif /* LWIP_DEBUG */ level = data->level; optname = data->optname; optval = data->optval; switch (level) { /* Level: SOL_SOCKET */ case SOL_SOCKET: switch (optname) { /* The option flags */ case SO_BROADCAST: /* UNIMPL case SO_DEBUG: */ /* UNIMPL case SO_DONTROUTE: */ case SO_KEEPALIVE: /* UNIMPL case SO_OOBINCLUDE: */ #if SO_REUSE case SO_REUSEADDR: case SO_REUSEPORT: #endif /* SO_REUSE */ /* UNIMPL case SO_USELOOPBACK: */ if (*(int*)optval) { ip_set_option(sock->conn->pcb.ip, optname); } else { ip_reset_option(sock->conn->pcb.ip, optname); } LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, SOL_SOCKET, optname=0x%x, ..) -> %s\n", s, optname, (*(int*)optval?"on":"off"))); break; #if LWIP_SO_SNDTIMEO case SO_SNDTIMEO: netconn_set_sendtimeout(sock->conn, (s32_t)*(int*)optval); break; #endif /* LWIP_SO_SNDTIMEO */ #if LWIP_SO_RCVTIMEO case SO_RCVTIMEO: netconn_set_recvtimeout(sock->conn, *(int*)optval); break; #endif /* LWIP_SO_RCVTIMEO */ #if LWIP_SO_RCVBUF case SO_RCVBUF: netconn_set_recvbufsize(sock->conn, *(int*)optval); break; #endif /* LWIP_SO_RCVBUF */ #if LWIP_UDP case SO_NO_CHECK: if (*(int*)optval) { udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) | UDP_FLAGS_NOCHKSUM); } else { udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) & ~UDP_FLAGS_NOCHKSUM); } break; #endif /* LWIP_UDP */ default: LWIP_ASSERT("unhandled optname", 0); break; } /* switch (optname) */ break; /* Level: IPPROTO_IP */ case IPPROTO_IP: switch (optname) { case IP_TTL: sock->conn->pcb.ip->ttl = (u8_t)(*(int*)optval); LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, IP_TTL, ..) -> %d\n", s, sock->conn->pcb.ip->ttl)); break; case IP_TOS: sock->conn->pcb.ip->tos = (u8_t)(*(int*)optval); LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, IP_TOS, ..)-> %d\n", s, sock->conn->pcb.ip->tos)); break; #if LWIP_IGMP case IP_MULTICAST_TTL: sock->conn->pcb.udp->ttl = (u8_t)(*(u8_t*)optval); break; case IP_MULTICAST_IF: inet_addr_to_ipaddr(&sock->conn->pcb.udp->multicast_ip, (struct in_addr*)optval); break; case IP_MULTICAST_LOOP: if (*(u8_t*)optval) { udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) | UDP_FLAGS_MULTICAST_LOOP); } else { udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) & ~UDP_FLAGS_MULTICAST_LOOP); } break; case IP_ADD_MEMBERSHIP: case IP_DROP_MEMBERSHIP: { /* If this is a TCP or a RAW socket, ignore these options. */ struct ip_mreq *imr = (struct ip_mreq *)optval; ip_addr_t if_addr; ip_addr_t multi_addr; inet_addr_to_ipaddr(&if_addr, &imr->imr_interface); inet_addr_to_ipaddr(&multi_addr, &imr->imr_multiaddr); if(optname == IP_ADD_MEMBERSHIP){ data->err = igmp_joingroup(&if_addr, &multi_addr); } else { data->err = igmp_leavegroup(&if_addr, &multi_addr); } if(data->err != ERR_OK) { data->err = EADDRNOTAVAIL; } } break; #endif /* LWIP_IGMP */ default: LWIP_ASSERT("unhandled optname", 0); break; } /* switch (optname) */ break; #if LWIP_TCP /* Level: IPPROTO_TCP */ case IPPROTO_TCP: switch (optname) { case TCP_NODELAY: if (*(int*)optval) { tcp_nagle_disable(sock->conn->pcb.tcp); } else { tcp_nagle_enable(sock->conn->pcb.tcp); } LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_NODELAY) -> %s\n", s, (*(int *)optval)?"on":"off") ); break; case TCP_KEEPALIVE: sock->conn->pcb.tcp->keep_idle = (u32_t)(*(int*)optval); LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPALIVE) -> %"U32_F"\n", s, sock->conn->pcb.tcp->keep_idle)); break; #if LWIP_TCP_KEEPALIVE case TCP_KEEPIDLE: sock->conn->pcb.tcp->keep_idle = 1000*(u32_t)(*(int*)optval); LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPIDLE) -> %"U32_F"\n", s, sock->conn->pcb.tcp->keep_idle)); break; case TCP_KEEPINTVL: sock->conn->pcb.tcp->keep_intvl = 1000*(u32_t)(*(int*)optval); LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPINTVL) -> %"U32_F"\n", s, sock->conn->pcb.tcp->keep_intvl)); break; case TCP_KEEPCNT: sock->conn->pcb.tcp->keep_cnt = (u32_t)(*(int*)optval); LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPCNT) -> %"U32_F"\n", s, sock->conn->pcb.tcp->keep_cnt)); break; #endif /* LWIP_TCP_KEEPALIVE */ default: LWIP_ASSERT("unhandled optname", 0); break; } /* switch (optname) */ break; #endif /* LWIP_TCP*/ #if LWIP_IPV6 /* Level: IPPROTO_IPV6 */ case IPPROTO_IPV6: switch (optname) { case IPV6_V6ONLY: if (*(int*)optval) { sock->conn->flags |= NETCONN_FLAG_IPV6_V6ONLY; } else { sock->conn->flags &= ~NETCONN_FLAG_IPV6_V6ONLY; } LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IPV6, IPV6_V6ONLY, ..) -> %d\n", s, ((sock->conn->flags & NETCONN_FLAG_IPV6_V6ONLY) ? 1 : 0))); break; default: LWIP_ASSERT("unhandled optname", 0); break; } /* switch (optname) */ break; #endif /* LWIP_IPV6 */ #if LWIP_UDP && LWIP_UDPLITE /* Level: IPPROTO_UDPLITE */ case IPPROTO_UDPLITE: switch (optname) { case UDPLITE_SEND_CSCOV: if ((*(int*)optval != 0) && ((*(int*)optval < 8) || (*(int*)optval > 0xffff))) { /* don't allow illegal values! */ sock->conn->pcb.udp->chksum_len_tx = 8; } else { sock->conn->pcb.udp->chksum_len_tx = (u16_t)*(int*)optval; } LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UDPLITE_SEND_CSCOV) -> %d\n", s, (*(int*)optval)) ); break; case UDPLITE_RECV_CSCOV: if ((*(int*)optval != 0) && ((*(int*)optval < 8) || (*(int*)optval > 0xffff))) { /* don't allow illegal values! */ sock->conn->pcb.udp->chksum_len_rx = 8; } else { sock->conn->pcb.udp->chksum_len_rx = (u16_t)*(int*)optval; } LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UDPLITE_RECV_CSCOV) -> %d\n", s, (*(int*)optval)) ); break; default: LWIP_ASSERT("unhandled optname", 0); break; } /* switch (optname) */ break; #endif /* LWIP_UDP */ /* Level: IPPROTO_RAW */ case IPPROTO_RAW: switch (optname) { #if LWIP_IPV6 case IPV6_CHECKSUM: if (*(int *)optval < 0) { sock->conn->pcb.raw->chksum_reqd = 0; } else { sock->conn->pcb.raw->chksum_reqd = 1; sock->conn->pcb.raw->chksum_offset = *(int *)optval; } LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_RAW, IPV6_CHECKSUM, ..) -> %d\n", s, sock->conn->pcb.raw->chksum_reqd)); break; #endif /* LWIP_IPV6 */ default: LWIP_ASSERT("unhandled optname", 0); break; } /* switch (optname) */ break; default: LWIP_ASSERT("unhandled level", 0); break; } /* switch (level) */ sys_sem_signal(&sock->conn->op_completed); } int lwip_ioctl(int s, long cmd, void *argp) { struct lwip_sock *sock = get_socket(s); u8_t val; #if LWIP_SO_RCVBUF u16_t buflen = 0; int recv_avail; #endif /* LWIP_SO_RCVBUF */ if (!sock) { return -1; } switch (cmd) { #if LWIP_SO_RCVBUF || LWIP_FIONREAD_LINUXMODE case FIONREAD: if (!argp) { sock_set_errno(sock, EINVAL); return -1; } #if LWIP_FIONREAD_LINUXMODE if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) { struct pbuf *p; if (sock->lastdata) { p = ((struct netbuf *)sock->lastdata)->p; } else { struct netbuf *rxbuf; err_t err; if (sock->rcvevent <= 0) { *((u16_t*)argp) = 0; } else { err = netconn_recv(sock->conn, &rxbuf); if (err != ERR_OK) { *((u16_t*)argp) = 0; } else { sock->lastdata = rxbuf; *((u16_t*)argp) = rxbuf->p->tot_len; } } } return 0; } #endif /* LWIP_FIONREAD_LINUXMODE */ #if LWIP_SO_RCVBUF /* we come here if either LWIP_FIONREAD_LINUXMODE==0 or this is a TCP socket */ SYS_ARCH_GET(sock->conn->recv_avail, recv_avail); if (recv_avail < 0) { recv_avail = 0; } *((int*)argp) = recv_avail; /* Check if there is data left from the last recv operation. /maq 041215 */ if (sock->lastdata) { struct pbuf *p = (struct pbuf *)sock->lastdata; if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) { p = ((struct netbuf *)p)->p; } buflen = p->tot_len; buflen -= sock->lastoffset; *((int*)argp) += buflen; } LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, FIONREAD, %p) = %"U16_F"\n", s, argp, *((u16_t*)argp))); sock_set_errno(sock, 0); return 0; #else /* LWIP_SO_RCVBUF */ break; #endif /* LWIP_SO_RCVBUF */ #endif /* LWIP_SO_RCVBUF || LWIP_FIONREAD_LINUXMODE */ case FIONBIO: val = 0; if (argp && *(u32_t*)argp) { val = 1; } netconn_set_nonblocking(sock->conn, val); LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, FIONBIO, %d)\n", s, val)); sock_set_errno(sock, 0); return 0; default: break; } /* switch (cmd) */ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, UNIMPL: 0x%lx, %p)\n", s, cmd, argp)); sock_set_errno(sock, ENOSYS); /* not yet implemented */ return -1; } /** A minimal implementation of fcntl. * Currently only the commands F_GETFL and F_SETFL are implemented. * Only the flag O_NONBLOCK is implemented. */ int lwip_fcntl(int s, int cmd, int val) { struct lwip_sock *sock = get_socket(s); int ret = -1; if (!sock || !sock->conn) { return -1; } switch (cmd) { case F_GETFL: ret = netconn_is_nonblocking(sock->conn) ? O_NONBLOCK : 0; break; case F_SETFL: if ((val & ~O_NONBLOCK) == 0) { /* only O_NONBLOCK, all other bits are zero */ netconn_set_nonblocking(sock->conn, val & O_NONBLOCK); ret = 0; } break; default: LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_fcntl(%d, UNIMPL: %d, %d)\n", s, cmd, val)); break; } return ret; } #endif /* LWIP_SOCKET */ ocproxy-1.60/lwip/src/api/tcpip.c000066400000000000000000000376551303453231400167570ustar00rootroot00000000000000/** * @file * Sequential API Main thread module * */ /* * Copyright (c) 2001-2004 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #include "lwip/opt.h" #if !NO_SYS /* don't build if not configured for use in lwipopts.h */ #include "lwip/sys.h" #include "lwip/memp.h" #include "lwip/mem.h" #include "lwip/pbuf.h" #include "lwip/tcpip.h" #include "lwip/init.h" #include "lwip/ip.h" #include "netif/etharp.h" #include "netif/ppp/pppoe.h" #define TCPIP_MSG_VAR_REF(name) API_VAR_REF(name) #define TCPIP_MSG_VAR_DECLARE(name) API_VAR_DECLARE(struct tcpip_msg, name) #define TCPIP_MSG_VAR_ALLOC(name) API_VAR_ALLOC(struct tcpip_msg, MEMP_TCPIP_MSG_API, name) #define TCPIP_MSG_VAR_FREE(name) API_VAR_FREE(MEMP_TCPIP_MSG_API, name) /* global variables */ static tcpip_init_done_fn tcpip_init_done; static void *tcpip_init_done_arg; static sys_mbox_t mbox; #if LWIP_TCPIP_CORE_LOCKING /** The global semaphore to lock the stack. */ sys_mutex_t lock_tcpip_core; #endif /* LWIP_TCPIP_CORE_LOCKING */ /** * The main lwIP thread. This thread has exclusive access to lwIP core functions * (unless access to them is not locked). Other threads communicate with this * thread using message boxes. * * It also starts all the timers to make sure they are running in the right * thread context. * * @param arg unused argument */ static void tcpip_thread(void *arg) { struct tcpip_msg *msg; LWIP_UNUSED_ARG(arg); if (tcpip_init_done != NULL) { tcpip_init_done(tcpip_init_done_arg); } LOCK_TCPIP_CORE(); while (1) { /* MAIN Loop */ UNLOCK_TCPIP_CORE(); LWIP_TCPIP_THREAD_ALIVE(); /* wait for a message, timeouts are processed while waiting */ sys_timeouts_mbox_fetch(&mbox, (void **)&msg); LOCK_TCPIP_CORE(); if (msg == NULL) { LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: invalid message: NULL\n")); LWIP_ASSERT("tcpip_thread: invalid message", 0); continue; } switch (msg->type) { #if LWIP_NETCONN case TCPIP_MSG_API: LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: API message %p\n", (void *)msg)); msg->msg.apimsg->function(&(msg->msg.apimsg->msg)); break; #endif /* LWIP_NETCONN */ #if !LWIP_TCPIP_CORE_LOCKING_INPUT case TCPIP_MSG_INPKT: LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: PACKET %p\n", (void *)msg)); #if LWIP_ETHERNET if (msg->msg.inp.netif->flags & (NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET)) { ethernet_input(msg->msg.inp.p, msg->msg.inp.netif); } else #endif /* LWIP_ETHERNET */ #if LWIP_IPV6 if ((*((unsigned char *)(msg->msg.inp.p->payload)) & 0xf0) == 0x60) { ip6_input(msg->msg.inp.p, msg->msg.inp.netif); } else #endif /* LWIP_IPV6 */ { ip_input(msg->msg.inp.p, msg->msg.inp.netif); } memp_free(MEMP_TCPIP_MSG_INPKT, msg); break; #endif /* LWIP_TCPIP_CORE_LOCKING_INPUT */ #if LWIP_NETIF_API case TCPIP_MSG_NETIFAPI: LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: Netif API message %p\n", (void *)msg)); msg->msg.netifapimsg->function(&(msg->msg.netifapimsg->msg)); break; #endif /* LWIP_NETIF_API */ #if LWIP_PPP_API case TCPIP_MSG_PPPAPI: LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: PPP API message %p\n", (void *)msg)); msg->msg.pppapimsg->function(&(msg->msg.pppapimsg->msg)); break; #endif /* LWIP_PPP_API */ #if LWIP_TCPIP_TIMEOUT case TCPIP_MSG_TIMEOUT: LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: TIMEOUT %p\n", (void *)msg)); sys_timeout(msg->msg.tmo.msecs, msg->msg.tmo.h, msg->msg.tmo.arg); memp_free(MEMP_TCPIP_MSG_API, msg); break; case TCPIP_MSG_UNTIMEOUT: LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: UNTIMEOUT %p\n", (void *)msg)); sys_untimeout(msg->msg.tmo.h, msg->msg.tmo.arg); memp_free(MEMP_TCPIP_MSG_API, msg); break; #endif /* LWIP_TCPIP_TIMEOUT */ case TCPIP_MSG_CALLBACK: LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: CALLBACK %p\n", (void *)msg)); msg->msg.cb.function(msg->msg.cb.ctx); memp_free(MEMP_TCPIP_MSG_API, msg); break; case TCPIP_MSG_CALLBACK_STATIC: LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: CALLBACK_STATIC %p\n", (void *)msg)); msg->msg.cb.function(msg->msg.cb.ctx); break; default: LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: invalid message: %d\n", msg->type)); LWIP_ASSERT("tcpip_thread: invalid message", 0); break; } } } /** * Pass a received packet to tcpip_thread for input processing * * @param p the received packet, p->payload pointing to the Ethernet header or * to an IP header (if inp doesn't have NETIF_FLAG_ETHARP or * NETIF_FLAG_ETHERNET flags) * @param inp the network interface on which the packet was received */ err_t tcpip_input(struct pbuf *p, struct netif *inp) { #if LWIP_TCPIP_CORE_LOCKING_INPUT err_t ret; LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_input: PACKET %p/%p\n", (void *)p, (void *)inp)); LOCK_TCPIP_CORE(); #if LWIP_ETHERNET if (inp->flags & (NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET)) { ret = ethernet_input(p, inp); } else #endif /* LWIP_ETHERNET */ { ret = ip_input(p, inp); } UNLOCK_TCPIP_CORE(); return ret; #else /* LWIP_TCPIP_CORE_LOCKING_INPUT */ struct tcpip_msg *msg; if (!sys_mbox_valid(&mbox)) { return ERR_VAL; } msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_INPKT); if (msg == NULL) { return ERR_MEM; } msg->type = TCPIP_MSG_INPKT; msg->msg.inp.p = p; msg->msg.inp.netif = inp; if (sys_mbox_trypost(&mbox, msg) != ERR_OK) { memp_free(MEMP_TCPIP_MSG_INPKT, msg); return ERR_MEM; } return ERR_OK; #endif /* LWIP_TCPIP_CORE_LOCKING_INPUT */ } /** * Call a specific function in the thread context of * tcpip_thread for easy access synchronization. * A function called in that way may access lwIP core code * without fearing concurrent access. * * @param f the function to call * @param ctx parameter passed to f * @param block 1 to block until the request is posted, 0 to non-blocking mode * @return ERR_OK if the function was called, another err_t if not */ err_t tcpip_callback_with_block(tcpip_callback_fn function, void *ctx, u8_t block) { struct tcpip_msg *msg; if (sys_mbox_valid(&mbox)) { msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API); if (msg == NULL) { return ERR_MEM; } msg->type = TCPIP_MSG_CALLBACK; msg->msg.cb.function = function; msg->msg.cb.ctx = ctx; if (block) { sys_mbox_post(&mbox, msg); } else { if (sys_mbox_trypost(&mbox, msg) != ERR_OK) { memp_free(MEMP_TCPIP_MSG_API, msg); return ERR_MEM; } } return ERR_OK; } return ERR_VAL; } #if LWIP_TCPIP_TIMEOUT /** * call sys_timeout in tcpip_thread * * @param msec time in milliseconds for timeout * @param h function to be called on timeout * @param arg argument to pass to timeout function h * @return ERR_MEM on memory error, ERR_OK otherwise */ err_t tcpip_timeout(u32_t msecs, sys_timeout_handler h, void *arg) { struct tcpip_msg *msg; if (sys_mbox_valid(&mbox)) { msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API); if (msg == NULL) { return ERR_MEM; } msg->type = TCPIP_MSG_TIMEOUT; msg->msg.tmo.msecs = msecs; msg->msg.tmo.h = h; msg->msg.tmo.arg = arg; sys_mbox_post(&mbox, msg); return ERR_OK; } return ERR_VAL; } /** * call sys_untimeout in tcpip_thread * * @param msec time in milliseconds for timeout * @param h function to be called on timeout * @param arg argument to pass to timeout function h * @return ERR_MEM on memory error, ERR_OK otherwise */ err_t tcpip_untimeout(sys_timeout_handler h, void *arg) { struct tcpip_msg *msg; if (sys_mbox_valid(&mbox)) { msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API); if (msg == NULL) { return ERR_MEM; } msg->type = TCPIP_MSG_UNTIMEOUT; msg->msg.tmo.h = h; msg->msg.tmo.arg = arg; sys_mbox_post(&mbox, msg); return ERR_OK; } return ERR_VAL; } #endif /* LWIP_TCPIP_TIMEOUT */ #if LWIP_NETCONN /** * Call the lower part of a netconn_* function * This function is then running in the thread context * of tcpip_thread and has exclusive access to lwIP core code. * * @param apimsg a struct containing the function to call and its parameters * @return ERR_OK if the function was called, another err_t if not */ err_t tcpip_apimsg(struct api_msg *apimsg) { TCPIP_MSG_VAR_DECLARE(msg); #ifdef LWIP_DEBUG /* catch functions that don't set err */ apimsg->msg.err = ERR_VAL; #endif if (sys_mbox_valid(&mbox)) { TCPIP_MSG_VAR_ALLOC(msg); TCPIP_MSG_VAR_REF(msg).type = TCPIP_MSG_API; TCPIP_MSG_VAR_REF(msg).msg.apimsg = apimsg; sys_mbox_post(&mbox, &TCPIP_MSG_VAR_REF(msg)); sys_arch_sem_wait(&apimsg->msg.conn->op_completed, 0); TCPIP_MSG_VAR_FREE(msg); return apimsg->msg.err; } return ERR_VAL; } #endif /* LWIP_NETCONN */ #if LWIP_NETIF_API #if !LWIP_TCPIP_CORE_LOCKING /** * Much like tcpip_apimsg, but calls the lower part of a netifapi_* * function. * * @param netifapimsg a struct containing the function to call and its parameters * @return error code given back by the function that was called */ err_t tcpip_netifapi(struct netifapi_msg* netifapimsg) { TCPIP_MSG_VAR_DECLARE(msg); if (sys_mbox_valid(&mbox)) { err_t err; TCPIP_MSG_VAR_ALLOC(msg); err = sys_sem_new(&netifapimsg->msg.sem, 0); if (err != ERR_OK) { netifapimsg->msg.err = err; return err; } TCPIP_MSG_VAR_REF(msg).type = TCPIP_MSG_NETIFAPI; TCPIP_MSG_VAR_REF(msg).msg.netifapimsg = netifapimsg; sys_mbox_post(&mbox, &TCPIP_MSG_VAR_REF(msg)); sys_sem_wait(&netifapimsg->msg.sem); sys_sem_free(&netifapimsg->msg.sem); TCPIP_MSG_VAR_FREE(msg); return netifapimsg->msg.err; } return ERR_VAL; } #else /* !LWIP_TCPIP_CORE_LOCKING */ /** * Call the lower part of a netifapi_* function * This function has exclusive access to lwIP core code by locking it * before the function is called. * * @param netifapimsg a struct containing the function to call and its parameters * @return ERR_OK (only for compatibility fo tcpip_netifapi()) */ err_t tcpip_netifapi_lock(struct netifapi_msg* netifapimsg) { LOCK_TCPIP_CORE(); netifapimsg->function(&(netifapimsg->msg)); UNLOCK_TCPIP_CORE(); return netifapimsg->msg.err; } #endif /* !LWIP_TCPIP_CORE_LOCKING */ #endif /* LWIP_NETIF_API */ #if LWIP_PPP_API #if !LWIP_TCPIP_CORE_LOCKING /** * Much like tcpip_apimsg, but calls the lower part of a pppapi_* * function. * * @param pppapimsg a struct containing the function to call and its parameters * @return error code given back by the function that was called */ err_t tcpip_pppapi(struct pppapi_msg* pppapimsg) { struct tcpip_msg msg; if (sys_mbox_valid(&mbox)) { err_t err = sys_sem_new(&pppapimsg->msg.sem, 0); if (err != ERR_OK) { pppapimsg->msg.err = err; return err; } msg.type = TCPIP_MSG_PPPAPI; msg.msg.pppapimsg = pppapimsg; sys_mbox_post(&mbox, &msg); sys_sem_wait(&pppapimsg->msg.sem); sys_sem_free(&pppapimsg->msg.sem); return pppapimsg->msg.err; } return ERR_VAL; } #else /* !LWIP_TCPIP_CORE_LOCKING */ /** * Call the lower part of a pppapi_* function * This function has exclusive access to lwIP core code by locking it * before the function is called. * * @param pppapimsg a struct containing the function to call and its parameters * @return ERR_OK (only for compatibility fo tcpip_pppapi()) */ err_t tcpip_pppapi_lock(struct pppapi_msg* pppapimsg) { LOCK_TCPIP_CORE(); pppapimsg->function(&(pppapimsg->msg)); UNLOCK_TCPIP_CORE(); return pppapimsg->msg.err; } #endif /* !LWIP_TCPIP_CORE_LOCKING */ #endif /* LWIP_PPP_API */ /** * Allocate a structure for a static callback message and initialize it. * This is intended to be used to send "static" messages from interrupt context. * * @param function the function to call * @param ctx parameter passed to function * @return a struct pointer to pass to tcpip_trycallback(). */ struct tcpip_callback_msg* tcpip_callbackmsg_new(tcpip_callback_fn function, void *ctx) { struct tcpip_msg *msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API); if (msg == NULL) { return NULL; } msg->type = TCPIP_MSG_CALLBACK_STATIC; msg->msg.cb.function = function; msg->msg.cb.ctx = ctx; return (struct tcpip_callback_msg*)msg; } /** * Free a callback message allocated by tcpip_callbackmsg_new(). * * @param msg the message to free */ void tcpip_callbackmsg_delete(struct tcpip_callback_msg* msg) { memp_free(MEMP_TCPIP_MSG_API, msg); } /** * Try to post a callback-message to the tcpip_thread mbox * This is intended to be used to send "static" messages from interrupt context. * * @param msg pointer to the message to post * @return sys_mbox_trypost() return code */ err_t tcpip_trycallback(struct tcpip_callback_msg* msg) { if (!sys_mbox_valid(&mbox)) { return ERR_VAL; } return sys_mbox_trypost(&mbox, msg); } /** * Initialize this module: * - initialize all sub modules * - start the tcpip_thread * * @param initfunc a function to call when tcpip_thread is running and finished initializing * @param arg argument to pass to initfunc */ void tcpip_init(tcpip_init_done_fn initfunc, void *arg) { lwip_init(); tcpip_init_done = initfunc; tcpip_init_done_arg = arg; if(sys_mbox_new(&mbox, TCPIP_MBOX_SIZE) != ERR_OK) { LWIP_ASSERT("failed to create tcpip_thread mbox", 0); } #if LWIP_TCPIP_CORE_LOCKING if(sys_mutex_new(&lock_tcpip_core) != ERR_OK) { LWIP_ASSERT("failed to create lock_tcpip_core", 0); } #endif /* LWIP_TCPIP_CORE_LOCKING */ sys_thread_new(TCPIP_THREAD_NAME, tcpip_thread, NULL, TCPIP_THREAD_STACKSIZE, TCPIP_THREAD_PRIO); } /** * Simple callback function used with tcpip_callback to free a pbuf * (pbuf_free has a wrong signature for tcpip_callback) * * @param p The pbuf (chain) to be dereferenced. */ static void pbuf_free_int(void *p) { struct pbuf *q = (struct pbuf *)p; pbuf_free(q); } /** * A simple wrapper function that allows you to free a pbuf from interrupt context. * * @param p The pbuf (chain) to be dereferenced. * @return ERR_OK if callback could be enqueued, an err_t if not */ err_t pbuf_free_callback(struct pbuf *p) { return tcpip_callback_with_block(pbuf_free_int, p, 0); } /** * A simple wrapper function that allows you to free heap memory from * interrupt context. * * @param m the heap memory to free * @return ERR_OK if callback could be enqueued, an err_t if not */ err_t mem_free_callback(void *m) { return tcpip_callback_with_block(mem_free, m, 0); } #endif /* !NO_SYS */ ocproxy-1.60/lwip/src/core/000077500000000000000000000000001303453231400156335ustar00rootroot00000000000000ocproxy-1.60/lwip/src/core/def.c000066400000000000000000000062271303453231400165440ustar00rootroot00000000000000/** * @file * Common functions used throughout the stack. * */ /* * Copyright (c) 2001-2004 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Simon Goldschmidt * */ #include "lwip/opt.h" #include "lwip/def.h" /** * These are reference implementations of the byte swapping functions. * Again with the aim of being simple, correct and fully portable. * Byte swapping is the second thing you would want to optimize. You will * need to port it to your architecture and in your cc.h: * * #define LWIP_PLATFORM_BYTESWAP 1 * #define LWIP_PLATFORM_HTONS(x) * #define LWIP_PLATFORM_HTONL(x) * * Note ntohs() and ntohl() are merely references to the htonx counterparts. */ #if (LWIP_PLATFORM_BYTESWAP == 0) && (BYTE_ORDER == LITTLE_ENDIAN) /** * Convert an u16_t from host- to network byte order. * * @param n u16_t in host byte order * @return n in network byte order */ u16_t lwip_htons(u16_t n) { return ((n & 0xff) << 8) | ((n & 0xff00) >> 8); } /** * Convert an u16_t from network- to host byte order. * * @param n u16_t in network byte order * @return n in host byte order */ u16_t lwip_ntohs(u16_t n) { return lwip_htons(n); } /** * Convert an u32_t from host- to network byte order. * * @param n u32_t in host byte order * @return n in network byte order */ u32_t lwip_htonl(u32_t n) { return ((n & 0xff) << 24) | ((n & 0xff00) << 8) | ((n & 0xff0000UL) >> 8) | ((n & 0xff000000UL) >> 24); } /** * Convert an u32_t from network- to host byte order. * * @param n u32_t in network byte order * @return n in host byte order */ u32_t lwip_ntohl(u32_t n) { return lwip_htonl(n); } #endif /* (LWIP_PLATFORM_BYTESWAP == 0) && (BYTE_ORDER == LITTLE_ENDIAN) */ ocproxy-1.60/lwip/src/core/dhcp.c000066400000000000000000001772621303453231400167340ustar00rootroot00000000000000/** * @file * Dynamic Host Configuration Protocol client * */ /* * * Copyright (c) 2001-2004 Leon Woestenberg * Copyright (c) 2001-2004 Axon Digital Design B.V., The Netherlands. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is a contribution to the lwIP TCP/IP stack. * The Swedish Institute of Computer Science and Adam Dunkels * are specifically granted permission to redistribute this * source code. * * Author: Leon Woestenberg * * This is a DHCP client for the lwIP TCP/IP stack. It aims to conform * with RFC 2131 and RFC 2132. * * TODO: * - Support for interfaces other than Ethernet (SLIP, PPP, ...) * * Please coordinate changes and requests with Leon Woestenberg * * * Integration with your code: * * In lwip/dhcp.h * #define DHCP_COARSE_TIMER_SECS (recommended 60 which is a minute) * #define DHCP_FINE_TIMER_MSECS (recommended 500 which equals TCP coarse timer) * * Then have your application call dhcp_coarse_tmr() and * dhcp_fine_tmr() on the defined intervals. * * dhcp_start(struct netif *netif); * starts a DHCP client instance which configures the interface by * obtaining an IP address lease and maintaining it. * * Use dhcp_release(netif) to end the lease and use dhcp_stop(netif) * to remove the DHCP client. * */ #include "lwip/opt.h" #if LWIP_DHCP /* don't build if not configured for use in lwipopts.h */ #include "lwip/stats.h" #include "lwip/mem.h" #include "lwip/udp.h" #include "lwip/ip_addr.h" #include "lwip/netif.h" #include "lwip/def.h" #include "lwip/dhcp.h" #include "lwip/autoip.h" #include "lwip/dns.h" #include "netif/etharp.h" #include /** DHCP_CREATE_RAND_XID: if this is set to 1, the xid is created using * LWIP_RAND() (this overrides DHCP_GLOBAL_XID) */ #ifndef DHCP_CREATE_RAND_XID #define DHCP_CREATE_RAND_XID 1 #endif /** Default for DHCP_GLOBAL_XID is 0xABCD0000 * This can be changed by defining DHCP_GLOBAL_XID and DHCP_GLOBAL_XID_HEADER, e.g. * #define DHCP_GLOBAL_XID_HEADER "stdlib.h" * #define DHCP_GLOBAL_XID rand() */ #ifdef DHCP_GLOBAL_XID_HEADER #include DHCP_GLOBAL_XID_HEADER /* include optional starting XID generation prototypes */ #endif /** DHCP_OPTION_MAX_MSG_SIZE is set to the MTU * MTU is checked to be big enough in dhcp_start */ #define DHCP_MAX_MSG_LEN(netif) (netif->mtu) #define DHCP_MAX_MSG_LEN_MIN_REQUIRED 576 /** Minimum length for reply before packet is parsed */ #define DHCP_MIN_REPLY_LEN 44 #define REBOOT_TRIES 2 /** Option handling: options are parsed in dhcp_parse_reply * and saved in an array where other functions can load them from. * This might be moved into the struct dhcp (not necessarily since * lwIP is single-threaded and the array is only used while in recv * callback). */ #define DHCP_OPTION_IDX_OVERLOAD 0 #define DHCP_OPTION_IDX_MSG_TYPE 1 #define DHCP_OPTION_IDX_SERVER_ID 2 #define DHCP_OPTION_IDX_LEASE_TIME 3 #define DHCP_OPTION_IDX_T1 4 #define DHCP_OPTION_IDX_T2 5 #define DHCP_OPTION_IDX_SUBNET_MASK 6 #define DHCP_OPTION_IDX_ROUTER 7 #define DHCP_OPTION_IDX_DNS_SERVER 8 #define DHCP_OPTION_IDX_MAX (DHCP_OPTION_IDX_DNS_SERVER + DNS_MAX_SERVERS) /** Holds the decoded option values, only valid while in dhcp_recv. @todo: move this into struct dhcp? */ u32_t dhcp_rx_options_val[DHCP_OPTION_IDX_MAX]; /** Holds a flag which option was received and is contained in dhcp_rx_options_val, only valid while in dhcp_recv. @todo: move this into struct dhcp? */ u8_t dhcp_rx_options_given[DHCP_OPTION_IDX_MAX]; #ifdef DHCP_GLOBAL_XID static u32_t xid; static u8_t xid_initialised; #endif /* DHCP_GLOBAL_XID */ #define dhcp_option_given(dhcp, idx) (dhcp_rx_options_given[idx] != 0) #define dhcp_got_option(dhcp, idx) (dhcp_rx_options_given[idx] = 1) #define dhcp_clear_option(dhcp, idx) (dhcp_rx_options_given[idx] = 0) #define dhcp_clear_all_options(dhcp) (memset(dhcp_rx_options_given, 0, sizeof(dhcp_rx_options_given))) #define dhcp_get_option_value(dhcp, idx) (dhcp_rx_options_val[idx]) #define dhcp_set_option_value(dhcp, idx, val) (dhcp_rx_options_val[idx] = (val)) /* DHCP client state machine functions */ static err_t dhcp_discover(struct netif *netif); static err_t dhcp_select(struct netif *netif); static void dhcp_bind(struct netif *netif); #if DHCP_DOES_ARP_CHECK static err_t dhcp_decline(struct netif *netif); #endif /* DHCP_DOES_ARP_CHECK */ static err_t dhcp_rebind(struct netif *netif); static err_t dhcp_reboot(struct netif *netif); static void dhcp_set_state(struct dhcp *dhcp, u8_t new_state); /* receive, unfold, parse and free incoming messages */ static void dhcp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port); /* set the DHCP timers */ static void dhcp_timeout(struct netif *netif); static void dhcp_t1_timeout(struct netif *netif); static void dhcp_t2_timeout(struct netif *netif); /* build outgoing messages */ /* create a DHCP message, fill in common headers */ static err_t dhcp_create_msg(struct netif *netif, struct dhcp *dhcp, u8_t message_type); /* free a DHCP request */ static void dhcp_delete_msg(struct dhcp *dhcp); /* add a DHCP option (type, then length in bytes) */ static void dhcp_option(struct dhcp *dhcp, u8_t option_type, u8_t option_len); /* add option values */ static void dhcp_option_byte(struct dhcp *dhcp, u8_t value); static void dhcp_option_short(struct dhcp *dhcp, u16_t value); static void dhcp_option_long(struct dhcp *dhcp, u32_t value); #if LWIP_NETIF_HOSTNAME static void dhcp_option_hostname(struct dhcp *dhcp, struct netif *netif); #endif /* LWIP_NETIF_HOSTNAME */ /* always add the DHCP options trailer to end and pad */ static void dhcp_option_trailer(struct dhcp *dhcp); /** * Back-off the DHCP client (because of a received NAK response). * * Back-off the DHCP client because of a received NAK. Receiving a * NAK means the client asked for something non-sensible, for * example when it tries to renew a lease obtained on another network. * * We clear any existing set IP address and restart DHCP negotiation * afresh (as per RFC2131 3.2.3). * * @param netif the netif under DHCP control */ static void dhcp_handle_nak(struct netif *netif) { struct dhcp *dhcp = netif->dhcp; LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_handle_nak(netif=%p) %c%c%"U16_F"\n", (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num)); /* Set the interface down since the address must no longer be used, as per RFC2131 */ netif_set_down(netif); /* remove IP address from interface */ netif_set_ipaddr(netif, IP_ADDR_ANY); netif_set_gw(netif, IP_ADDR_ANY); netif_set_netmask(netif, IP_ADDR_ANY); /* Change to a defined state */ dhcp_set_state(dhcp, DHCP_BACKING_OFF); /* We can immediately restart discovery */ dhcp_discover(netif); } #if DHCP_DOES_ARP_CHECK /** * Checks if the offered IP address is already in use. * * It does so by sending an ARP request for the offered address and * entering CHECKING state. If no ARP reply is received within a small * interval, the address is assumed to be free for use by us. * * @param netif the netif under DHCP control */ static void dhcp_check(struct netif *netif) { struct dhcp *dhcp = netif->dhcp; err_t result; u16_t msecs; LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_check(netif=%p) %c%c\n", (void *)netif, (s16_t)netif->name[0], (s16_t)netif->name[1])); dhcp_set_state(dhcp, DHCP_CHECKING); /* create an ARP query for the offered IP address, expecting that no host responds, as the IP address should not be in use. */ result = etharp_query(netif, &dhcp->offered_ip_addr, NULL); if (result != ERR_OK) { LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("dhcp_check: could not perform ARP query\n")); } dhcp->tries++; msecs = 500; dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS; LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_check(): set request timeout %"U16_F" msecs\n", msecs)); } #endif /* DHCP_DOES_ARP_CHECK */ /** * Remember the configuration offered by a DHCP server. * * @param netif the netif under DHCP control */ static void dhcp_handle_offer(struct netif *netif) { struct dhcp *dhcp = netif->dhcp; LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_handle_offer(netif=%p) %c%c%"U16_F"\n", (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num)); /* obtain the server address */ if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_SERVER_ID)) { ip4_addr_set_u32(&dhcp->server_ip_addr, htonl(dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_SERVER_ID))); LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_handle_offer(): server 0x%08"X32_F"\n", ip4_addr_get_u32(&dhcp->server_ip_addr))); /* remember offered address */ ip_addr_copy(dhcp->offered_ip_addr, dhcp->msg_in->yiaddr); LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_handle_offer(): offer for 0x%08"X32_F"\n", ip4_addr_get_u32(&dhcp->offered_ip_addr))); dhcp_select(netif); } else { LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp_handle_offer(netif=%p) did not get server ID!\n", (void*)netif)); } } /** * Select a DHCP server offer out of all offers. * * Simply select the first offer received. * * @param netif the netif under DHCP control * @return lwIP specific error (see error.h) */ static err_t dhcp_select(struct netif *netif) { struct dhcp *dhcp = netif->dhcp; err_t result; u16_t msecs; LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_select(netif=%p) %c%c%"U16_F"\n", (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num)); dhcp_set_state(dhcp, DHCP_REQUESTING); /* create and initialize the DHCP message header */ result = dhcp_create_msg(netif, dhcp, DHCP_REQUEST); if (result == ERR_OK) { dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN); dhcp_option_short(dhcp, DHCP_MAX_MSG_LEN(netif)); /* MUST request the offered IP address */ dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4); dhcp_option_long(dhcp, ntohl(ip4_addr_get_u32(&dhcp->offered_ip_addr))); dhcp_option(dhcp, DHCP_OPTION_SERVER_ID, 4); dhcp_option_long(dhcp, ntohl(ip4_addr_get_u32(&dhcp->server_ip_addr))); dhcp_option(dhcp, DHCP_OPTION_PARAMETER_REQUEST_LIST, 4/*num options*/); dhcp_option_byte(dhcp, DHCP_OPTION_SUBNET_MASK); dhcp_option_byte(dhcp, DHCP_OPTION_ROUTER); dhcp_option_byte(dhcp, DHCP_OPTION_BROADCAST); dhcp_option_byte(dhcp, DHCP_OPTION_DNS_SERVER); #if LWIP_NETIF_HOSTNAME dhcp_option_hostname(dhcp, netif); #endif /* LWIP_NETIF_HOSTNAME */ dhcp_option_trailer(dhcp); /* shrink the pbuf to the actual content length */ pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len); /* send broadcast to any DHCP server */ udp_sendto_if_src(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif, IP_ADDR_ANY); dhcp_delete_msg(dhcp); LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_select: REQUESTING\n")); } else { LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("dhcp_select: could not allocate DHCP request\n")); } dhcp->tries++; msecs = (dhcp->tries < 6 ? 1 << dhcp->tries : 60) * 1000; dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS; LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_select(): set request timeout %"U16_F" msecs\n", msecs)); return result; } /** * The DHCP timer that checks for lease renewal/rebind timeouts. */ void dhcp_coarse_tmr() { struct netif *netif = netif_list; LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_coarse_tmr()\n")); /* iterate through all network interfaces */ while (netif != NULL) { /* only act on DHCP configured interfaces */ if (netif->dhcp != NULL) { /* timer is active (non zero), and triggers (zeroes) now? */ if (netif->dhcp->t2_timeout-- == 1) { LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_coarse_tmr(): t2 timeout\n")); /* this clients' rebind timeout triggered */ dhcp_t2_timeout(netif); /* timer is active (non zero), and triggers (zeroes) now */ } else if (netif->dhcp->t1_timeout-- == 1) { LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_coarse_tmr(): t1 timeout\n")); /* this clients' renewal timeout triggered */ dhcp_t1_timeout(netif); } } /* proceed to next netif */ netif = netif->next; } } /** * DHCP transaction timeout handling * * A DHCP server is expected to respond within a short period of time. * This timer checks whether an outstanding DHCP request is timed out. */ void dhcp_fine_tmr() { struct netif *netif = netif_list; /* loop through netif's */ while (netif != NULL) { /* only act on DHCP configured interfaces */ if (netif->dhcp != NULL) { /* timer is active (non zero), and is about to trigger now */ if (netif->dhcp->request_timeout > 1) { netif->dhcp->request_timeout--; } else if (netif->dhcp->request_timeout == 1) { netif->dhcp->request_timeout--; /* { netif->dhcp->request_timeout == 0 } */ LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_fine_tmr(): request timeout\n")); /* this client's request timeout triggered */ dhcp_timeout(netif); } } /* proceed to next network interface */ netif = netif->next; } } /** * A DHCP negotiation transaction, or ARP request, has timed out. * * The timer that was started with the DHCP or ARP request has * timed out, indicating no response was received in time. * * @param netif the netif under DHCP control */ static void dhcp_timeout(struct netif *netif) { struct dhcp *dhcp = netif->dhcp; LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_timeout()\n")); /* back-off period has passed, or server selection timed out */ if ((dhcp->state == DHCP_BACKING_OFF) || (dhcp->state == DHCP_SELECTING)) { LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_timeout(): restarting discovery\n")); dhcp_discover(netif); /* receiving the requested lease timed out */ } else if (dhcp->state == DHCP_REQUESTING) { LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_timeout(): REQUESTING, DHCP request timed out\n")); if (dhcp->tries <= 5) { dhcp_select(netif); } else { LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_timeout(): REQUESTING, releasing, restarting\n")); dhcp_release(netif); dhcp_discover(netif); } #if DHCP_DOES_ARP_CHECK /* received no ARP reply for the offered address (which is good) */ } else if (dhcp->state == DHCP_CHECKING) { LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_timeout(): CHECKING, ARP request timed out\n")); if (dhcp->tries <= 1) { dhcp_check(netif); /* no ARP replies on the offered address, looks like the IP address is indeed free */ } else { /* bind the interface to the offered address */ dhcp_bind(netif); } #endif /* DHCP_DOES_ARP_CHECK */ } /* did not get response to renew request? */ else if (dhcp->state == DHCP_RENEWING) { LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_timeout(): RENEWING, DHCP request timed out\n")); /* just retry renewal */ /* note that the rebind timer will eventually time-out if renew does not work */ dhcp_renew(netif); /* did not get response to rebind request? */ } else if (dhcp->state == DHCP_REBINDING) { LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_timeout(): REBINDING, DHCP request timed out\n")); if (dhcp->tries <= 8) { dhcp_rebind(netif); } else { LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_timeout(): RELEASING, DISCOVERING\n")); dhcp_release(netif); dhcp_discover(netif); } } else if (dhcp->state == DHCP_REBOOTING) { if (dhcp->tries < REBOOT_TRIES) { dhcp_reboot(netif); } else { dhcp_discover(netif); } } } /** * The renewal period has timed out. * * @param netif the netif under DHCP control */ static void dhcp_t1_timeout(struct netif *netif) { struct dhcp *dhcp = netif->dhcp; LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_t1_timeout()\n")); if ((dhcp->state == DHCP_REQUESTING) || (dhcp->state == DHCP_BOUND) || (dhcp->state == DHCP_RENEWING)) { /* just retry to renew - note that the rebind timer (t2) will * eventually time-out if renew tries fail. */ LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_t1_timeout(): must renew\n")); /* This slightly different to RFC2131: DHCPREQUEST will be sent from state DHCP_RENEWING, not DHCP_BOUND */ dhcp_renew(netif); } } /** * The rebind period has timed out. * * @param netif the netif under DHCP control */ static void dhcp_t2_timeout(struct netif *netif) { struct dhcp *dhcp = netif->dhcp; LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_t2_timeout()\n")); if ((dhcp->state == DHCP_REQUESTING) || (dhcp->state == DHCP_BOUND) || (dhcp->state == DHCP_RENEWING)) { /* just retry to rebind */ LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_t2_timeout(): must rebind\n")); /* This slightly different to RFC2131: DHCPREQUEST will be sent from state DHCP_REBINDING, not DHCP_BOUND */ dhcp_rebind(netif); } } /** * Handle a DHCP ACK packet * * @param netif the netif under DHCP control */ static void dhcp_handle_ack(struct netif *netif) { struct dhcp *dhcp = netif->dhcp; #if LWIP_DNS u8_t n; #endif /* LWIP_DNS */ /* clear options we might not get from the ACK */ ip_addr_set_zero(&dhcp->offered_sn_mask); ip_addr_set_zero(&dhcp->offered_gw_addr); #if LWIP_DHCP_BOOTP_FILE ip_addr_set_zero(&dhcp->offered_si_addr); #endif /* LWIP_DHCP_BOOTP_FILE */ /* lease time given? */ if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_LEASE_TIME)) { /* remember offered lease time */ dhcp->offered_t0_lease = dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_LEASE_TIME); } /* renewal period given? */ if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_T1)) { /* remember given renewal period */ dhcp->offered_t1_renew = dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_T1); } else { /* calculate safe periods for renewal */ dhcp->offered_t1_renew = dhcp->offered_t0_lease / 2; } /* renewal period given? */ if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_T2)) { /* remember given rebind period */ dhcp->offered_t2_rebind = dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_T2); } else { /* calculate safe periods for rebinding */ dhcp->offered_t2_rebind = dhcp->offered_t0_lease; } /* (y)our internet address */ ip_addr_copy(dhcp->offered_ip_addr, dhcp->msg_in->yiaddr); #if LWIP_DHCP_BOOTP_FILE /* copy boot server address, boot file name copied in dhcp_parse_reply if not overloaded */ ip_addr_copy(dhcp->offered_si_addr, dhcp->msg_in->siaddr); #endif /* LWIP_DHCP_BOOTP_FILE */ /* subnet mask given? */ if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_SUBNET_MASK)) { /* remember given subnet mask */ ip4_addr_set_u32(&dhcp->offered_sn_mask, htonl(dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_SUBNET_MASK))); dhcp->subnet_mask_given = 1; } else { dhcp->subnet_mask_given = 0; } /* gateway router */ if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_ROUTER)) { ip4_addr_set_u32(&dhcp->offered_gw_addr, htonl(dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_ROUTER))); } #if LWIP_DNS /* DNS servers */ for(n = 0; (n < DNS_MAX_SERVERS) && dhcp_option_given(dhcp, DHCP_OPTION_IDX_DNS_SERVER + n); n++) { ip_addr_t dns_addr; ip4_addr_set_u32(&dns_addr, htonl(dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_DNS_SERVER + n))); dns_setserver(n, &dns_addr); } #endif /* LWIP_DNS */ } /** Set a statically allocated struct dhcp to work with. * Using this prevents dhcp_start to allocate it using mem_malloc. * * @param netif the netif for which to set the struct dhcp * @param dhcp (uninitialised) dhcp struct allocated by the application */ void dhcp_set_struct(struct netif *netif, struct dhcp *dhcp) { LWIP_ASSERT("netif != NULL", netif != NULL); LWIP_ASSERT("dhcp != NULL", dhcp != NULL); LWIP_ASSERT("netif already has a struct dhcp set", netif->dhcp == NULL); /* clear data structure */ memset(dhcp, 0, sizeof(struct dhcp)); /* dhcp_set_state(&dhcp, DHCP_OFF); */ netif->dhcp = dhcp; } /** Removes a struct dhcp from a netif. * * ATTENTION: Only use this when not using dhcp_set_struct() to allocate the * struct dhcp since the memory is passed back to the heap. * * @param netif the netif from which to remove the struct dhcp */ void dhcp_cleanup(struct netif *netif) { LWIP_ASSERT("netif != NULL", netif != NULL); if (netif->dhcp != NULL) { mem_free(netif->dhcp); netif->dhcp = NULL; } } /** * Start DHCP negotiation for a network interface. * * If no DHCP client instance was attached to this interface, * a new client is created first. If a DHCP client instance * was already present, it restarts negotiation. * * @param netif The lwIP network interface * @return lwIP error code * - ERR_OK - No error * - ERR_MEM - Out of memory */ err_t dhcp_start(struct netif *netif) { struct dhcp *dhcp; err_t result = ERR_OK; LWIP_ERROR("netif != NULL", (netif != NULL), return ERR_ARG;); dhcp = netif->dhcp; LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_start(netif=%p) %c%c%"U16_F"\n", (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num)); /* Remove the flag that says this netif is handled by DHCP, it is set when we succeeded starting. */ netif->flags &= ~NETIF_FLAG_DHCP; /* check hwtype of the netif */ if ((netif->flags & NETIF_FLAG_ETHARP) == 0) { LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): No ETHARP netif\n")); return ERR_ARG; } /* check MTU of the netif */ if (netif->mtu < DHCP_MAX_MSG_LEN_MIN_REQUIRED) { LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): Cannot use this netif with DHCP: MTU is too small\n")); return ERR_MEM; } /* no DHCP client attached yet? */ if (dhcp == NULL) { LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): starting new DHCP client\n")); dhcp = (struct dhcp *)mem_malloc(sizeof(struct dhcp)); if (dhcp == NULL) { LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): could not allocate dhcp\n")); return ERR_MEM; } /* store this dhcp client in the netif */ netif->dhcp = dhcp; LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): allocated dhcp")); /* already has DHCP client attached */ } else { LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_start(): restarting DHCP configuration\n")); if (dhcp->pcb != NULL) { udp_remove(dhcp->pcb); } LWIP_ASSERT("pbuf p_out wasn't freed", dhcp->p_out == NULL); LWIP_ASSERT("reply wasn't freed", dhcp->msg_in == NULL ); } /* clear data structure */ memset(dhcp, 0, sizeof(struct dhcp)); /* dhcp_set_state(&dhcp, DHCP_OFF); */ /* allocate UDP PCB */ dhcp->pcb = udp_new(); if (dhcp->pcb == NULL) { LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): could not obtain pcb\n")); return ERR_MEM; } ip_set_option(dhcp->pcb, SOF_BROADCAST); /* set up local and remote port for the pcb */ udp_bind(dhcp->pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT); udp_connect(dhcp->pcb, IP_ADDR_ANY, DHCP_SERVER_PORT); /* set up the recv callback and argument */ udp_recv(dhcp->pcb, dhcp_recv, netif); LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): starting DHCP configuration\n")); /* (re)start the DHCP negotiation */ result = dhcp_discover(netif); if (result != ERR_OK) { /* free resources allocated above */ dhcp_stop(netif); return ERR_MEM; } /* Set the flag that says this netif is handled by DHCP. */ netif->flags |= NETIF_FLAG_DHCP; return result; } /** * Inform a DHCP server of our manual configuration. * * This informs DHCP servers of our fixed IP address configuration * by sending an INFORM message. It does not involve DHCP address * configuration, it is just here to be nice to the network. * * @param netif The lwIP network interface */ void dhcp_inform(struct netif *netif) { struct dhcp dhcp; err_t result = ERR_OK; struct udp_pcb *pcb; LWIP_ERROR("netif != NULL", (netif != NULL), return;); memset(&dhcp, 0, sizeof(struct dhcp)); dhcp_set_state(&dhcp, DHCP_INFORM); if ((netif->dhcp != NULL) && (netif->dhcp->pcb != NULL)) { /* re-use existing pcb */ pcb = netif->dhcp->pcb; } else { pcb = udp_new(); if (pcb == NULL) { LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp_inform(): could not obtain pcb")); return; } dhcp.pcb = pcb; ip_set_option(dhcp.pcb, SOF_BROADCAST); udp_bind(dhcp.pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT); LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_inform(): created new udp pcb\n")); } /* create and initialize the DHCP message header */ result = dhcp_create_msg(netif, &dhcp, DHCP_INFORM); if (result == ERR_OK) { dhcp_option(&dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN); dhcp_option_short(&dhcp, DHCP_MAX_MSG_LEN(netif)); dhcp_option_trailer(&dhcp); pbuf_realloc(dhcp.p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp.options_out_len); LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_inform: INFORMING\n")); udp_sendto_if(pcb, dhcp.p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif); dhcp_delete_msg(&dhcp); } else { LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp_inform: could not allocate DHCP request\n")); } if (dhcp.pcb != NULL) { /* otherwise, the existing pcb was used */ udp_remove(dhcp.pcb); } } /** Handle a possible change in the network configuration. * * This enters the REBOOTING state to verify that the currently bound * address is still valid. */ void dhcp_network_changed(struct netif *netif) { struct dhcp *dhcp = netif->dhcp; if (!dhcp) return; switch (dhcp->state) { case DHCP_REBINDING: case DHCP_RENEWING: case DHCP_BOUND: case DHCP_REBOOTING: netif_set_down(netif); dhcp->tries = 0; dhcp_reboot(netif); break; case DHCP_OFF: /* stay off */ break; default: dhcp->tries = 0; #if LWIP_DHCP_AUTOIP_COOP if(dhcp->autoip_coop_state == DHCP_AUTOIP_COOP_STATE_ON) { autoip_stop(netif); dhcp->autoip_coop_state = DHCP_AUTOIP_COOP_STATE_OFF; } #endif /* LWIP_DHCP_AUTOIP_COOP */ dhcp_discover(netif); break; } } #if DHCP_DOES_ARP_CHECK /** * Match an ARP reply with the offered IP address. * * @param netif the network interface on which the reply was received * @param addr The IP address we received a reply from */ void dhcp_arp_reply(struct netif *netif, ip_addr_t *addr) { LWIP_ERROR("netif != NULL", (netif != NULL), return;); LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_arp_reply()\n")); /* is a DHCP client doing an ARP check? */ if ((netif->dhcp != NULL) && (netif->dhcp->state == DHCP_CHECKING)) { LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_arp_reply(): CHECKING, arp reply for 0x%08"X32_F"\n", ip4_addr_get_u32(addr))); /* did a host respond with the address we were offered by the DHCP server? */ if (ip_addr_cmp(addr, &netif->dhcp->offered_ip_addr)) { /* we will not accept the offered address */ LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | LWIP_DBG_LEVEL_WARNING, ("dhcp_arp_reply(): arp reply matched with offered address, declining\n")); dhcp_decline(netif); } } } /** * Decline an offered lease. * * Tell the DHCP server we do not accept the offered address. * One reason to decline the lease is when we find out the address * is already in use by another host (through ARP). * * @param netif the netif under DHCP control */ static err_t dhcp_decline(struct netif *netif) { struct dhcp *dhcp = netif->dhcp; err_t result = ERR_OK; u16_t msecs; LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_decline()\n")); dhcp_set_state(dhcp, DHCP_BACKING_OFF); /* create and initialize the DHCP message header */ result = dhcp_create_msg(netif, dhcp, DHCP_DECLINE); if (result == ERR_OK) { dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4); dhcp_option_long(dhcp, ntohl(ip4_addr_get_u32(&dhcp->offered_ip_addr))); dhcp_option_trailer(dhcp); /* resize pbuf to reflect true size of options */ pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len); /* per section 4.4.4, broadcast DECLINE messages */ udp_sendto_if_src(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif, IP_ADDR_ANY); dhcp_delete_msg(dhcp); LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_decline: BACKING OFF\n")); } else { LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp_decline: could not allocate DHCP request\n")); } dhcp->tries++; msecs = 10*1000; dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS; LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_decline(): set request timeout %"U16_F" msecs\n", msecs)); return result; } #endif /* DHCP_DOES_ARP_CHECK */ /** * Start the DHCP process, discover a DHCP server. * * @param netif the netif under DHCP control */ static err_t dhcp_discover(struct netif *netif) { struct dhcp *dhcp = netif->dhcp; err_t result = ERR_OK; u16_t msecs; LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_discover()\n")); ip_addr_set_any(&dhcp->offered_ip_addr); dhcp_set_state(dhcp, DHCP_SELECTING); /* create and initialize the DHCP message header */ result = dhcp_create_msg(netif, dhcp, DHCP_DISCOVER); if (result == ERR_OK) { LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_discover: making request\n")); dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN); dhcp_option_short(dhcp, DHCP_MAX_MSG_LEN(netif)); dhcp_option(dhcp, DHCP_OPTION_PARAMETER_REQUEST_LIST, 4/*num options*/); dhcp_option_byte(dhcp, DHCP_OPTION_SUBNET_MASK); dhcp_option_byte(dhcp, DHCP_OPTION_ROUTER); dhcp_option_byte(dhcp, DHCP_OPTION_BROADCAST); dhcp_option_byte(dhcp, DHCP_OPTION_DNS_SERVER); dhcp_option_trailer(dhcp); LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_discover: realloc()ing\n")); pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len); LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_discover: sendto(DISCOVER, IP_ADDR_BROADCAST, DHCP_SERVER_PORT)\n")); udp_sendto_if_src(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif, IP_ADDR_ANY); LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_discover: deleting()ing\n")); dhcp_delete_msg(dhcp); LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_discover: SELECTING\n")); } else { LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp_discover: could not allocate DHCP request\n")); } dhcp->tries++; #if LWIP_DHCP_AUTOIP_COOP if(dhcp->tries >= LWIP_DHCP_AUTOIP_COOP_TRIES && dhcp->autoip_coop_state == DHCP_AUTOIP_COOP_STATE_OFF) { dhcp->autoip_coop_state = DHCP_AUTOIP_COOP_STATE_ON; autoip_start(netif); } #endif /* LWIP_DHCP_AUTOIP_COOP */ msecs = (dhcp->tries < 6 ? 1 << dhcp->tries : 60) * 1000; dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS; LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_discover(): set request timeout %"U16_F" msecs\n", msecs)); return result; } /** * Bind the interface to the offered IP address. * * @param netif network interface to bind to the offered address */ static void dhcp_bind(struct netif *netif) { u32_t timeout; struct dhcp *dhcp; ip_addr_t sn_mask, gw_addr; LWIP_ERROR("dhcp_bind: netif != NULL", (netif != NULL), return;); dhcp = netif->dhcp; LWIP_ERROR("dhcp_bind: dhcp != NULL", (dhcp != NULL), return;); LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_bind(netif=%p) %c%c%"U16_F"\n", (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num)); /* temporary DHCP lease? */ if (dhcp->offered_t1_renew != 0xffffffffUL) { /* set renewal period timer */ LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_bind(): t1 renewal timer %"U32_F" secs\n", dhcp->offered_t1_renew)); timeout = (dhcp->offered_t1_renew + DHCP_COARSE_TIMER_SECS / 2) / DHCP_COARSE_TIMER_SECS; if(timeout > 0xffff) { timeout = 0xffff; } dhcp->t1_timeout = (u16_t)timeout; if (dhcp->t1_timeout == 0) { dhcp->t1_timeout = 1; } LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_bind(): set request timeout %"U32_F" msecs\n", dhcp->offered_t1_renew*1000)); } /* set renewal period timer */ if (dhcp->offered_t2_rebind != 0xffffffffUL) { LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_bind(): t2 rebind timer %"U32_F" secs\n", dhcp->offered_t2_rebind)); timeout = (dhcp->offered_t2_rebind + DHCP_COARSE_TIMER_SECS / 2) / DHCP_COARSE_TIMER_SECS; if(timeout > 0xffff) { timeout = 0xffff; } dhcp->t2_timeout = (u16_t)timeout; if (dhcp->t2_timeout == 0) { dhcp->t2_timeout = 1; } LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_bind(): set request timeout %"U32_F" msecs\n", dhcp->offered_t2_rebind*1000)); } /* If we have sub 1 minute lease, t2 and t1 will kick in at the same time. */ if ((dhcp->t1_timeout >= dhcp->t2_timeout) && (dhcp->t2_timeout > 0)) { dhcp->t1_timeout = 0; } if (dhcp->subnet_mask_given) { /* copy offered network mask */ ip_addr_copy(sn_mask, dhcp->offered_sn_mask); } else { /* subnet mask not given, choose a safe subnet mask given the network class */ u8_t first_octet = ip4_addr1(&dhcp->offered_ip_addr); if (first_octet <= 127) { ip4_addr_set_u32(&sn_mask, PP_HTONL(0xff000000UL)); } else if (first_octet >= 192) { ip4_addr_set_u32(&sn_mask, PP_HTONL(0xffffff00UL)); } else { ip4_addr_set_u32(&sn_mask, PP_HTONL(0xffff0000UL)); } } ip_addr_copy(gw_addr, dhcp->offered_gw_addr); /* gateway address not given? */ if (ip_addr_isany(&gw_addr)) { /* copy network address */ ip_addr_get_network(&gw_addr, &dhcp->offered_ip_addr, &sn_mask); /* use first host address on network as gateway */ ip4_addr_set_u32(&gw_addr, ip4_addr_get_u32(&gw_addr) | PP_HTONL(0x00000001UL)); } #if LWIP_DHCP_AUTOIP_COOP if(dhcp->autoip_coop_state == DHCP_AUTOIP_COOP_STATE_ON) { autoip_stop(netif); dhcp->autoip_coop_state = DHCP_AUTOIP_COOP_STATE_OFF; } #endif /* LWIP_DHCP_AUTOIP_COOP */ LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_bind(): IP: 0x%08"X32_F"\n", ip4_addr_get_u32(&dhcp->offered_ip_addr))); netif_set_ipaddr(netif, &dhcp->offered_ip_addr); LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_bind(): SN: 0x%08"X32_F"\n", ip4_addr_get_u32(&sn_mask))); netif_set_netmask(netif, &sn_mask); LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_bind(): GW: 0x%08"X32_F"\n", ip4_addr_get_u32(&gw_addr))); netif_set_gw(netif, &gw_addr); /* bring the interface up */ netif_set_up(netif); /* netif is now bound to DHCP leased address */ dhcp_set_state(dhcp, DHCP_BOUND); } /** * Renew an existing DHCP lease at the involved DHCP server. * * @param netif network interface which must renew its lease */ err_t dhcp_renew(struct netif *netif) { struct dhcp *dhcp = netif->dhcp; err_t result; u16_t msecs; LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_renew()\n")); dhcp_set_state(dhcp, DHCP_RENEWING); /* create and initialize the DHCP message header */ result = dhcp_create_msg(netif, dhcp, DHCP_REQUEST); if (result == ERR_OK) { dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN); dhcp_option_short(dhcp, DHCP_MAX_MSG_LEN(netif)); #if 0 dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4); dhcp_option_long(dhcp, ntohl(dhcp->offered_ip_addr.addr)); #endif #if 0 dhcp_option(dhcp, DHCP_OPTION_SERVER_ID, 4); dhcp_option_long(dhcp, ntohl(dhcp->server_ip_addr.addr)); #endif #if LWIP_NETIF_HOSTNAME dhcp_option_hostname(dhcp, netif); #endif /* LWIP_NETIF_HOSTNAME */ /* append DHCP message trailer */ dhcp_option_trailer(dhcp); pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len); udp_sendto_if(dhcp->pcb, dhcp->p_out, &dhcp->server_ip_addr, DHCP_SERVER_PORT, netif); dhcp_delete_msg(dhcp); LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_renew: RENEWING\n")); } else { LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp_renew: could not allocate DHCP request\n")); } dhcp->tries++; /* back-off on retries, but to a maximum of 20 seconds */ msecs = dhcp->tries < 10 ? dhcp->tries * 2000 : 20 * 1000; dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS; LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_renew(): set request timeout %"U16_F" msecs\n", msecs)); return result; } /** * Rebind with a DHCP server for an existing DHCP lease. * * @param netif network interface which must rebind with a DHCP server */ static err_t dhcp_rebind(struct netif *netif) { struct dhcp *dhcp = netif->dhcp; err_t result; u16_t msecs; LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_rebind()\n")); dhcp_set_state(dhcp, DHCP_REBINDING); /* create and initialize the DHCP message header */ result = dhcp_create_msg(netif, dhcp, DHCP_REQUEST); if (result == ERR_OK) { dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN); dhcp_option_short(dhcp, DHCP_MAX_MSG_LEN(netif)); #if LWIP_NETIF_HOSTNAME dhcp_option_hostname(dhcp, netif); #endif /* LWIP_NETIF_HOSTNAME */ #if 0 dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4); dhcp_option_long(dhcp, ntohl(dhcp->offered_ip_addr.addr)); dhcp_option(dhcp, DHCP_OPTION_SERVER_ID, 4); dhcp_option_long(dhcp, ntohl(dhcp->server_ip_addr.addr)); #endif dhcp_option_trailer(dhcp); pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len); /* broadcast to server */ udp_sendto_if(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif); dhcp_delete_msg(dhcp); LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_rebind: REBINDING\n")); } else { LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp_rebind: could not allocate DHCP request\n")); } dhcp->tries++; msecs = dhcp->tries < 10 ? dhcp->tries * 1000 : 10 * 1000; dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS; LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_rebind(): set request timeout %"U16_F" msecs\n", msecs)); return result; } /** * Enter REBOOTING state to verify an existing lease * * @param netif network interface which must reboot */ static err_t dhcp_reboot(struct netif *netif) { struct dhcp *dhcp = netif->dhcp; err_t result; u16_t msecs; LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_reboot()\n")); dhcp_set_state(dhcp, DHCP_REBOOTING); /* create and initialize the DHCP message header */ result = dhcp_create_msg(netif, dhcp, DHCP_REQUEST); if (result == ERR_OK) { dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN); dhcp_option_short(dhcp, 576); dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4); dhcp_option_long(dhcp, ntohl(ip4_addr_get_u32(&dhcp->offered_ip_addr))); dhcp_option_trailer(dhcp); pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len); /* broadcast to server */ udp_sendto_if(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif); dhcp_delete_msg(dhcp); LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_reboot: REBOOTING\n")); } else { LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp_reboot: could not allocate DHCP request\n")); } dhcp->tries++; msecs = dhcp->tries < 10 ? dhcp->tries * 1000 : 10 * 1000; dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS; LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_reboot(): set request timeout %"U16_F" msecs\n", msecs)); return result; } /** * Release a DHCP lease. * * @param netif network interface which must release its lease */ err_t dhcp_release(struct netif *netif) { struct dhcp *dhcp = netif->dhcp; err_t result; u16_t msecs; LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_release()\n")); if (dhcp == NULL) { return ERR_ARG; } /* idle DHCP client */ dhcp_set_state(dhcp, DHCP_OFF); /* clean old DHCP offer */ ip_addr_set_zero(&dhcp->server_ip_addr); ip_addr_set_zero(&dhcp->offered_ip_addr); ip_addr_set_zero(&dhcp->offered_sn_mask); ip_addr_set_zero(&dhcp->offered_gw_addr); #if LWIP_DHCP_BOOTP_FILE ip_addr_set_zero(&dhcp->offered_si_addr); #endif /* LWIP_DHCP_BOOTP_FILE */ dhcp->offered_t0_lease = dhcp->offered_t1_renew = dhcp->offered_t2_rebind = 0; /* create and initialize the DHCP message header */ result = dhcp_create_msg(netif, dhcp, DHCP_RELEASE); if (result == ERR_OK) { dhcp_option_trailer(dhcp); pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len); udp_sendto_if(dhcp->pcb, dhcp->p_out, &dhcp->server_ip_addr, DHCP_SERVER_PORT, netif); dhcp_delete_msg(dhcp); LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_release: RELEASED, DHCP_OFF\n")); } else { LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp_release: could not allocate DHCP request\n")); } dhcp->tries++; msecs = dhcp->tries < 10 ? dhcp->tries * 1000 : 10 * 1000; dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS; LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_release(): set request timeout %"U16_F" msecs\n", msecs)); /* bring the interface down */ netif_set_down(netif); /* remove IP address from interface */ netif_set_ipaddr(netif, IP_ADDR_ANY); netif_set_gw(netif, IP_ADDR_ANY); netif_set_netmask(netif, IP_ADDR_ANY); return result; } /** * Remove the DHCP client from the interface. * * @param netif The network interface to stop DHCP on */ void dhcp_stop(struct netif *netif) { struct dhcp *dhcp; LWIP_ERROR("dhcp_stop: netif != NULL", (netif != NULL), return;); dhcp = netif->dhcp; /* Remove the flag that says this netif is handled by DHCP. */ netif->flags &= ~NETIF_FLAG_DHCP; LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_stop()\n")); /* netif is DHCP configured? */ if (dhcp != NULL) { #if LWIP_DHCP_AUTOIP_COOP if(dhcp->autoip_coop_state == DHCP_AUTOIP_COOP_STATE_ON) { autoip_stop(netif); dhcp->autoip_coop_state = DHCP_AUTOIP_COOP_STATE_OFF; } #endif /* LWIP_DHCP_AUTOIP_COOP */ if (dhcp->pcb != NULL) { udp_remove(dhcp->pcb); dhcp->pcb = NULL; } LWIP_ASSERT("reply wasn't freed", dhcp->msg_in == NULL); dhcp_set_state(dhcp, DHCP_OFF); } } /* * Set the DHCP state of a DHCP client. * * If the state changed, reset the number of tries. */ static void dhcp_set_state(struct dhcp *dhcp, u8_t new_state) { if (new_state != dhcp->state) { dhcp->state = new_state; dhcp->tries = 0; dhcp->request_timeout = 0; } } /* * Concatenate an option type and length field to the outgoing * DHCP message. * */ static void dhcp_option(struct dhcp *dhcp, u8_t option_type, u8_t option_len) { LWIP_ASSERT("dhcp_option: dhcp->options_out_len + 2 + option_len <= DHCP_OPTIONS_LEN", dhcp->options_out_len + 2U + option_len <= DHCP_OPTIONS_LEN); dhcp->msg_out->options[dhcp->options_out_len++] = option_type; dhcp->msg_out->options[dhcp->options_out_len++] = option_len; } /* * Concatenate a single byte to the outgoing DHCP message. * */ static void dhcp_option_byte(struct dhcp *dhcp, u8_t value) { LWIP_ASSERT("dhcp_option_byte: dhcp->options_out_len < DHCP_OPTIONS_LEN", dhcp->options_out_len < DHCP_OPTIONS_LEN); dhcp->msg_out->options[dhcp->options_out_len++] = value; } static void dhcp_option_short(struct dhcp *dhcp, u16_t value) { LWIP_ASSERT("dhcp_option_short: dhcp->options_out_len + 2 <= DHCP_OPTIONS_LEN", dhcp->options_out_len + 2U <= DHCP_OPTIONS_LEN); dhcp->msg_out->options[dhcp->options_out_len++] = (u8_t)((value & 0xff00U) >> 8); dhcp->msg_out->options[dhcp->options_out_len++] = (u8_t) (value & 0x00ffU); } static void dhcp_option_long(struct dhcp *dhcp, u32_t value) { LWIP_ASSERT("dhcp_option_long: dhcp->options_out_len + 4 <= DHCP_OPTIONS_LEN", dhcp->options_out_len + 4U <= DHCP_OPTIONS_LEN); dhcp->msg_out->options[dhcp->options_out_len++] = (u8_t)((value & 0xff000000UL) >> 24); dhcp->msg_out->options[dhcp->options_out_len++] = (u8_t)((value & 0x00ff0000UL) >> 16); dhcp->msg_out->options[dhcp->options_out_len++] = (u8_t)((value & 0x0000ff00UL) >> 8); dhcp->msg_out->options[dhcp->options_out_len++] = (u8_t)((value & 0x000000ffUL)); } #if LWIP_NETIF_HOSTNAME static void dhcp_option_hostname(struct dhcp *dhcp, struct netif *netif) { if (netif->hostname != NULL) { size_t namelen = strlen(netif->hostname); if (namelen > 0) { u8_t len; const char *p = netif->hostname; /* Shrink len to available bytes (need 2 bytes for OPTION_HOSTNAME and 1 byte for trailer) */ size_t available = DHCP_OPTIONS_LEN - dhcp->options_out_len - 3; LWIP_ASSERT("DHCP: hostname is too long!", namelen <= available); len = LWIP_MIN(namelen, available); dhcp_option(dhcp, DHCP_OPTION_HOSTNAME, len); while (len--) { dhcp_option_byte(dhcp, *p++); } } } } #endif /* LWIP_NETIF_HOSTNAME */ /** * Extract the DHCP message and the DHCP options. * * Extract the DHCP message and the DHCP options, each into a contiguous * piece of memory. As a DHCP message is variable sized by its options, * and also allows overriding some fields for options, the easy approach * is to first unfold the options into a conitguous piece of memory, and * use that further on. * */ static err_t dhcp_parse_reply(struct dhcp *dhcp, struct pbuf *p) { u8_t *options; u16_t offset; u16_t offset_max; u16_t options_idx; u16_t options_idx_max; struct pbuf *q; int parse_file_as_options = 0; int parse_sname_as_options = 0; /* clear received options */ dhcp_clear_all_options(dhcp); /* check that beginning of dhcp_msg (up to and including chaddr) is in first pbuf */ if (p->len < DHCP_SNAME_OFS) { return ERR_BUF; } dhcp->msg_in = (struct dhcp_msg *)p->payload; #if LWIP_DHCP_BOOTP_FILE /* clear boot file name */ dhcp->boot_file_name[0] = 0; #endif /* LWIP_DHCP_BOOTP_FILE */ /* parse options */ /* start with options field */ options_idx = DHCP_OPTIONS_OFS; /* parse options to the end of the received packet */ options_idx_max = p->tot_len; again: q = p; while((q != NULL) && (options_idx >= q->len)) { options_idx -= q->len; options_idx_max -= q->len; q = q->next; } if (q == NULL) { return ERR_BUF; } offset = options_idx; offset_max = options_idx_max; options = (u8_t*)q->payload; /* at least 1 byte to read and no end marker, then at least 3 bytes to read? */ while((q != NULL) && (options[offset] != DHCP_OPTION_END) && (offset < offset_max)) { u8_t op = options[offset]; u8_t len; u8_t decode_len = 0; int decode_idx = -1; u16_t val_offset = offset + 2; /* len byte might be in the next pbuf */ if (offset + 1 < q->len) { len = options[offset + 1]; } else { len = (q->next != NULL ? ((u8_t*)q->next->payload)[0] : 0); } /* LWIP_DEBUGF(DHCP_DEBUG, ("msg_offset=%"U16_F", q->len=%"U16_F, msg_offset, q->len)); */ decode_len = len; switch(op) { /* case(DHCP_OPTION_END): handled above */ case(DHCP_OPTION_PAD): /* special option: no len encoded */ decode_len = len = 0; /* will be increased below */ offset--; break; case(DHCP_OPTION_SUBNET_MASK): LWIP_ERROR("len == 4", len == 4, return ERR_VAL;); decode_idx = DHCP_OPTION_IDX_SUBNET_MASK; break; case(DHCP_OPTION_ROUTER): decode_len = 4; /* only copy the first given router */ LWIP_ERROR("len >= decode_len", len >= decode_len, return ERR_VAL;); decode_idx = DHCP_OPTION_IDX_ROUTER; break; case(DHCP_OPTION_DNS_SERVER): /* special case: there might be more than one server */ LWIP_ERROR("len % 4 == 0", len % 4 == 0, return ERR_VAL;); /* limit number of DNS servers */ decode_len = LWIP_MIN(len, 4 * DNS_MAX_SERVERS); LWIP_ERROR("len >= decode_len", len >= decode_len, return ERR_VAL;); decode_idx = DHCP_OPTION_IDX_DNS_SERVER; break; case(DHCP_OPTION_LEASE_TIME): LWIP_ERROR("len == 4", len == 4, return ERR_VAL;); decode_idx = DHCP_OPTION_IDX_LEASE_TIME; break; case(DHCP_OPTION_OVERLOAD): LWIP_ERROR("len == 1", len == 1, return ERR_VAL;); decode_idx = DHCP_OPTION_IDX_OVERLOAD; break; case(DHCP_OPTION_MESSAGE_TYPE): LWIP_ERROR("len == 1", len == 1, return ERR_VAL;); decode_idx = DHCP_OPTION_IDX_MSG_TYPE; break; case(DHCP_OPTION_SERVER_ID): LWIP_ERROR("len == 4", len == 4, return ERR_VAL;); decode_idx = DHCP_OPTION_IDX_SERVER_ID; break; case(DHCP_OPTION_T1): LWIP_ERROR("len == 4", len == 4, return ERR_VAL;); decode_idx = DHCP_OPTION_IDX_T1; break; case(DHCP_OPTION_T2): LWIP_ERROR("len == 4", len == 4, return ERR_VAL;); decode_idx = DHCP_OPTION_IDX_T2; break; default: decode_len = 0; LWIP_DEBUGF(DHCP_DEBUG, ("skipping option %"U16_F" in options\n", op)); break; } offset += len + 2; if (decode_len > 0) { u32_t value = 0; u16_t copy_len; decode_next: LWIP_ASSERT("check decode_idx", decode_idx >= 0 && decode_idx < DHCP_OPTION_IDX_MAX); if (!dhcp_option_given(dhcp, decode_idx)) { copy_len = LWIP_MIN(decode_len, 4); pbuf_copy_partial(q, &value, copy_len, val_offset); if (decode_len > 4) { /* decode more than one u32_t */ LWIP_ERROR("decode_len % 4 == 0", decode_len % 4 == 0, return ERR_VAL;); dhcp_got_option(dhcp, decode_idx); dhcp_set_option_value(dhcp, decode_idx, htonl(value)); decode_len -= 4; val_offset += 4; decode_idx++; goto decode_next; } else if (decode_len == 4) { value = ntohl(value); } else { LWIP_ERROR("invalid decode_len", decode_len == 1, return ERR_VAL;); value = ((u8_t*)&value)[0]; } dhcp_got_option(dhcp, decode_idx); dhcp_set_option_value(dhcp, decode_idx, value); } } if (offset >= q->len) { offset -= q->len; offset_max -= q->len; if ((offset < offset_max) && offset_max) { q = q->next; LWIP_ASSERT("next pbuf was null", q); options = (u8_t*)q->payload; } else { /* We've run out of bytes, probably no end marker. Don't proceed. */ break; } } } /* is this an overloaded message? */ if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_OVERLOAD)) { u32_t overload = dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_OVERLOAD); dhcp_clear_option(dhcp, DHCP_OPTION_IDX_OVERLOAD); if (overload == DHCP_OVERLOAD_FILE) { parse_file_as_options = 1; LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("overloaded file field\n")); } else if (overload == DHCP_OVERLOAD_SNAME) { parse_sname_as_options = 1; LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("overloaded sname field\n")); } else if (overload == DHCP_OVERLOAD_SNAME_FILE) { parse_sname_as_options = 1; parse_file_as_options = 1; LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("overloaded sname and file field\n")); } else { LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("invalid overload option: %d\n", (int)overload)); } #if LWIP_DHCP_BOOTP_FILE if (!parse_file_as_options) { /* only do this for ACK messages */ if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_MSG_TYPE) && (dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_MSG_TYPE) == DHCP_ACK)) /* copy bootp file name, don't care for sname (server hostname) */ pbuf_copy_partial(p, dhcp->boot_file_name, DHCP_FILE_LEN-1, DHCP_FILE_OFS); /* make sure the string is really NULL-terminated */ dhcp->boot_file_name[DHCP_FILE_LEN-1] = 0; } #endif /* LWIP_DHCP_BOOTP_FILE */ } if (parse_file_as_options) { /* if both are overloaded, parse file first and then sname (RFC 2131 ch. 4.1) */ parse_file_as_options = 0; options_idx = DHCP_FILE_OFS; options_idx_max = DHCP_FILE_OFS + DHCP_FILE_LEN; goto again; } else if (parse_sname_as_options) { parse_sname_as_options = 0; options_idx = DHCP_SNAME_OFS; options_idx_max = DHCP_SNAME_OFS + DHCP_SNAME_LEN; goto again; } return ERR_OK; } /** * If an incoming DHCP message is in response to us, then trigger the state machine */ static void dhcp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port) { struct netif *netif = (struct netif *)arg; struct dhcp *dhcp = netif->dhcp; struct dhcp_msg *reply_msg = (struct dhcp_msg *)p->payload; u8_t msg_type; u8_t i; LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_recv(pbuf = %p) from DHCP server %"U16_F".%"U16_F".%"U16_F".%"U16_F" port %"U16_F"\n", (void*)p, ip4_addr1_16(addr), ip4_addr2_16(addr), ip4_addr3_16(addr), ip4_addr4_16(addr), port)); LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("pbuf->len = %"U16_F"\n", p->len)); LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("pbuf->tot_len = %"U16_F"\n", p->tot_len)); /* prevent warnings about unused arguments */ LWIP_UNUSED_ARG(pcb); LWIP_UNUSED_ARG(addr); LWIP_UNUSED_ARG(port); LWIP_ASSERT("reply wasn't freed", dhcp->msg_in == NULL); if (p->len < DHCP_MIN_REPLY_LEN) { LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("DHCP reply message or pbuf too short\n")); goto free_pbuf_and_return; } if (reply_msg->op != DHCP_BOOTREPLY) { LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("not a DHCP reply message, but type %"U16_F"\n", (u16_t)reply_msg->op)); goto free_pbuf_and_return; } /* iterate through hardware address and match against DHCP message */ for (i = 0; i < netif->hwaddr_len && i < NETIF_MAX_HWADDR_LEN && i < DHCP_CHADDR_LEN; i++) { if (netif->hwaddr[i] != reply_msg->chaddr[i]) { LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("netif->hwaddr[%"U16_F"]==%02"X16_F" != reply_msg->chaddr[%"U16_F"]==%02"X16_F"\n", (u16_t)i, (u16_t)netif->hwaddr[i], (u16_t)i, (u16_t)reply_msg->chaddr[i])); goto free_pbuf_and_return; } } /* match transaction ID against what we expected */ if (ntohl(reply_msg->xid) != dhcp->xid) { LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("transaction id mismatch reply_msg->xid(%"X32_F")!=dhcp->xid(%"X32_F")\n",ntohl(reply_msg->xid),dhcp->xid)); goto free_pbuf_and_return; } /* option fields could be unfold? */ if (dhcp_parse_reply(dhcp, p) != ERR_OK) { LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("problem unfolding DHCP message - too short on memory?\n")); goto free_pbuf_and_return; } LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("searching DHCP_OPTION_MESSAGE_TYPE\n")); /* obtain pointer to DHCP message type */ if (!dhcp_option_given(dhcp, DHCP_OPTION_IDX_MSG_TYPE)) { LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("DHCP_OPTION_MESSAGE_TYPE option not found\n")); goto free_pbuf_and_return; } /* read DHCP message type */ msg_type = (u8_t)dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_MSG_TYPE); /* message type is DHCP ACK? */ if (msg_type == DHCP_ACK) { LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("DHCP_ACK received\n")); /* in requesting state? */ if (dhcp->state == DHCP_REQUESTING) { dhcp_handle_ack(netif); #if DHCP_DOES_ARP_CHECK /* check if the acknowledged lease address is already in use */ dhcp_check(netif); #else /* bind interface to the acknowledged lease address */ dhcp_bind(netif); #endif } /* already bound to the given lease address? */ else if ((dhcp->state == DHCP_REBOOTING) || (dhcp->state == DHCP_REBINDING) || (dhcp->state == DHCP_RENEWING)) { dhcp_bind(netif); } } /* received a DHCP_NAK in appropriate state? */ else if ((msg_type == DHCP_NAK) && ((dhcp->state == DHCP_REBOOTING) || (dhcp->state == DHCP_REQUESTING) || (dhcp->state == DHCP_REBINDING) || (dhcp->state == DHCP_RENEWING ))) { LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("DHCP_NAK received\n")); dhcp_handle_nak(netif); } /* received a DHCP_OFFER in DHCP_SELECTING state? */ else if ((msg_type == DHCP_OFFER) && (dhcp->state == DHCP_SELECTING)) { LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("DHCP_OFFER received in DHCP_SELECTING state\n")); dhcp->request_timeout = 0; /* remember offered lease */ dhcp_handle_offer(netif); } free_pbuf_and_return: dhcp->msg_in = NULL; pbuf_free(p); } /** * Create a DHCP request, fill in common headers * * @param netif the netif under DHCP control * @param dhcp dhcp control struct * @param message_type message type of the request */ static err_t dhcp_create_msg(struct netif *netif, struct dhcp *dhcp, u8_t message_type) { u16_t i; #ifndef DHCP_GLOBAL_XID /** default global transaction identifier starting value (easy to match * with a packet analyser). We simply increment for each new request. * Predefine DHCP_GLOBAL_XID to a better value or a function call to generate one * at runtime, any supporting function prototypes can be defined in DHCP_GLOBAL_XID_HEADER */ #if DHCP_CREATE_RAND_XID && defined(LWIP_RAND) static u32_t xid; #else /* DHCP_CREATE_RAND_XID && defined(LWIP_RAND) */ static u32_t xid = 0xABCD0000; #endif /* DHCP_CREATE_RAND_XID && defined(LWIP_RAND) */ #else if (!xid_initialised) { xid = DHCP_GLOBAL_XID; xid_initialised = !xid_initialised; } #endif LWIP_ERROR("dhcp_create_msg: netif != NULL", (netif != NULL), return ERR_ARG;); LWIP_ERROR("dhcp_create_msg: dhcp != NULL", (dhcp != NULL), return ERR_VAL;); LWIP_ASSERT("dhcp_create_msg: dhcp->p_out == NULL", dhcp->p_out == NULL); LWIP_ASSERT("dhcp_create_msg: dhcp->msg_out == NULL", dhcp->msg_out == NULL); dhcp->p_out = pbuf_alloc(PBUF_TRANSPORT, sizeof(struct dhcp_msg), PBUF_RAM); if (dhcp->p_out == NULL) { LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp_create_msg(): could not allocate pbuf\n")); return ERR_MEM; } LWIP_ASSERT("dhcp_create_msg: check that first pbuf can hold struct dhcp_msg", (dhcp->p_out->len >= sizeof(struct dhcp_msg))); /* DHCP_REQUEST should reuse 'xid' from DHCPOFFER */ if (message_type != DHCP_REQUEST) { /* reuse transaction identifier in retransmissions */ if (dhcp->tries == 0) { #if DHCP_CREATE_RAND_XID && defined(LWIP_RAND) xid = LWIP_RAND(); #else /* DHCP_CREATE_RAND_XID && defined(LWIP_RAND) */ xid++; #endif /* DHCP_CREATE_RAND_XID && defined(LWIP_RAND) */ } dhcp->xid = xid; } LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("transaction id xid(%"X32_F")\n", xid)); dhcp->msg_out = (struct dhcp_msg *)dhcp->p_out->payload; dhcp->msg_out->op = DHCP_BOOTREQUEST; /* TODO: make link layer independent */ dhcp->msg_out->htype = DHCP_HTYPE_ETH; dhcp->msg_out->hlen = netif->hwaddr_len; dhcp->msg_out->hops = 0; dhcp->msg_out->xid = htonl(dhcp->xid); dhcp->msg_out->secs = 0; /* we don't need the broadcast flag since we can receive unicast traffic before being fully configured! */ dhcp->msg_out->flags = 0; ip_addr_set_zero(&dhcp->msg_out->ciaddr); /* set ciaddr to netif->ip_addr based on message_type and state */ if ((message_type == DHCP_INFORM) || (message_type == DHCP_DECLINE) || ((message_type == DHCP_REQUEST) && /* DHCP_BOUND not used for sending! */ ((dhcp->state==DHCP_RENEWING) || dhcp->state==DHCP_REBINDING))) { ip_addr_copy(dhcp->msg_out->ciaddr, netif->ip_addr); } ip_addr_set_zero(&dhcp->msg_out->yiaddr); ip_addr_set_zero(&dhcp->msg_out->siaddr); ip_addr_set_zero(&dhcp->msg_out->giaddr); for (i = 0; i < DHCP_CHADDR_LEN; i++) { /* copy netif hardware address, pad with zeroes */ dhcp->msg_out->chaddr[i] = (i < netif->hwaddr_len && i < NETIF_MAX_HWADDR_LEN) ? netif->hwaddr[i] : 0/* pad byte*/; } for (i = 0; i < DHCP_SNAME_LEN; i++) { dhcp->msg_out->sname[i] = 0; } for (i = 0; i < DHCP_FILE_LEN; i++) { dhcp->msg_out->file[i] = 0; } dhcp->msg_out->cookie = PP_HTONL(DHCP_MAGIC_COOKIE); dhcp->options_out_len = 0; /* fill options field with an incrementing array (for debugging purposes) */ for (i = 0; i < DHCP_OPTIONS_LEN; i++) { dhcp->msg_out->options[i] = (u8_t)i; /* for debugging only, no matter if truncated */ } /* Add option MESSAGE_TYPE */ dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN); dhcp_option_byte(dhcp, message_type); return ERR_OK; } /** * Free previously allocated memory used to send a DHCP request. * * @param dhcp the dhcp struct to free the request from */ static void dhcp_delete_msg(struct dhcp *dhcp) { LWIP_ERROR("dhcp_delete_msg: dhcp != NULL", (dhcp != NULL), return;); LWIP_ASSERT("dhcp_delete_msg: dhcp->p_out != NULL", dhcp->p_out != NULL); LWIP_ASSERT("dhcp_delete_msg: dhcp->msg_out != NULL", dhcp->msg_out != NULL); if (dhcp->p_out != NULL) { pbuf_free(dhcp->p_out); } dhcp->p_out = NULL; dhcp->msg_out = NULL; } /** * Add a DHCP message trailer * * Adds the END option to the DHCP message, and if * necessary, up to three padding bytes. * * @param dhcp DHCP state structure */ static void dhcp_option_trailer(struct dhcp *dhcp) { LWIP_ERROR("dhcp_option_trailer: dhcp != NULL", (dhcp != NULL), return;); LWIP_ASSERT("dhcp_option_trailer: dhcp->msg_out != NULL\n", dhcp->msg_out != NULL); LWIP_ASSERT("dhcp_option_trailer: dhcp->options_out_len < DHCP_OPTIONS_LEN\n", dhcp->options_out_len < DHCP_OPTIONS_LEN); dhcp->msg_out->options[dhcp->options_out_len++] = DHCP_OPTION_END; /* packet is too small, or not 4 byte aligned? */ while (((dhcp->options_out_len < DHCP_MIN_OPTIONS_LEN) || (dhcp->options_out_len & 3)) && (dhcp->options_out_len < DHCP_OPTIONS_LEN)) { /* add a fill/padding byte */ dhcp->msg_out->options[dhcp->options_out_len++] = 0; } } #endif /* LWIP_DHCP */ ocproxy-1.60/lwip/src/core/dns.c000066400000000000000000000755111303453231400165740ustar00rootroot00000000000000/** * @file * DNS - host name to IP address resolver. * */ /** * This file implements a DNS host name to IP address resolver. * Port to lwIP from uIP * by Jim Pettinato April 2007 * uIP version Copyright (c) 2002-2003, Adam Dunkels. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote * products derived from this software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * * DNS.C * * The lwIP DNS resolver functions are used to lookup a host name and * map it to a numerical IP address. It maintains a list of resolved * hostnames that can be queried with the dns_lookup() function. * New hostnames can be resolved using the dns_query() function. * * The lwIP version of the resolver also adds a non-blocking version of * gethostbyname() that will work with a raw API application. This function * checks for an IP address string first and converts it if it is valid. * gethostbyname() then does a dns_lookup() to see if the name is * already in the table. If so, the IP is returned. If not, a query is * issued and the function returns with a ERR_INPROGRESS status. The app * using the dns client must then go into a waiting state. * * Once a hostname has been resolved (or found to be non-existent), * the resolver code calls a specified callback function (which * must be implemented by the module that uses the resolver). */ /*----------------------------------------------------------------------------- * RFC 1035 - Domain names - implementation and specification * RFC 2181 - Clarifications to the DNS Specification *----------------------------------------------------------------------------*/ /** @todo: define good default values (rfc compliance) */ /** @todo: improve answer parsing, more checkings... */ /** @todo: check RFC1035 - 7.3. Processing responses */ /*----------------------------------------------------------------------------- * Includes *----------------------------------------------------------------------------*/ #include "lwip/opt.h" #if LWIP_DNS /* don't build if not configured for use in lwipopts.h */ #include "lwip/udp.h" #include "lwip/mem.h" #include "lwip/memp.h" #include "lwip/dns.h" #include /** DNS server IP address */ #ifndef DNS_SERVER_ADDRESS #define DNS_SERVER_ADDRESS(ipaddr) (ip4_addr_set_u32(ipaddr, ipaddr_addr("208.67.222.222"))) /* resolver1.opendns.com */ #endif /** DNS server port address */ #ifndef DNS_SERVER_PORT #define DNS_SERVER_PORT 53 #endif /** DNS maximum number of retries when asking for a name, before "timeout". */ #ifndef DNS_MAX_RETRIES #define DNS_MAX_RETRIES 4 #endif /** DNS resource record max. TTL (one week as default) */ #ifndef DNS_MAX_TTL #define DNS_MAX_TTL 604800 #endif /* DNS protocol flags */ #define DNS_FLAG1_RESPONSE 0x80 #define DNS_FLAG1_OPCODE_STATUS 0x10 #define DNS_FLAG1_OPCODE_INVERSE 0x08 #define DNS_FLAG1_OPCODE_STANDARD 0x00 #define DNS_FLAG1_AUTHORATIVE 0x04 #define DNS_FLAG1_TRUNC 0x02 #define DNS_FLAG1_RD 0x01 #define DNS_FLAG2_RA 0x80 #define DNS_FLAG2_ERR_MASK 0x0f #define DNS_FLAG2_ERR_NONE 0x00 #define DNS_FLAG2_ERR_NAME 0x03 /* DNS protocol states */ #define DNS_STATE_UNUSED 0 #define DNS_STATE_NEW 1 #define DNS_STATE_ASKING 2 #define DNS_STATE_DONE 3 #ifdef PACK_STRUCT_USE_INCLUDES # include "arch/bpstruct.h" #endif PACK_STRUCT_BEGIN /** DNS message header */ struct dns_hdr { PACK_STRUCT_FIELD(u16_t id); PACK_STRUCT_FIELD(u8_t flags1); PACK_STRUCT_FIELD(u8_t flags2); PACK_STRUCT_FIELD(u16_t numquestions); PACK_STRUCT_FIELD(u16_t numanswers); PACK_STRUCT_FIELD(u16_t numauthrr); PACK_STRUCT_FIELD(u16_t numextrarr); } PACK_STRUCT_STRUCT; PACK_STRUCT_END #ifdef PACK_STRUCT_USE_INCLUDES # include "arch/epstruct.h" #endif #define SIZEOF_DNS_HDR 12 /** DNS query message structure. No packing needed: only used locally on the stack. */ struct dns_query { /* DNS query record starts with either a domain name or a pointer to a name already present somewhere in the packet. */ u16_t type; u16_t cls; }; #define SIZEOF_DNS_QUERY 4 /** DNS answer message structure. No packing needed: only used locally on the stack. */ struct dns_answer { /* DNS answer record starts with either a domain name or a pointer to a name already present somewhere in the packet. */ u16_t type; u16_t cls; u32_t ttl; u16_t len; }; #define SIZEOF_DNS_ANSWER 10 /** DNS table entry */ struct dns_table_entry { u8_t state; u8_t numdns; u8_t tmr; u8_t retries; u8_t seqno; u8_t err; u32_t ttl; char name[DNS_MAX_NAME_LENGTH]; ip_addr_t ipaddr; /* pointer to callback on DNS query done */ dns_found_callback found; void *arg; }; #if DNS_LOCAL_HOSTLIST #if DNS_LOCAL_HOSTLIST_IS_DYNAMIC /** Local host-list. For hostnames in this list, no * external name resolution is performed */ static struct local_hostlist_entry *local_hostlist_dynamic; #else /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ /** Defining this allows the local_hostlist_static to be placed in a different * linker section (e.g. FLASH) */ #ifndef DNS_LOCAL_HOSTLIST_STORAGE_PRE #define DNS_LOCAL_HOSTLIST_STORAGE_PRE static #endif /* DNS_LOCAL_HOSTLIST_STORAGE_PRE */ /** Defining this allows the local_hostlist_static to be placed in a different * linker section (e.g. FLASH) */ #ifndef DNS_LOCAL_HOSTLIST_STORAGE_POST #define DNS_LOCAL_HOSTLIST_STORAGE_POST #endif /* DNS_LOCAL_HOSTLIST_STORAGE_POST */ DNS_LOCAL_HOSTLIST_STORAGE_PRE struct local_hostlist_entry local_hostlist_static[] DNS_LOCAL_HOSTLIST_STORAGE_POST = DNS_LOCAL_HOSTLIST_INIT; #endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ static void dns_init_local(); #endif /* DNS_LOCAL_HOSTLIST */ /* forward declarations */ static void dns_recv(void *s, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port); static void dns_check_entries(void); /*----------------------------------------------------------------------------- * Globales *----------------------------------------------------------------------------*/ /* DNS variables */ static struct udp_pcb *dns_pcb; static u8_t dns_seqno; static struct dns_table_entry dns_table[DNS_TABLE_SIZE]; static ip_addr_t dns_servers[DNS_MAX_SERVERS]; /** Contiguous buffer for processing responses */ static u8_t dns_payload_buffer[LWIP_MEM_ALIGN_BUFFER(DNS_MSG_SIZE)]; static u8_t* dns_payload; /** * Initialize the resolver: set up the UDP pcb and configure the default server * (DNS_SERVER_ADDRESS). */ void dns_init() { ip_addr_t dnsserver; dns_payload = (u8_t *)LWIP_MEM_ALIGN(dns_payload_buffer); /* initialize default DNS server address */ DNS_SERVER_ADDRESS(&dnsserver); LWIP_DEBUGF(DNS_DEBUG, ("dns_init: initializing\n")); /* if dns client not yet initialized... */ if (dns_pcb == NULL) { dns_pcb = udp_new(); if (dns_pcb != NULL) { /* initialize DNS table not needed (initialized to zero since it is a * global variable) */ LWIP_ASSERT("For implicit initialization to work, DNS_STATE_UNUSED needs to be 0", DNS_STATE_UNUSED == 0); /* initialize DNS client */ udp_bind(dns_pcb, IP_ADDR_ANY, 0); udp_recv(dns_pcb, dns_recv, NULL); /* initialize default DNS primary server */ dns_setserver(0, &dnsserver); } } #if DNS_LOCAL_HOSTLIST dns_init_local(); #endif } /** * Initialize one of the DNS servers. * * @param numdns the index of the DNS server to set must be < DNS_MAX_SERVERS * @param dnsserver IP address of the DNS server to set */ void dns_setserver(u8_t numdns, ip_addr_t *dnsserver) { if ((numdns < DNS_MAX_SERVERS) && (dns_pcb != NULL) && (dnsserver != NULL) && !ip_addr_isany(dnsserver)) { dns_servers[numdns] = (*dnsserver); } } /** * Obtain one of the currently configured DNS server. * * @param numdns the index of the DNS server * @return IP address of the indexed DNS server or "ip_addr_any" if the DNS * server has not been configured. */ ip_addr_t dns_getserver(u8_t numdns) { if (numdns < DNS_MAX_SERVERS) { return dns_servers[numdns]; } else { return *IP_ADDR_ANY; } } /** * The DNS resolver client timer - handle retries and timeouts and should * be called every DNS_TMR_INTERVAL milliseconds (every second by default). */ void dns_tmr(void) { if (dns_pcb != NULL) { LWIP_DEBUGF(DNS_DEBUG, ("dns_tmr: dns_check_entries\n")); dns_check_entries(); } } #if DNS_LOCAL_HOSTLIST static void dns_init_local() { #if DNS_LOCAL_HOSTLIST_IS_DYNAMIC && defined(DNS_LOCAL_HOSTLIST_INIT) int i; struct local_hostlist_entry *entry; /* Dynamic: copy entries from DNS_LOCAL_HOSTLIST_INIT to list */ struct local_hostlist_entry local_hostlist_init[] = DNS_LOCAL_HOSTLIST_INIT; size_t namelen; for (i = 0; i < sizeof(local_hostlist_init) / sizeof(struct local_hostlist_entry); i++) { struct local_hostlist_entry *init_entry = &local_hostlist_init[i]; LWIP_ASSERT("invalid host name (NULL)", init_entry->name != NULL); namelen = strlen(init_entry->name); LWIP_ASSERT("namelen <= DNS_LOCAL_HOSTLIST_MAX_NAMELEN", namelen <= DNS_LOCAL_HOSTLIST_MAX_NAMELEN); entry = (struct local_hostlist_entry *)memp_malloc(MEMP_LOCALHOSTLIST); LWIP_ASSERT("mem-error in dns_init_local", entry != NULL); if (entry != NULL) { entry->name = (char*)entry + sizeof(struct local_hostlist_entry); MEMCPY((char*)entry->name, init_entry->name, namelen); ((char*)entry->name)[namelen] = 0; entry->addr = init_entry->addr; entry->next = local_hostlist_dynamic; local_hostlist_dynamic = entry; } } #endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC && defined(DNS_LOCAL_HOSTLIST_INIT) */ } /** * Scans the local host-list for a hostname. * * @param hostname Hostname to look for in the local host-list * @return The first IP address for the hostname in the local host-list or * IPADDR_NONE if not found. */ static u32_t dns_lookup_local(const char *hostname) { #if DNS_LOCAL_HOSTLIST_IS_DYNAMIC struct local_hostlist_entry *entry = local_hostlist_dynamic; while(entry != NULL) { if(strcmp(entry->name, hostname) == 0) { return ip4_addr_get_u32(&entry->addr); } entry = entry->next; } #else /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ int i; for (i = 0; i < sizeof(local_hostlist_static) / sizeof(struct local_hostlist_entry); i++) { if(strcmp(local_hostlist_static[i].name, hostname) == 0) { return ip4_addr_get_u32(&local_hostlist_static[i].addr); } } #endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ return IPADDR_NONE; } #if DNS_LOCAL_HOSTLIST_IS_DYNAMIC /** Remove all entries from the local host-list for a specific hostname * and/or IP addess * * @param hostname hostname for which entries shall be removed from the local * host-list * @param addr address for which entries shall be removed from the local host-list * @return the number of removed entries */ int dns_local_removehost(const char *hostname, const ip_addr_t *addr) { int removed = 0; struct local_hostlist_entry *entry = local_hostlist_dynamic; struct local_hostlist_entry *last_entry = NULL; while (entry != NULL) { if (((hostname == NULL) || !strcmp(entry->name, hostname)) && ((addr == NULL) || ip_addr_cmp(&entry->addr, addr))) { struct local_hostlist_entry *free_entry; if (last_entry != NULL) { last_entry->next = entry->next; } else { local_hostlist_dynamic = entry->next; } free_entry = entry; entry = entry->next; memp_free(MEMP_LOCALHOSTLIST, free_entry); removed++; } else { last_entry = entry; entry = entry->next; } } return removed; } /** * Add a hostname/IP address pair to the local host-list. * Duplicates are not checked. * * @param hostname hostname of the new entry * @param addr IP address of the new entry * @return ERR_OK if succeeded or ERR_MEM on memory error */ err_t dns_local_addhost(const char *hostname, const ip_addr_t *addr) { struct local_hostlist_entry *entry; size_t namelen; LWIP_ASSERT("invalid host name (NULL)", hostname != NULL); namelen = strlen(hostname); LWIP_ASSERT("namelen <= DNS_LOCAL_HOSTLIST_MAX_NAMELEN", namelen <= DNS_LOCAL_HOSTLIST_MAX_NAMELEN); entry = (struct local_hostlist_entry *)memp_malloc(MEMP_LOCALHOSTLIST); if (entry == NULL) { return ERR_MEM; } entry->name = (char*)entry + sizeof(struct local_hostlist_entry); MEMCPY((char*)entry->name, hostname, namelen); ((char*)entry->name)[namelen] = 0; ip_addr_copy(entry->addr, *addr); entry->next = local_hostlist_dynamic; local_hostlist_dynamic = entry; return ERR_OK; } #endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC*/ #endif /* DNS_LOCAL_HOSTLIST */ /** * Look up a hostname in the array of known hostnames. * * @note This function only looks in the internal array of known * hostnames, it does not send out a query for the hostname if none * was found. The function dns_enqueue() can be used to send a query * for a hostname. * * @param name the hostname to look up * @return the hostname's IP address, as u32_t (instead of ip_addr_t to * better check for failure: != IPADDR_NONE) or IPADDR_NONE if the hostname * was not found in the cached dns_table. */ static u32_t dns_lookup(const char *name) { u8_t i; #if DNS_LOCAL_HOSTLIST || defined(DNS_LOOKUP_LOCAL_EXTERN) u32_t addr; #endif /* DNS_LOCAL_HOSTLIST || defined(DNS_LOOKUP_LOCAL_EXTERN) */ #if DNS_LOCAL_HOSTLIST if ((addr = dns_lookup_local(name)) != IPADDR_NONE) { return addr; } #endif /* DNS_LOCAL_HOSTLIST */ #ifdef DNS_LOOKUP_LOCAL_EXTERN if((addr = DNS_LOOKUP_LOCAL_EXTERN(name)) != IPADDR_NONE) { return addr; } #endif /* DNS_LOOKUP_LOCAL_EXTERN */ /* Walk through name list, return entry if found. If not, return NULL. */ for (i = 0; i < DNS_TABLE_SIZE; ++i) { if ((dns_table[i].state == DNS_STATE_DONE) && (strcmp(name, dns_table[i].name) == 0)) { LWIP_DEBUGF(DNS_DEBUG, ("dns_lookup: \"%s\": found = ", name)); ip_addr_debug_print(DNS_DEBUG, &(dns_table[i].ipaddr)); LWIP_DEBUGF(DNS_DEBUG, ("\n")); return ip4_addr_get_u32(&dns_table[i].ipaddr); } } return IPADDR_NONE; } #if DNS_DOES_NAME_CHECK /** * Compare the "dotted" name "query" with the encoded name "response" * to make sure an answer from the DNS server matches the current dns_table * entry (otherwise, answers might arrive late for hostname not on the list * any more). * * @param query hostname (not encoded) from the dns_table * @param response encoded hostname in the DNS response * @return 0: names equal; 1: names differ */ static u8_t dns_compare_name(unsigned char *query, unsigned char *response) { unsigned char n; do { n = *response++; /** @see RFC 1035 - 4.1.4. Message compression */ if ((n & 0xc0) == 0xc0) { /* Compressed name */ break; } else { /* Not compressed name */ while (n > 0) { if ((*query) != (*response)) { return 1; } ++response; ++query; --n; }; ++query; } } while (*response != 0); return 0; } #endif /* DNS_DOES_NAME_CHECK */ /** * Walk through a compact encoded DNS name and return the end of the name. * * @param query encoded DNS name in the DNS server response * @return end of the name */ static unsigned char * dns_parse_name(unsigned char *query) { unsigned char n; do { n = *query++; /** @see RFC 1035 - 4.1.4. Message compression */ if ((n & 0xc0) == 0xc0) { /* Compressed name */ break; } else { /* Not compressed name */ while (n > 0) { ++query; --n; }; } } while (*query != 0); return query + 1; } /** * Send a DNS query packet. * * @param numdns index of the DNS server in the dns_servers table * @param name hostname to query * @param id index of the hostname in dns_table, used as transaction ID in the * DNS query packet * @return ERR_OK if packet is sent; an err_t indicating the problem otherwise */ static err_t dns_send(u8_t numdns, const char* name, u8_t id) { err_t err; struct dns_hdr *hdr; struct dns_query qry; struct pbuf *p; char *query, *nptr; const char *pHostname; u8_t n; LWIP_DEBUGF(DNS_DEBUG, ("dns_send: dns_servers[%"U16_F"] \"%s\": request\n", (u16_t)(numdns), name)); LWIP_ASSERT("dns server out of array", numdns < DNS_MAX_SERVERS); LWIP_ASSERT("dns server has no IP address set", !ip_addr_isany(&dns_servers[numdns])); /* if here, we have either a new query or a retry on a previous query to process */ p = pbuf_alloc(PBUF_TRANSPORT, SIZEOF_DNS_HDR + DNS_MAX_NAME_LENGTH + 1 + SIZEOF_DNS_QUERY, PBUF_RAM); if (p != NULL) { u16_t realloc_size; LWIP_ASSERT("pbuf must be in one piece", p->next == NULL); /* fill dns header */ hdr = (struct dns_hdr*)p->payload; memset(hdr, 0, SIZEOF_DNS_HDR); hdr->id = htons(id); hdr->flags1 = DNS_FLAG1_RD; hdr->numquestions = PP_HTONS(1); query = (char*)hdr + SIZEOF_DNS_HDR; pHostname = name; --pHostname; /* convert hostname into suitable query format. */ do { ++pHostname; nptr = query; ++query; for(n = 0; *pHostname != '.' && *pHostname != 0; ++pHostname) { *query = *pHostname; ++query; ++n; } *nptr = n; } while(*pHostname != 0); *query++='\0'; /* fill dns query */ qry.type = PP_HTONS(DNS_RRTYPE_A); qry.cls = PP_HTONS(DNS_RRCLASS_IN); SMEMCPY(query, &qry, SIZEOF_DNS_QUERY); /* resize pbuf to the exact dns query */ realloc_size = (u16_t)((query + SIZEOF_DNS_QUERY) - ((char*)(p->payload))); LWIP_ASSERT("p->tot_len >= realloc_size", p->tot_len >= realloc_size); pbuf_realloc(p, realloc_size); /* connect to the server for faster receiving */ udp_connect(dns_pcb, &dns_servers[numdns], DNS_SERVER_PORT); /* send dns packet */ err = udp_sendto(dns_pcb, p, &dns_servers[numdns], DNS_SERVER_PORT); /* free pbuf */ pbuf_free(p); } else { err = ERR_MEM; } return err; } /** * dns_check_entry() - see if pEntry has not yet been queried and, if so, sends out a query. * Check an entry in the dns_table: * - send out query for new entries * - retry old pending entries on timeout (also with different servers) * - remove completed entries from the table if their TTL has expired * * @param i index of the dns_table entry to check */ static void dns_check_entry(u8_t i) { err_t err; struct dns_table_entry *pEntry = &dns_table[i]; LWIP_ASSERT("array index out of bounds", i < DNS_TABLE_SIZE); switch(pEntry->state) { case DNS_STATE_NEW: { /* initialize new entry */ pEntry->state = DNS_STATE_ASKING; pEntry->numdns = 0; pEntry->tmr = 1; pEntry->retries = 0; /* send DNS packet for this entry */ err = dns_send(pEntry->numdns, pEntry->name, i); if (err != ERR_OK) { LWIP_DEBUGF(DNS_DEBUG | LWIP_DBG_LEVEL_WARNING, ("dns_send returned error: %s\n", lwip_strerr(err))); } break; } case DNS_STATE_ASKING: { if (--pEntry->tmr == 0) { if (++pEntry->retries == DNS_MAX_RETRIES) { if ((pEntry->numdns+1numdns+1])) { /* change of server */ pEntry->numdns++; pEntry->tmr = 1; pEntry->retries = 0; break; } else { LWIP_DEBUGF(DNS_DEBUG, ("dns_check_entry: \"%s\": timeout\n", pEntry->name)); /* call specified callback function if provided */ if (pEntry->found) (*pEntry->found)(pEntry->name, NULL, pEntry->arg); /* flush this entry */ pEntry->state = DNS_STATE_UNUSED; pEntry->found = NULL; break; } } /* wait longer for the next retry */ pEntry->tmr = pEntry->retries; /* send DNS packet for this entry */ err = dns_send(pEntry->numdns, pEntry->name, i); if (err != ERR_OK) { LWIP_DEBUGF(DNS_DEBUG | LWIP_DBG_LEVEL_WARNING, ("dns_send returned error: %s\n", lwip_strerr(err))); } } break; } case DNS_STATE_DONE: { /* if the time to live is nul */ if ((pEntry->ttl == 0) || (--pEntry->ttl == 0)) { LWIP_DEBUGF(DNS_DEBUG, ("dns_check_entry: \"%s\": flush\n", pEntry->name)); /* flush this entry */ pEntry->state = DNS_STATE_UNUSED; pEntry->found = NULL; } break; } case DNS_STATE_UNUSED: /* nothing to do */ break; default: LWIP_ASSERT("unknown dns_table entry state:", 0); break; } } /** * Call dns_check_entry for each entry in dns_table - check all entries. */ static void dns_check_entries(void) { u8_t i; for (i = 0; i < DNS_TABLE_SIZE; ++i) { dns_check_entry(i); } } /** * Receive input function for DNS response packets arriving for the dns UDP pcb. * * @params see udp.h */ static void dns_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port) { u16_t i; char *pHostname; struct dns_hdr *hdr; struct dns_answer ans; struct dns_table_entry *pEntry; u16_t nquestions, nanswers; LWIP_UNUSED_ARG(arg); LWIP_UNUSED_ARG(pcb); LWIP_UNUSED_ARG(addr); LWIP_UNUSED_ARG(port); /* is the dns message too big ? */ if (p->tot_len > DNS_MSG_SIZE) { LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: pbuf too big\n")); /* free pbuf and return */ goto memerr; } /* is the dns message big enough ? */ if (p->tot_len < (SIZEOF_DNS_HDR + SIZEOF_DNS_QUERY + SIZEOF_DNS_ANSWER)) { LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: pbuf too small\n")); /* free pbuf and return */ goto memerr; } /* copy dns payload inside static buffer for processing */ if (pbuf_copy_partial(p, dns_payload, p->tot_len, 0) == p->tot_len) { /* The ID in the DNS header should be our entry into the name table. */ hdr = (struct dns_hdr*)dns_payload; i = htons(hdr->id); if (i < DNS_TABLE_SIZE) { pEntry = &dns_table[i]; if(pEntry->state == DNS_STATE_ASKING) { /* This entry is now completed. */ pEntry->state = DNS_STATE_DONE; pEntry->err = hdr->flags2 & DNS_FLAG2_ERR_MASK; /* We only care about the question(s) and the answers. The authrr and the extrarr are simply discarded. */ nquestions = htons(hdr->numquestions); nanswers = htons(hdr->numanswers); /* Check for error. If so, call callback to inform. */ if (((hdr->flags1 & DNS_FLAG1_RESPONSE) == 0) || (pEntry->err != 0) || (nquestions != 1)) { LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": error in flags\n", pEntry->name)); /* call callback to indicate error, clean up memory and return */ goto responseerr; } #if DNS_DOES_NAME_CHECK /* Check if the name in the "question" part match with the name in the entry. */ if (dns_compare_name((unsigned char *)(pEntry->name), (unsigned char *)dns_payload + SIZEOF_DNS_HDR) != 0) { LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": response not match to query\n", pEntry->name)); /* call callback to indicate error, clean up memory and return */ goto responseerr; } #endif /* DNS_DOES_NAME_CHECK */ /* Skip the name in the "question" part */ pHostname = (char *) dns_parse_name((unsigned char *)dns_payload + SIZEOF_DNS_HDR) + SIZEOF_DNS_QUERY; while (nanswers > 0) { /* skip answer resource record's host name */ pHostname = (char *) dns_parse_name((unsigned char *)pHostname); /* Check for IP address type and Internet class. Others are discarded. */ SMEMCPY(&ans, pHostname, SIZEOF_DNS_ANSWER); if((ans.type == PP_HTONS(DNS_RRTYPE_A)) && (ans.cls == PP_HTONS(DNS_RRCLASS_IN)) && (ans.len == PP_HTONS(sizeof(ip_addr_t))) ) { /* read the answer resource record's TTL, and maximize it if needed */ pEntry->ttl = ntohl(ans.ttl); if (pEntry->ttl > DNS_MAX_TTL) { pEntry->ttl = DNS_MAX_TTL; } /* read the IP address after answer resource record's header */ SMEMCPY(&(pEntry->ipaddr), (pHostname+SIZEOF_DNS_ANSWER), sizeof(ip_addr_t)); LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": response = ", pEntry->name)); ip_addr_debug_print(DNS_DEBUG, (&(pEntry->ipaddr))); LWIP_DEBUGF(DNS_DEBUG, ("\n")); /* call specified callback function if provided */ if (pEntry->found) { (*pEntry->found)(pEntry->name, &pEntry->ipaddr, pEntry->arg); } if (pEntry->ttl == 0) { /* RFC 883, page 29: "Zero values are interpreted to mean that the RR can only be used for the transaction in progress, and should not be cached." -> flush this entry now */ goto flushentry; } /* deallocate memory and return */ goto memerr; } else { pHostname = pHostname + SIZEOF_DNS_ANSWER + htons(ans.len); } --nanswers; } LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": error in response\n", pEntry->name)); /* call callback to indicate error, clean up memory and return */ goto responseerr; } } } /* deallocate memory and return */ goto memerr; responseerr: /* ERROR: call specified callback function with NULL as name to indicate an error */ if (pEntry->found) { (*pEntry->found)(pEntry->name, NULL, pEntry->arg); } flushentry: /* flush this entry */ pEntry->state = DNS_STATE_UNUSED; pEntry->found = NULL; memerr: /* free pbuf */ pbuf_free(p); return; } /** * Queues a new hostname to resolve and sends out a DNS query for that hostname * * @param name the hostname that is to be queried * @param hostnamelen length of the hostname * @param found a callback founction to be called on success, failure or timeout * @param callback_arg argument to pass to the callback function * @return @return a err_t return code. */ static err_t dns_enqueue(const char *name, size_t hostnamelen, dns_found_callback found, void *callback_arg) { u8_t i; u8_t lseq, lseqi; struct dns_table_entry *pEntry = NULL; size_t namelen; /* search an unused entry, or the oldest one */ lseq = lseqi = 0; for (i = 0; i < DNS_TABLE_SIZE; ++i) { pEntry = &dns_table[i]; /* is it an unused entry ? */ if (pEntry->state == DNS_STATE_UNUSED) break; /* check if this is the oldest completed entry */ if (pEntry->state == DNS_STATE_DONE) { if ((u8_t)(dns_seqno - pEntry->seqno) > lseq) { lseq = dns_seqno - pEntry->seqno; lseqi = i; } } } /* if we don't have found an unused entry, use the oldest completed one */ if (i == DNS_TABLE_SIZE) { if ((lseqi >= DNS_TABLE_SIZE) || (dns_table[lseqi].state != DNS_STATE_DONE)) { /* no entry can't be used now, table is full */ LWIP_DEBUGF(DNS_DEBUG, ("dns_enqueue: \"%s\": DNS entries table is full\n", name)); return ERR_MEM; } else { /* use the oldest completed one */ i = lseqi; pEntry = &dns_table[i]; } } /* use this entry */ LWIP_DEBUGF(DNS_DEBUG, ("dns_enqueue: \"%s\": use DNS entry %"U16_F"\n", name, (u16_t)(i))); /* fill the entry */ pEntry->state = DNS_STATE_NEW; pEntry->seqno = dns_seqno++; pEntry->found = found; pEntry->arg = callback_arg; namelen = LWIP_MIN(hostnamelen, DNS_MAX_NAME_LENGTH-1); MEMCPY(pEntry->name, name, namelen); pEntry->name[namelen] = 0; /* force to send query without waiting timer */ dns_check_entry(i); /* dns query is enqueued */ return ERR_INPROGRESS; } /** * Resolve a hostname (string) into an IP address. * NON-BLOCKING callback version for use with raw API!!! * * Returns immediately with one of err_t return codes: * - ERR_OK if hostname is a valid IP address string or the host * name is already in the local names table. * - ERR_INPROGRESS enqueue a request to be sent to the DNS server * for resolution if no errors are present. * - ERR_ARG: dns client not initialized or invalid hostname * * @param hostname the hostname that is to be queried * @param addr pointer to a ip_addr_t where to store the address if it is already * cached in the dns_table (only valid if ERR_OK is returned!) * @param found a callback function to be called on success, failure or timeout (only if * ERR_INPROGRESS is returned!) * @param callback_arg argument to pass to the callback function * @return a err_t return code. */ err_t dns_gethostbyname(const char *hostname, ip_addr_t *addr, dns_found_callback found, void *callback_arg) { u32_t ipaddr; size_t hostnamelen; /* not initialized or no valid server yet, or invalid addr pointer * or invalid hostname or invalid hostname length */ if ((dns_pcb == NULL) || (addr == NULL) || (!hostname) || (!hostname[0])) { return ERR_ARG; } hostnamelen = strlen(hostname); if (hostnamelen >= DNS_MAX_NAME_LENGTH) { return ERR_ARG; } #if LWIP_HAVE_LOOPIF if (strcmp(hostname, "localhost")==0) { ip_addr_set_loopback(addr); return ERR_OK; } #endif /* LWIP_HAVE_LOOPIF */ /* host name already in octet notation? set ip addr and return ERR_OK */ ipaddr = ipaddr_addr(hostname); if (ipaddr == IPADDR_NONE) { /* already have this address cached? */ ipaddr = dns_lookup(hostname); } if (ipaddr != IPADDR_NONE) { ip4_addr_set_u32(addr, ipaddr); return ERR_OK; } /* queue query with specified callback */ return dns_enqueue(hostname, hostnamelen, found, callback_arg); } #endif /* LWIP_DNS */ ocproxy-1.60/lwip/src/core/inet_chksum.c000066400000000000000000000401261303453231400203130ustar00rootroot00000000000000/** * @file * Incluse internet checksum functions. * */ /* * Copyright (c) 2001-2004 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #include "lwip/opt.h" #include "lwip/inet_chksum.h" #include "lwip/def.h" #include #include /* These are some reference implementations of the checksum algorithm, with the * aim of being simple, correct and fully portable. Checksumming is the * first thing you would want to optimize for your platform. If you create * your own version, link it in and in your cc.h put: * * #define LWIP_CHKSUM * * Or you can select from the implementations below by defining * LWIP_CHKSUM_ALGORITHM to 1, 2 or 3. */ #ifndef LWIP_CHKSUM # define LWIP_CHKSUM lwip_standard_chksum # ifndef LWIP_CHKSUM_ALGORITHM # define LWIP_CHKSUM_ALGORITHM 2 # endif u16_t lwip_standard_chksum(void *dataptr, int len); #endif /* If none set: */ #ifndef LWIP_CHKSUM_ALGORITHM # define LWIP_CHKSUM_ALGORITHM 0 #endif #if (LWIP_CHKSUM_ALGORITHM == 1) /* Version #1 */ /** * lwip checksum * * @param dataptr points to start of data to be summed at any boundary * @param len length of data to be summed * @return host order (!) lwip checksum (non-inverted Internet sum) * * @note accumulator size limits summable length to 64k * @note host endianess is irrelevant (p3 RFC1071) */ u16_t lwip_standard_chksum(void *dataptr, u16_t len) { u32_t acc; u16_t src; u8_t *octetptr; acc = 0; /* dataptr may be at odd or even addresses */ octetptr = (u8_t*)dataptr; while (len > 1) { /* declare first octet as most significant thus assume network order, ignoring host order */ src = (*octetptr) << 8; octetptr++; /* declare second octet as least significant */ src |= (*octetptr); octetptr++; acc += src; len -= 2; } if (len > 0) { /* accumulate remaining octet */ src = (*octetptr) << 8; acc += src; } /* add deferred carry bits */ acc = (acc >> 16) + (acc & 0x0000ffffUL); if ((acc & 0xffff0000UL) != 0) { acc = (acc >> 16) + (acc & 0x0000ffffUL); } /* This maybe a little confusing: reorder sum using htons() instead of ntohs() since it has a little less call overhead. The caller must invert bits for Internet sum ! */ return htons((u16_t)acc); } #endif #if (LWIP_CHKSUM_ALGORITHM == 2) /* Alternative version #2 */ /* * Curt McDowell * Broadcom Corp. * csm@broadcom.com * * IP checksum two bytes at a time with support for * unaligned buffer. * Works for len up to and including 0x20000. * by Curt McDowell, Broadcom Corp. 12/08/2005 * * @param dataptr points to start of data to be summed at any boundary * @param len length of data to be summed * @return host order (!) lwip checksum (non-inverted Internet sum) */ u16_t lwip_standard_chksum(void *dataptr, int len) { u8_t *pb = (u8_t *)dataptr; u16_t *ps, t = 0; u32_t sum = 0; int odd = ((mem_ptr_t)pb & 1); /* Get aligned to u16_t */ if (odd && len > 0) { ((u8_t *)&t)[1] = *pb++; len--; } /* Add the bulk of the data */ ps = (u16_t *)(void *)pb; while (len > 1) { sum += *ps++; len -= 2; } /* Consume left-over byte, if any */ if (len > 0) { ((u8_t *)&t)[0] = *(u8_t *)ps; } /* Add end bytes */ sum += t; /* Fold 32-bit sum to 16 bits calling this twice is propably faster than if statements... */ sum = FOLD_U32T(sum); sum = FOLD_U32T(sum); /* Swap if alignment was odd */ if (odd) { sum = SWAP_BYTES_IN_WORD(sum); } return (u16_t)sum; } #endif #if (LWIP_CHKSUM_ALGORITHM == 3) /* Alternative version #3 */ /** * An optimized checksum routine. Basically, it uses loop-unrolling on * the checksum loop, treating the head and tail bytes specially, whereas * the inner loop acts on 8 bytes at a time. * * @arg start of buffer to be checksummed. May be an odd byte address. * @len number of bytes in the buffer to be checksummed. * @return host order (!) lwip checksum (non-inverted Internet sum) * * by Curt McDowell, Broadcom Corp. December 8th, 2005 */ u16_t lwip_standard_chksum(void *dataptr, int len) { u8_t *pb = (u8_t *)dataptr; u16_t *ps, t = 0; u32_t *pl; u32_t sum = 0, tmp; /* starts at odd byte address? */ int odd = ((mem_ptr_t)pb & 1); if (odd && len > 0) { ((u8_t *)&t)[1] = *pb++; len--; } ps = (u16_t *)pb; if (((mem_ptr_t)ps & 3) && len > 1) { sum += *ps++; len -= 2; } pl = (u32_t *)ps; while (len > 7) { tmp = sum + *pl++; /* ping */ if (tmp < sum) { tmp++; /* add back carry */ } sum = tmp + *pl++; /* pong */ if (sum < tmp) { sum++; /* add back carry */ } len -= 8; } /* make room in upper bits */ sum = FOLD_U32T(sum); ps = (u16_t *)pl; /* 16-bit aligned word remaining? */ while (len > 1) { sum += *ps++; len -= 2; } /* dangling tail byte remaining? */ if (len > 0) { /* include odd byte */ ((u8_t *)&t)[0] = *(u8_t *)ps; } sum += t; /* add end bytes */ /* Fold 32-bit sum to 16 bits calling this twice is propably faster than if statements... */ sum = FOLD_U32T(sum); sum = FOLD_U32T(sum); if (odd) { sum = SWAP_BYTES_IN_WORD(sum); } return (u16_t)sum; } #endif /** Parts of the pseudo checksum which are common to IPv4 and IPv6 */ static u16_t inet_cksum_pseudo_base(struct pbuf *p, u8_t proto, u16_t proto_len, u32_t acc) { struct pbuf *q; u8_t swapped = 0; /* iterate through all pbuf in chain */ for(q = p; q != NULL; q = q->next) { LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): checksumming pbuf %p (has next %p) \n", (void *)q, (void *)q->next)); acc += LWIP_CHKSUM(q->payload, q->len); /*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): unwrapped lwip_chksum()=%"X32_F" \n", acc));*/ /* just executing this next line is probably faster that the if statement needed to check whether we really need to execute it, and does no harm */ acc = FOLD_U32T(acc); if (q->len % 2 != 0) { swapped = 1 - swapped; acc = SWAP_BYTES_IN_WORD(acc); } /*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): wrapped lwip_chksum()=%"X32_F" \n", acc));*/ } if (swapped) { acc = SWAP_BYTES_IN_WORD(acc); } acc += (u32_t)htons((u16_t)proto); acc += (u32_t)htons(proto_len); /* Fold 32-bit sum to 16 bits calling this twice is propably faster than if statements... */ acc = FOLD_U32T(acc); acc = FOLD_U32T(acc); LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): pbuf chain lwip_chksum()=%"X32_F"\n", acc)); return (u16_t)~(acc & 0xffffUL); } /* inet_chksum_pseudo: * * Calculates the pseudo Internet checksum used by TCP and UDP for a pbuf chain. * IP addresses are expected to be in network byte order. * * @param p chain of pbufs over that a checksum should be calculated (ip data part) * @param src source ip address (used for checksum of pseudo header) * @param dst destination ip address (used for checksum of pseudo header) * @param proto ip protocol (used for checksum of pseudo header) * @param proto_len length of the ip data part (used for checksum of pseudo header) * @return checksum (as u16_t) to be saved directly in the protocol header */ u16_t inet_chksum_pseudo(struct pbuf *p, u8_t proto, u16_t proto_len, ip_addr_t *src, ip_addr_t *dest) { u32_t acc; u32_t addr; addr = ip4_addr_get_u32(src); acc = (addr & 0xffffUL); acc += ((addr >> 16) & 0xffffUL); addr = ip4_addr_get_u32(dest); acc += (addr & 0xffffUL); acc += ((addr >> 16) & 0xffffUL); /* fold down to 16 bits */ acc = FOLD_U32T(acc); acc = FOLD_U32T(acc); return inet_cksum_pseudo_base(p, proto, proto_len, acc); } #if LWIP_IPV6 /** * Calculates the checksum with IPv6 pseudo header used by TCP and UDP for a pbuf chain. * IPv6 addresses are expected to be in network byte order. * * @param p chain of pbufs over that a checksum should be calculated (ip data part) * @param src source ipv6 address (used for checksum of pseudo header) * @param dst destination ipv6 address (used for checksum of pseudo header) * @param proto ipv6 protocol/next header (used for checksum of pseudo header) * @param proto_len length of the ipv6 payload (used for checksum of pseudo header) * @return checksum (as u16_t) to be saved directly in the protocol header */ u16_t ip6_chksum_pseudo(struct pbuf *p, u8_t proto, u16_t proto_len, ip6_addr_t *src, ip6_addr_t *dest) { u32_t acc = 0; u32_t addr; u8_t addr_part; for (addr_part = 0; addr_part < 4; addr_part++) { addr = src->addr[addr_part]; acc += (addr & 0xffffUL); acc += ((addr >> 16) & 0xffffUL); addr = dest->addr[addr_part]; acc += (addr & 0xffffUL); acc += ((addr >> 16) & 0xffffUL); } /* fold down to 16 bits */ acc = FOLD_U32T(acc); acc = FOLD_U32T(acc); return inet_cksum_pseudo_base(p, proto, proto_len, acc); } #endif /* LWIP_IPV6 */ /** Parts of the pseudo checksum which are common to IPv4 and IPv6 */ static u16_t inet_cksum_pseudo_partial_base(struct pbuf *p, u8_t proto, u16_t proto_len, u16_t chksum_len, u32_t acc) { struct pbuf *q; u8_t swapped = 0; u16_t chklen; /* iterate through all pbuf in chain */ for(q = p; (q != NULL) && (chksum_len > 0); q = q->next) { LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): checksumming pbuf %p (has next %p) \n", (void *)q, (void *)q->next)); chklen = q->len; if (chklen > chksum_len) { chklen = chksum_len; } acc += LWIP_CHKSUM(q->payload, chklen); chksum_len -= chklen; LWIP_ASSERT("delete me", chksum_len < 0x7fff); /*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): unwrapped lwip_chksum()=%"X32_F" \n", acc));*/ /* fold the upper bit down */ acc = FOLD_U32T(acc); if (q->len % 2 != 0) { swapped = 1 - swapped; acc = SWAP_BYTES_IN_WORD(acc); } /*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): wrapped lwip_chksum()=%"X32_F" \n", acc));*/ } if (swapped) { acc = SWAP_BYTES_IN_WORD(acc); } acc += (u32_t)htons((u16_t)proto); acc += (u32_t)htons(proto_len); /* Fold 32-bit sum to 16 bits calling this twice is propably faster than if statements... */ acc = FOLD_U32T(acc); acc = FOLD_U32T(acc); LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): pbuf chain lwip_chksum()=%"X32_F"\n", acc)); return (u16_t)~(acc & 0xffffUL); } /* inet_chksum_pseudo_partial: * * Calculates the pseudo Internet checksum used by TCP and UDP for a pbuf chain. * IP addresses are expected to be in network byte order. * * @param p chain of pbufs over that a checksum should be calculated (ip data part) * @param src source ip address (used for checksum of pseudo header) * @param dst destination ip address (used for checksum of pseudo header) * @param proto ip protocol (used for checksum of pseudo header) * @param proto_len length of the ip data part (used for checksum of pseudo header) * @return checksum (as u16_t) to be saved directly in the protocol header */ u16_t inet_chksum_pseudo_partial(struct pbuf *p, u8_t proto, u16_t proto_len, u16_t chksum_len, ip_addr_t *src, ip_addr_t *dest) { u32_t acc; u32_t addr; addr = ip4_addr_get_u32(src); acc = (addr & 0xffffUL); acc += ((addr >> 16) & 0xffffUL); addr = ip4_addr_get_u32(dest); acc += (addr & 0xffffUL); acc += ((addr >> 16) & 0xffffUL); /* fold down to 16 bits */ acc = FOLD_U32T(acc); acc = FOLD_U32T(acc); return inet_cksum_pseudo_partial_base(p, proto, proto_len, chksum_len, acc); } #if LWIP_IPV6 /** * Calculates the checksum with IPv6 pseudo header used by TCP and UDP for a pbuf chain. * IPv6 addresses are expected to be in network byte order. Will only compute for a * portion of the payload. * * @param p chain of pbufs over that a checksum should be calculated (ip data part) * @param src source ipv6 address (used for checksum of pseudo header) * @param dst destination ipv6 address (used for checksum of pseudo header) * @param proto ipv6 protocol/next header (used for checksum of pseudo header) * @param proto_len length of the ipv6 payload (used for checksum of pseudo header) * @param chksum_len number of payload bytes used to compute chksum * @return checksum (as u16_t) to be saved directly in the protocol header */ u16_t ip6_chksum_pseudo_partial(struct pbuf *p, u8_t proto, u16_t proto_len, u16_t chksum_len, ip6_addr_t *src, ip6_addr_t *dest) { u32_t acc = 0; u32_t addr; u8_t addr_part; for (addr_part = 0; addr_part < 4; addr_part++) { addr = src->addr[addr_part]; acc += (addr & 0xffffUL); acc += ((addr >> 16) & 0xffffUL); addr = dest->addr[addr_part]; acc += (addr & 0xffffUL); acc += ((addr >> 16) & 0xffffUL); } /* fold down to 16 bits */ acc = FOLD_U32T(acc); acc = FOLD_U32T(acc); return inet_cksum_pseudo_partial_base(p, proto, proto_len, chksum_len, acc); } #endif /* LWIP_IPV6 */ /* inet_chksum: * * Calculates the Internet checksum over a portion of memory. Used primarily for IP * and ICMP. * * @param dataptr start of the buffer to calculate the checksum (no alignment needed) * @param len length of the buffer to calculate the checksum * @return checksum (as u16_t) to be saved directly in the protocol header */ u16_t inet_chksum(void *dataptr, u16_t len) { return ~LWIP_CHKSUM(dataptr, len); } /** * Calculate a checksum over a chain of pbufs (without pseudo-header, much like * inet_chksum only pbufs are used). * * @param p pbuf chain over that the checksum should be calculated * @return checksum (as u16_t) to be saved directly in the protocol header */ u16_t inet_chksum_pbuf(struct pbuf *p) { u32_t acc; struct pbuf *q; u8_t swapped; acc = 0; swapped = 0; for(q = p; q != NULL; q = q->next) { acc += LWIP_CHKSUM(q->payload, q->len); acc = FOLD_U32T(acc); if (q->len % 2 != 0) { swapped = 1 - swapped; acc = SWAP_BYTES_IN_WORD(acc); } } if (swapped) { acc = SWAP_BYTES_IN_WORD(acc); } return (u16_t)~(acc & 0xffffUL); } /* These are some implementations for LWIP_CHKSUM_COPY, which copies data * like MEMCPY but generates a checksum at the same time. Since this is a * performance-sensitive function, you might want to create your own version * in assembly targeted at your hardware by defining it in lwipopts.h: * #define LWIP_CHKSUM_COPY(dst, src, len) your_chksum_copy(dst, src, len) */ #if (LWIP_CHKSUM_COPY_ALGORITHM == 1) /* Version #1 */ /** Safe but slow: first call MEMCPY, then call LWIP_CHKSUM. * For architectures with big caches, data might still be in cache when * generating the checksum after copying. */ u16_t lwip_chksum_copy(void *dst, const void *src, u16_t len) { MEMCPY(dst, src, len); return LWIP_CHKSUM(dst, len); } #endif /* (LWIP_CHKSUM_COPY_ALGORITHM == 1) */ ocproxy-1.60/lwip/src/core/init.c000066400000000000000000000354321303453231400167510ustar00rootroot00000000000000/** * @file * Modules initialization * */ /* * Copyright (c) 2001-2004 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #include "lwip/opt.h" #include "lwip/init.h" #include "lwip/stats.h" #include "lwip/sys.h" #include "lwip/mem.h" #include "lwip/memp.h" #include "lwip/pbuf.h" #include "lwip/netif.h" #include "lwip/sockets.h" #include "lwip/ip.h" #include "lwip/raw.h" #include "lwip/udp.h" #include "lwip/tcp_impl.h" #include "lwip/snmp_msg.h" #include "lwip/autoip.h" #include "lwip/igmp.h" #include "lwip/dns.h" #include "lwip/timers.h" #include "netif/etharp.h" #include "lwip/ip6.h" #include "lwip/nd6.h" #include "lwip/mld6.h" #include "lwip/api.h" #include "netif/ppp/ppp.h" /* Compile-time sanity checks for configuration errors. * These can be done independently of LWIP_DEBUG, without penalty. */ #ifndef BYTE_ORDER #error "BYTE_ORDER is not defined, you have to define it in your cc.h" #endif #if (!IP_SOF_BROADCAST && IP_SOF_BROADCAST_RECV) #error "If you want to use broadcast filter per pcb on recv operations, you have to define IP_SOF_BROADCAST=1 in your lwipopts.h" #endif #if (!LWIP_UDP && LWIP_UDPLITE) #error "If you want to use UDP Lite, you have to define LWIP_UDP=1 in your lwipopts.h" #endif #if (!LWIP_UDP && LWIP_DHCP) #error "If you want to use DHCP, you have to define LWIP_UDP=1 in your lwipopts.h" #endif #if (!LWIP_UDP && LWIP_IGMP) #error "If you want to use IGMP, you have to define LWIP_UDP=1 in your lwipopts.h" #endif #if (!LWIP_UDP && LWIP_SNMP) #error "If you want to use SNMP, you have to define LWIP_UDP=1 in your lwipopts.h" #endif #if (!LWIP_UDP && LWIP_DNS) #error "If you want to use DNS, you have to define LWIP_UDP=1 in your lwipopts.h" #endif #if !MEMP_MEM_MALLOC /* MEMP_NUM_* checks are disabled when not using the pool allocator */ #if (LWIP_ARP && ARP_QUEUEING && (MEMP_NUM_ARP_QUEUE<=0)) #error "If you want to use ARP Queueing, you have to define MEMP_NUM_ARP_QUEUE>=1 in your lwipopts.h" #endif #if (LWIP_RAW && (MEMP_NUM_RAW_PCB<=0)) #error "If you want to use RAW, you have to define MEMP_NUM_RAW_PCB>=1 in your lwipopts.h" #endif #if (LWIP_UDP && (MEMP_NUM_UDP_PCB<=0)) #error "If you want to use UDP, you have to define MEMP_NUM_UDP_PCB>=1 in your lwipopts.h" #endif #if (LWIP_TCP && (MEMP_NUM_TCP_PCB<=0)) #error "If you want to use TCP, you have to define MEMP_NUM_TCP_PCB>=1 in your lwipopts.h" #endif #if (LWIP_IGMP && (MEMP_NUM_IGMP_GROUP<=1)) #error "If you want to use IGMP, you have to define MEMP_NUM_IGMP_GROUP>1 in your lwipopts.h" #endif #if ((LWIP_NETCONN || LWIP_SOCKET) && (MEMP_NUM_TCPIP_MSG_API<=0)) #error "If you want to use Sequential API, you have to define MEMP_NUM_TCPIP_MSG_API>=1 in your lwipopts.h" #endif /* There must be sufficient timeouts, taking into account requirements of the subsystems. */ #if LWIP_TIMERS && (MEMP_NUM_SYS_TIMEOUT < (LWIP_TCP + IP_REASSEMBLY + LWIP_ARP + (2*LWIP_DHCP) + LWIP_AUTOIP + LWIP_IGMP + LWIP_DNS + PPP_SUPPORT + (LWIP_IPV6 ? (1 + LWIP_IPV6_REASS + LWIP_IPV6_MLD) : 0))) #error "MEMP_NUM_SYS_TIMEOUT is too low to accomodate all required timeouts" #endif #if (IP_REASSEMBLY && (MEMP_NUM_REASSDATA > IP_REASS_MAX_PBUFS)) #error "MEMP_NUM_REASSDATA > IP_REASS_MAX_PBUFS doesn't make sense since each struct ip_reassdata must hold 2 pbufs at least!" #endif #endif /* !MEMP_MEM_MALLOC */ #if LWIP_WND_SCALE #if (LWIP_TCP && (TCP_WND > 0xffffffff)) #error "If you want to use TCP, TCP_WND must fit in an u32_t, so, you have to reduce it in your lwipopts.h" #endif #if (LWIP_TCP && LWIP_WND_SCALE > 14) #error "The maximum valid window scale value is 14!" #endif #if (LWIP_TCP && (TCP_WND > (0xFFFFU << TCP_RCV_SCALE))) #error "TCP_WND is bigger than the configured LWIP_WND_SCALE allows!" #endif #if (LWIP_TCP && ((TCP_WND >> TCP_RCV_SCALE) == 0)) #error "TCP_WND is too small for the configured LWIP_WND_SCALE (results in zero window)!" #endif #else /* LWIP_WND_SCALE */ #if (LWIP_TCP && (TCP_WND > 0xffff)) #error "If you want to use TCP, TCP_WND must fit in an u16_t, so, you have to reduce it in your lwipopts.h (or enable window scaling)" #endif #endif /* LWIP_WND_SCALE */ #if (LWIP_TCP && (TCP_SND_QUEUELEN > 0xffff)) #error "If you want to use TCP, TCP_SND_QUEUELEN must fit in an u16_t, so, you have to reduce it in your lwipopts.h" #endif #if (LWIP_TCP && (TCP_SND_QUEUELEN < 2)) #error "TCP_SND_QUEUELEN must be at least 2 for no-copy TCP writes to work" #endif #if (LWIP_TCP && ((TCP_MAXRTX > 12) || (TCP_SYNMAXRTX > 12))) #error "If you want to use TCP, TCP_MAXRTX and TCP_SYNMAXRTX must less or equal to 12 (due to tcp_backoff table), so, you have to reduce them in your lwipopts.h" #endif #if (LWIP_TCP && TCP_LISTEN_BACKLOG && ((TCP_DEFAULT_LISTEN_BACKLOG < 0) || (TCP_DEFAULT_LISTEN_BACKLOG > 0xff))) #error "If you want to use TCP backlog, TCP_DEFAULT_LISTEN_BACKLOG must fit into an u8_t" #endif #if (LWIP_NETIF_API && (NO_SYS==1)) #error "If you want to use NETIF API, you have to define NO_SYS=0 in your lwipopts.h" #endif #if ((LWIP_SOCKET || LWIP_NETCONN) && (NO_SYS==1)) #error "If you want to use Sequential API, you have to define NO_SYS=0 in your lwipopts.h" #endif #if (!LWIP_NETCONN && LWIP_SOCKET) #error "If you want to use Socket API, you have to define LWIP_NETCONN=1 in your lwipopts.h" #endif #if (((!LWIP_DHCP) || (!LWIP_AUTOIP)) && LWIP_DHCP_AUTOIP_COOP) #error "If you want to use DHCP/AUTOIP cooperation mode, you have to define LWIP_DHCP=1 and LWIP_AUTOIP=1 in your lwipopts.h" #endif #if (((!LWIP_DHCP) || (!LWIP_ARP)) && DHCP_DOES_ARP_CHECK) #error "If you want to use DHCP ARP checking, you have to define LWIP_DHCP=1 and LWIP_ARP=1 in your lwipopts.h" #endif #if (!LWIP_ARP && LWIP_AUTOIP) #error "If you want to use AUTOIP, you have to define LWIP_ARP=1 in your lwipopts.h" #endif #if (LWIP_SNMP && (SNMP_CONCURRENT_REQUESTS<=0)) #error "If you want to use SNMP, you have to define SNMP_CONCURRENT_REQUESTS>=1 in your lwipopts.h" #endif #if (LWIP_SNMP && (SNMP_TRAP_DESTINATIONS<=0)) #error "If you want to use SNMP, you have to define SNMP_TRAP_DESTINATIONS>=1 in your lwipopts.h" #endif #if (LWIP_TCP && ((LWIP_EVENT_API && LWIP_CALLBACK_API) || (!LWIP_EVENT_API && !LWIP_CALLBACK_API))) #error "One and exactly one of LWIP_EVENT_API and LWIP_CALLBACK_API has to be enabled in your lwipopts.h" #endif #if (MEM_LIBC_MALLOC && MEM_USE_POOLS) #error "MEM_LIBC_MALLOC and MEM_USE_POOLS may not both be simultaneously enabled in your lwipopts.h" #endif #if (MEM_USE_POOLS && !MEMP_USE_CUSTOM_POOLS) #error "MEM_USE_POOLS requires custom pools (MEMP_USE_CUSTOM_POOLS) to be enabled in your lwipopts.h" #endif #if (PBUF_POOL_BUFSIZE <= MEM_ALIGNMENT) #error "PBUF_POOL_BUFSIZE must be greater than MEM_ALIGNMENT or the offset may take the full first pbuf" #endif #if (DNS_LOCAL_HOSTLIST && !DNS_LOCAL_HOSTLIST_IS_DYNAMIC && !(defined(DNS_LOCAL_HOSTLIST_INIT))) #error "you have to define define DNS_LOCAL_HOSTLIST_INIT {{'host1', 0x123}, {'host2', 0x234}} to initialize DNS_LOCAL_HOSTLIST" #endif #if PPP_SUPPORT && !PPPOS_SUPPORT && !PPPOE_SUPPORT #error "PPP_SUPPORT needs either PPPOS_SUPPORT or PPPOE_SUPPORT turned on" #endif #if !LWIP_ETHERNET && (LWIP_ARP || PPPOE_SUPPORT) #error "LWIP_ETHERNET needs to be turned on for LWIP_ARP or PPPOE_SUPPORT" #endif #if (LWIP_IGMP || LWIP_IPV6) && !defined(LWIP_RAND) #error "When using IGMP or IPv6, LWIP_RAND() needs to be defined to a random-function returning an u32_t random value" #endif #if LWIP_TCPIP_CORE_LOCKING_INPUT && !LWIP_TCPIP_CORE_LOCKING #error "When using LWIP_TCPIP_CORE_LOCKING_INPUT, LWIP_TCPIP_CORE_LOCKING must be enabled, too" #endif #if LWIP_TCP && LWIP_NETIF_TX_SINGLE_PBUF && !TCP_OVERSIZE #error "LWIP_NETIF_TX_SINGLE_PBUF needs TCP_OVERSIZE enabled to create single-pbuf TCP packets" #endif #if IP_FRAG && IP_FRAG_USES_STATIC_BUF && LWIP_NETIF_TX_SINGLE_PBUF #error "LWIP_NETIF_TX_SINGLE_PBUF does not work with IP_FRAG_USES_STATIC_BUF==1 as that creates pbuf queues" #endif #if LWIP_NETCONN && LWIP_TCP #if NETCONN_COPY != TCP_WRITE_FLAG_COPY #error "NETCONN_COPY != TCP_WRITE_FLAG_COPY" #endif #if NETCONN_MORE != TCP_WRITE_FLAG_MORE #error "NETCONN_MORE != TCP_WRITE_FLAG_MORE" #endif #endif /* LWIP_NETCONN && LWIP_TCP */ #if LWIP_SOCKET /* Check that the SO_* socket options and SOF_* lwIP-internal flags match */ #if SO_ACCEPTCONN != SOF_ACCEPTCONN #error "SO_ACCEPTCONN != SOF_ACCEPTCONN" #endif #if SO_REUSEADDR != SOF_REUSEADDR #error "WARNING: SO_REUSEADDR != SOF_REUSEADDR" #endif #if SO_KEEPALIVE != SOF_KEEPALIVE #error "WARNING: SO_KEEPALIVE != SOF_KEEPALIVE" #endif #if SO_BROADCAST != SOF_BROADCAST #error "WARNING: SO_BROADCAST != SOF_BROADCAST" #endif #if SO_LINGER != SOF_LINGER #error "WARNING: SO_LINGER != SOF_LINGER" #endif #endif /* LWIP_SOCKET */ /* Compile-time checks for deprecated options. */ #ifdef MEMP_NUM_TCPIP_MSG #error "MEMP_NUM_TCPIP_MSG option is deprecated. Remove it from your lwipopts.h." #endif #ifdef TCP_REXMIT_DEBUG #error "TCP_REXMIT_DEBUG option is deprecated. Remove it from your lwipopts.h." #endif #ifdef RAW_STATS #error "RAW_STATS option is deprecated. Remove it from your lwipopts.h." #endif #ifdef ETHARP_QUEUE_FIRST #error "ETHARP_QUEUE_FIRST option is deprecated. Remove it from your lwipopts.h." #endif #ifdef ETHARP_ALWAYS_INSERT #error "ETHARP_ALWAYS_INSERT option is deprecated. Remove it from your lwipopts.h." #endif #ifndef LWIP_DISABLE_TCP_SANITY_CHECKS #define LWIP_DISABLE_TCP_SANITY_CHECKS 0 #endif #ifndef LWIP_DISABLE_MEMP_SANITY_CHECKS #define LWIP_DISABLE_MEMP_SANITY_CHECKS 0 #endif /* MEMP sanity checks */ #if !LWIP_DISABLE_MEMP_SANITY_CHECKS #if LWIP_NETCONN #if MEMP_MEM_MALLOC #if !MEMP_NUM_NETCONN && LWIP_SOCKET #error "lwip_sanity_check: WARNING: MEMP_NUM_NETCONN cannot be 0 when using sockets!" #endif #else /* MEMP_MEM_MALLOC */ #if MEMP_NUM_NETCONN > (MEMP_NUM_TCP_PCB+MEMP_NUM_TCP_PCB_LISTEN+MEMP_NUM_UDP_PCB+MEMP_NUM_RAW_PCB) #error "lwip_sanity_check: WARNING: MEMP_NUM_NETCONN should be less than the sum of MEMP_NUM_{TCP,RAW,UDP}_PCB+MEMP_NUM_TCP_PCB_LISTEN. If you know what you are doing, define LWIP_DISABLE_MEMP_SANITY_CHECKS to 1 to disable this error." #endif #endif /* MEMP_MEM_MALLOC */ #endif /* LWIP_NETCONN */ #endif /* !LWIP_DISABLE_MEMP_SANITY_CHECKS */ /* TCP sanity checks */ #if !LWIP_DISABLE_TCP_SANITY_CHECKS #if LWIP_TCP #if !MEMP_MEM_MALLOC && (MEMP_NUM_TCP_SEG < TCP_SND_QUEUELEN) #error "lwip_sanity_check: WARNING: MEMP_NUM_TCP_SEG should be at least as big as TCP_SND_QUEUELEN. If you know what you are doing, define LWIP_DISABLE_TCP_SANITY_CHECKS to 1 to disable this error." #endif #if TCP_SND_BUF < (2 * TCP_MSS) #error "lwip_sanity_check: WARNING: TCP_SND_BUF must be at least as much as (2 * TCP_MSS) for things to work smoothly. If you know what you are doing, define LWIP_DISABLE_TCP_SANITY_CHECKS to 1 to disable this error." #endif #if TCP_SND_QUEUELEN < (2 * (TCP_SND_BUF / TCP_MSS)) #error "lwip_sanity_check: WARNING: TCP_SND_QUEUELEN must be at least as much as (2 * TCP_SND_BUF/TCP_MSS) for things to work. If you know what you are doing, define LWIP_DISABLE_TCP_SANITY_CHECKS to 1 to disable this error." #endif #if TCP_SNDLOWAT >= TCP_SND_BUF #error "lwip_sanity_check: WARNING: TCP_SNDLOWAT must be less than TCP_SND_BUF. If you know what you are doing, define LWIP_DISABLE_TCP_SANITY_CHECKS to 1 to disable this error." #endif #if TCP_SNDQUEUELOWAT >= TCP_SND_QUEUELEN #error "lwip_sanity_check: WARNING: TCP_SNDQUEUELOWAT must be less than TCP_SND_QUEUELEN. If you know what you are doing, define LWIP_DISABLE_TCP_SANITY_CHECKS to 1 to disable this error." #endif #if !MEMP_MEM_MALLOC && (PBUF_POOL_BUFSIZE <= (PBUF_LINK_HLEN + PBUF_IP_HLEN + PBUF_TRANSPORT_HLEN)) #error "lwip_sanity_check: WARNING: PBUF_POOL_BUFSIZE does not provide enough space for protocol headers. If you know what you are doing, define LWIP_DISABLE_TCP_SANITY_CHECKS to 1 to disable this error." #endif #if !MEMP_MEM_MALLOC && (TCP_WND > (PBUF_POOL_SIZE * (PBUF_POOL_BUFSIZE - (PBUF_LINK_HLEN + PBUF_IP_HLEN + PBUF_TRANSPORT_HLEN)))) #error "lwip_sanity_check: WARNING: TCP_WND is larger than space provided by PBUF_POOL_SIZE * (PBUF_POOL_BUFSIZE - protocol headers). If you know what you are doing, define LWIP_DISABLE_TCP_SANITY_CHECKS to 1 to disable this error." #endif #if TCP_WND < TCP_MSS #error "lwip_sanity_check: WARNING: TCP_WND is smaller than MSS. If you know what you are doing, define LWIP_DISABLE_TCP_SANITY_CHECKS to 1 to disable this error." #endif #endif /* LWIP_TCP */ #endif /* !LWIP_DISABLE_TCP_SANITY_CHECKS */ /** * Perform Sanity check of user-configurable values, and initialize all modules. */ void lwip_init(void) { /* Modules initialization */ stats_init(); #if !NO_SYS sys_init(); #endif /* !NO_SYS */ mem_init(); memp_init(); pbuf_init(); netif_init(); #if LWIP_SOCKET lwip_socket_init(); #endif /* LWIP_SOCKET */ ip_init(); #if LWIP_ARP etharp_init(); #endif /* LWIP_ARP */ #if LWIP_RAW raw_init(); #endif /* LWIP_RAW */ #if LWIP_UDP udp_init(); #endif /* LWIP_UDP */ #if LWIP_TCP tcp_init(); #endif /* LWIP_TCP */ #if LWIP_SNMP snmp_init(); #endif /* LWIP_SNMP */ #if LWIP_AUTOIP autoip_init(); #endif /* LWIP_AUTOIP */ #if LWIP_IGMP igmp_init(); #endif /* LWIP_IGMP */ #if LWIP_DNS dns_init(); #endif /* LWIP_DNS */ #if LWIP_IPV6 ip6_init(); nd6_init(); #if LWIP_IPV6_MLD mld6_init(); #endif /* LWIP_IPV6_MLD */ #endif /* LWIP_IPV6 */ #if PPP_SUPPORT ppp_init(); #endif #if LWIP_TIMERS sys_timeouts_init(); #endif /* LWIP_TIMERS */ } ocproxy-1.60/lwip/src/core/ipv4/000077500000000000000000000000001303453231400165155ustar00rootroot00000000000000ocproxy-1.60/lwip/src/core/ipv4/autoip.c000066400000000000000000000433731303453231400201740ustar00rootroot00000000000000/** * @file * AutoIP Automatic LinkLocal IP Configuration * */ /* * * Copyright (c) 2007 Dominik Spies * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * Author: Dominik Spies * * This is a AutoIP implementation for the lwIP TCP/IP stack. It aims to conform * with RFC 3927. * * * Please coordinate changes and requests with Dominik Spies * */ /******************************************************************************* * USAGE: * * define LWIP_AUTOIP 1 in your lwipopts.h * * If you don't use tcpip.c (so, don't call, you don't call tcpip_init): * - First, call autoip_init(). * - call autoip_tmr() all AUTOIP_TMR_INTERVAL msces, * that should be defined in autoip.h. * I recommend a value of 100. The value must divide 1000 with a remainder almost 0. * Possible values are 1000, 500, 333, 250, 200, 166, 142, 125, 111, 100 .... * * Without DHCP: * - Call autoip_start() after netif_add(). * * With DHCP: * - define LWIP_DHCP_AUTOIP_COOP 1 in your lwipopts.h. * - Configure your DHCP Client. * */ #include "lwip/opt.h" #if LWIP_AUTOIP /* don't build if not configured for use in lwipopts.h */ #include "lwip/mem.h" #include "lwip/udp.h" #include "lwip/ip_addr.h" #include "lwip/netif.h" #include "lwip/autoip.h" #include "netif/etharp.h" #include #include /* 169.254.0.0 */ #define AUTOIP_NET 0xA9FE0000 /* 169.254.1.0 */ #define AUTOIP_RANGE_START (AUTOIP_NET | 0x0100) /* 169.254.254.255 */ #define AUTOIP_RANGE_END (AUTOIP_NET | 0xFEFF) /** Pseudo random macro based on netif informations. * You could use "rand()" from the C Library if you define LWIP_AUTOIP_RAND in lwipopts.h */ #ifndef LWIP_AUTOIP_RAND #define LWIP_AUTOIP_RAND(netif) ( (((u32_t)((netif->hwaddr[5]) & 0xff) << 24) | \ ((u32_t)((netif->hwaddr[3]) & 0xff) << 16) | \ ((u32_t)((netif->hwaddr[2]) & 0xff) << 8) | \ ((u32_t)((netif->hwaddr[4]) & 0xff))) + \ (netif->autoip?netif->autoip->tried_llipaddr:0)) #endif /* LWIP_AUTOIP_RAND */ /** * Macro that generates the initial IP address to be tried by AUTOIP. * If you want to override this, define it to something else in lwipopts.h. */ #ifndef LWIP_AUTOIP_CREATE_SEED_ADDR #define LWIP_AUTOIP_CREATE_SEED_ADDR(netif) \ htonl(AUTOIP_RANGE_START + ((u32_t)(((u8_t)(netif->hwaddr[4])) | \ ((u32_t)((u8_t)(netif->hwaddr[5]))) << 8))) #endif /* LWIP_AUTOIP_CREATE_SEED_ADDR */ /* static functions */ static void autoip_handle_arp_conflict(struct netif *netif); /* creates a pseudo random LL IP-Address for a network interface */ static void autoip_create_addr(struct netif *netif, ip_addr_t *ipaddr); /* sends an ARP probe */ static err_t autoip_arp_probe(struct netif *netif); /* sends an ARP announce */ static err_t autoip_arp_announce(struct netif *netif); /* configure interface for use with current LL IP-Address */ static err_t autoip_bind(struct netif *netif); /* start sending probes for llipaddr */ static void autoip_start_probing(struct netif *netif); /** Set a statically allocated struct autoip to work with. * Using this prevents autoip_start to allocate it using mem_malloc. * * @param netif the netif for which to set the struct autoip * @param dhcp (uninitialised) dhcp struct allocated by the application */ void autoip_set_struct(struct netif *netif, struct autoip *autoip) { LWIP_ASSERT("netif != NULL", netif != NULL); LWIP_ASSERT("autoip != NULL", autoip != NULL); LWIP_ASSERT("netif already has a struct autoip set", netif->autoip == NULL); /* clear data structure */ memset(autoip, 0, sizeof(struct autoip)); /* autoip->state = AUTOIP_STATE_OFF; */ netif->autoip = autoip; } /** Restart AutoIP client and check the next address (conflict detected) * * @param netif The netif under AutoIP control */ static void autoip_restart(struct netif *netif) { netif->autoip->tried_llipaddr++; autoip_start(netif); } /** * Handle a IP address conflict after an ARP conflict detection */ static void autoip_handle_arp_conflict(struct netif *netif) { /* Somehow detect if we are defending or retreating */ unsigned char defend = 1; /* tbd */ if (defend) { if (netif->autoip->lastconflict > 0) { /* retreat, there was a conflicting ARP in the last * DEFEND_INTERVAL seconds */ LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("autoip_handle_arp_conflict(): we are defending, but in DEFEND_INTERVAL, retreating\n")); /* TODO: close all TCP sessions */ autoip_restart(netif); } else { LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("autoip_handle_arp_conflict(): we are defend, send ARP Announce\n")); autoip_arp_announce(netif); netif->autoip->lastconflict = DEFEND_INTERVAL * AUTOIP_TICKS_PER_SECOND; } } else { LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("autoip_handle_arp_conflict(): we do not defend, retreating\n")); /* TODO: close all TCP sessions */ autoip_restart(netif); } } /** * Create an IP-Address out of range 169.254.1.0 to 169.254.254.255 * * @param netif network interface on which create the IP-Address * @param ipaddr ip address to initialize */ static void autoip_create_addr(struct netif *netif, ip_addr_t *ipaddr) { /* Here we create an IP-Address out of range 169.254.1.0 to 169.254.254.255 * compliant to RFC 3927 Section 2.1 * We have 254 * 256 possibilities */ u32_t addr = ntohl(LWIP_AUTOIP_CREATE_SEED_ADDR(netif)); addr += netif->autoip->tried_llipaddr; addr = AUTOIP_NET | (addr & 0xffff); /* Now, 169.254.0.0 <= addr <= 169.254.255.255 */ if (addr < AUTOIP_RANGE_START) { addr += AUTOIP_RANGE_END - AUTOIP_RANGE_START + 1; } if (addr > AUTOIP_RANGE_END) { addr -= AUTOIP_RANGE_END - AUTOIP_RANGE_START + 1; } LWIP_ASSERT("AUTOIP address not in range", (addr >= AUTOIP_RANGE_START) && (addr <= AUTOIP_RANGE_END)); ip4_addr_set_u32(ipaddr, htonl(addr)); LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("autoip_create_addr(): tried_llipaddr=%"U16_F", %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", (u16_t)(netif->autoip->tried_llipaddr), ip4_addr1_16(ipaddr), ip4_addr2_16(ipaddr), ip4_addr3_16(ipaddr), ip4_addr4_16(ipaddr))); } /** * Sends an ARP probe from a network interface * * @param netif network interface used to send the probe */ static err_t autoip_arp_probe(struct netif *netif) { return etharp_raw(netif, (struct eth_addr *)netif->hwaddr, ðbroadcast, (struct eth_addr *)netif->hwaddr, IP_ADDR_ANY, ðzero, &netif->autoip->llipaddr, ARP_REQUEST); } /** * Sends an ARP announce from a network interface * * @param netif network interface used to send the announce */ static err_t autoip_arp_announce(struct netif *netif) { return etharp_raw(netif, (struct eth_addr *)netif->hwaddr, ðbroadcast, (struct eth_addr *)netif->hwaddr, &netif->autoip->llipaddr, ðzero, &netif->autoip->llipaddr, ARP_REQUEST); } /** * Configure interface for use with current LL IP-Address * * @param netif network interface to configure with current LL IP-Address */ static err_t autoip_bind(struct netif *netif) { struct autoip *autoip = netif->autoip; ip_addr_t sn_mask, gw_addr; LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, ("autoip_bind(netif=%p) %c%c%"U16_F" %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num, ip4_addr1_16(&autoip->llipaddr), ip4_addr2_16(&autoip->llipaddr), ip4_addr3_16(&autoip->llipaddr), ip4_addr4_16(&autoip->llipaddr))); IP4_ADDR(&sn_mask, 255, 255, 0, 0); IP4_ADDR(&gw_addr, 0, 0, 0, 0); netif_set_ipaddr(netif, &autoip->llipaddr); netif_set_netmask(netif, &sn_mask); netif_set_gw(netif, &gw_addr); /* bring the interface up */ netif_set_up(netif); return ERR_OK; } /** * Start AutoIP client * * @param netif network interface on which start the AutoIP client */ err_t autoip_start(struct netif *netif) { struct autoip *autoip = netif->autoip; err_t result = ERR_OK; if (netif_is_up(netif)) { netif_set_down(netif); } /* Set IP-Address, Netmask and Gateway to 0 to make sure that * ARP Packets are formed correctly */ ip_addr_set_zero(&netif->ip_addr); ip_addr_set_zero(&netif->netmask); ip_addr_set_zero(&netif->gw); LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("autoip_start(netif=%p) %c%c%"U16_F"\n", (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num)); if (autoip == NULL) { /* no AutoIP client attached yet? */ LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, ("autoip_start(): starting new AUTOIP client\n")); autoip = (struct autoip *)mem_malloc(sizeof(struct autoip)); if (autoip == NULL) { LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, ("autoip_start(): could not allocate autoip\n")); return ERR_MEM; } memset(autoip, 0, sizeof(struct autoip)); /* store this AutoIP client in the netif */ netif->autoip = autoip; LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, ("autoip_start(): allocated autoip")); } else { autoip->state = AUTOIP_STATE_OFF; autoip->ttw = 0; autoip->sent_num = 0; ip_addr_set_zero(&autoip->llipaddr); autoip->lastconflict = 0; } autoip_create_addr(netif, &(autoip->llipaddr)); autoip_start_probing(netif); return result; } static void autoip_start_probing(struct netif *netif) { struct autoip *autoip = netif->autoip; autoip->state = AUTOIP_STATE_PROBING; autoip->sent_num = 0; LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("autoip_start_probing(): changing state to PROBING: %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", ip4_addr1_16(&netif->autoip->llipaddr), ip4_addr2_16(&netif->autoip->llipaddr), ip4_addr3_16(&netif->autoip->llipaddr), ip4_addr4_16(&netif->autoip->llipaddr))); /* time to wait to first probe, this is randomly * choosen out of 0 to PROBE_WAIT seconds. * compliant to RFC 3927 Section 2.2.1 */ autoip->ttw = (u16_t)(LWIP_AUTOIP_RAND(netif) % (PROBE_WAIT * AUTOIP_TICKS_PER_SECOND)); /* * if we tried more then MAX_CONFLICTS we must limit our rate for * accquiring and probing address * compliant to RFC 3927 Section 2.2.1 */ if (autoip->tried_llipaddr > MAX_CONFLICTS) { autoip->ttw = RATE_LIMIT_INTERVAL * AUTOIP_TICKS_PER_SECOND; } } /** * Handle a possible change in the network configuration. * * If there is an AutoIP address configured, take the interface down * and begin probing with the same address. */ void autoip_network_changed(struct netif *netif) { if (netif->autoip && netif->autoip->state != AUTOIP_STATE_OFF) { netif_set_down(netif); autoip_start_probing(netif); } } /** * Stop AutoIP client * * @param netif network interface on which stop the AutoIP client */ err_t autoip_stop(struct netif *netif) { netif->autoip->state = AUTOIP_STATE_OFF; netif_set_down(netif); return ERR_OK; } /** * Has to be called in loop every AUTOIP_TMR_INTERVAL milliseconds */ void autoip_tmr() { struct netif *netif = netif_list; /* loop through netif's */ while (netif != NULL) { /* only act on AutoIP configured interfaces */ if (netif->autoip != NULL) { if (netif->autoip->lastconflict > 0) { netif->autoip->lastconflict--; } LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, ("autoip_tmr() AutoIP-State: %"U16_F", ttw=%"U16_F"\n", (u16_t)(netif->autoip->state), netif->autoip->ttw)); switch(netif->autoip->state) { case AUTOIP_STATE_PROBING: if (netif->autoip->ttw > 0) { netif->autoip->ttw--; } else { if (netif->autoip->sent_num >= PROBE_NUM) { netif->autoip->state = AUTOIP_STATE_ANNOUNCING; netif->autoip->sent_num = 0; netif->autoip->ttw = ANNOUNCE_WAIT * AUTOIP_TICKS_PER_SECOND; LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("autoip_tmr(): changing state to ANNOUNCING: %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", ip4_addr1_16(&netif->autoip->llipaddr), ip4_addr2_16(&netif->autoip->llipaddr), ip4_addr3_16(&netif->autoip->llipaddr), ip4_addr4_16(&netif->autoip->llipaddr))); } else { autoip_arp_probe(netif); LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, ("autoip_tmr() PROBING Sent Probe\n")); netif->autoip->sent_num++; /* calculate time to wait to next probe */ netif->autoip->ttw = (u16_t)((LWIP_AUTOIP_RAND(netif) % ((PROBE_MAX - PROBE_MIN) * AUTOIP_TICKS_PER_SECOND) ) + PROBE_MIN * AUTOIP_TICKS_PER_SECOND); } } break; case AUTOIP_STATE_ANNOUNCING: if (netif->autoip->ttw > 0) { netif->autoip->ttw--; } else { if (netif->autoip->sent_num == 0) { /* We are here the first time, so we waited ANNOUNCE_WAIT seconds * Now we can bind to an IP address and use it. * * autoip_bind calls netif_set_up. This triggers a gratuitous ARP * which counts as an announcement. */ autoip_bind(netif); } else { autoip_arp_announce(netif); LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, ("autoip_tmr() ANNOUNCING Sent Announce\n")); } netif->autoip->ttw = ANNOUNCE_INTERVAL * AUTOIP_TICKS_PER_SECOND; netif->autoip->sent_num++; if (netif->autoip->sent_num >= ANNOUNCE_NUM) { netif->autoip->state = AUTOIP_STATE_BOUND; netif->autoip->sent_num = 0; netif->autoip->ttw = 0; LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("autoip_tmr(): changing state to BOUND: %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", ip4_addr1_16(&netif->autoip->llipaddr), ip4_addr2_16(&netif->autoip->llipaddr), ip4_addr3_16(&netif->autoip->llipaddr), ip4_addr4_16(&netif->autoip->llipaddr))); } } break; } } /* proceed to next network interface */ netif = netif->next; } } /** * Handles every incoming ARP Packet, called by etharp_arp_input. * * @param netif network interface to use for autoip processing * @param hdr Incoming ARP packet */ void autoip_arp_reply(struct netif *netif, struct etharp_hdr *hdr) { LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, ("autoip_arp_reply()\n")); if ((netif->autoip != NULL) && (netif->autoip->state != AUTOIP_STATE_OFF)) { /* when ip.src == llipaddr && hw.src != netif->hwaddr * * when probing ip.dst == llipaddr && hw.src != netif->hwaddr * we have a conflict and must solve it */ ip_addr_t sipaddr, dipaddr; struct eth_addr netifaddr; ETHADDR16_COPY(netifaddr.addr, netif->hwaddr); /* Copy struct ip_addr2 to aligned ip_addr, to support compilers without * structure packing (not using structure copy which breaks strict-aliasing rules). */ IPADDR2_COPY(&sipaddr, &hdr->sipaddr); IPADDR2_COPY(&dipaddr, &hdr->dipaddr); if ((netif->autoip->state == AUTOIP_STATE_PROBING) || ((netif->autoip->state == AUTOIP_STATE_ANNOUNCING) && (netif->autoip->sent_num == 0))) { /* RFC 3927 Section 2.2.1: * from beginning to after ANNOUNCE_WAIT * seconds we have a conflict if * ip.src == llipaddr OR * ip.dst == llipaddr && hw.src != own hwaddr */ if ((ip_addr_cmp(&sipaddr, &netif->autoip->llipaddr)) || (ip_addr_cmp(&dipaddr, &netif->autoip->llipaddr) && !eth_addr_cmp(&netifaddr, &hdr->shwaddr))) { LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | LWIP_DBG_LEVEL_WARNING, ("autoip_arp_reply(): Probe Conflict detected\n")); autoip_restart(netif); } } else { /* RFC 3927 Section 2.5: * in any state we have a conflict if * ip.src == llipaddr && hw.src != own hwaddr */ if (ip_addr_cmp(&sipaddr, &netif->autoip->llipaddr) && !eth_addr_cmp(&netifaddr, &hdr->shwaddr)) { LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | LWIP_DBG_LEVEL_WARNING, ("autoip_arp_reply(): Conflicting ARP-Packet detected\n")); autoip_handle_arp_conflict(netif); } } } } #endif /* LWIP_AUTOIP */ ocproxy-1.60/lwip/src/core/ipv4/icmp.c000066400000000000000000000265251303453231400176230ustar00rootroot00000000000000/** * @file * ICMP - Internet Control Message Protocol * */ /* * Copyright (c) 2001-2004 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ /* Some ICMP messages should be passed to the transport protocols. This is not implemented. */ #include "lwip/opt.h" #if LWIP_ICMP /* don't build if not configured for use in lwipopts.h */ #include "lwip/icmp.h" #include "lwip/inet_chksum.h" #include "lwip/ip.h" #include "lwip/def.h" #include "lwip/stats.h" #include "lwip/snmp.h" #include /** Small optimization: set to 0 if incoming PBUF_POOL pbuf always can be * used to modify and send a response packet (and to 1 if this is not the case, * e.g. when link header is stripped of when receiving) */ #ifndef LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN #define LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN 1 #endif /* LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN */ /* The amount of data from the original packet to return in a dest-unreachable */ #define ICMP_DEST_UNREACH_DATASIZE 8 static void icmp_send_response(struct pbuf *p, u8_t type, u8_t code); /** * Processes ICMP input packets, called from ip_input(). * * Currently only processes icmp echo requests and sends * out the echo response. * * @param p the icmp echo request packet, p->payload pointing to the icmp header * @param inp the netif on which this packet was received */ void icmp_input(struct pbuf *p, struct netif *inp) { u8_t type; #ifdef LWIP_DEBUG u8_t code; #endif /* LWIP_DEBUG */ struct icmp_echo_hdr *iecho; struct ip_hdr *iphdr; s16_t hlen; ICMP_STATS_INC(icmp.recv); snmp_inc_icmpinmsgs(); iphdr = (struct ip_hdr *)ip_current_header(); hlen = IPH_HL(iphdr) * 4; if (p->len < sizeof(u16_t)*2) { LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: short ICMP (%"U16_F" bytes) received\n", p->tot_len)); goto lenerr; } type = *((u8_t *)p->payload); #ifdef LWIP_DEBUG code = *(((u8_t *)p->payload)+1); #endif /* LWIP_DEBUG */ switch (type) { case ICMP_ER: /* This is OK, echo reply might have been parsed by a raw PCB (as obviously, an echo request has been sent, too). */ break; case ICMP_ECHO: #if !LWIP_MULTICAST_PING || !LWIP_BROADCAST_PING { int accepted = 1; #if !LWIP_MULTICAST_PING /* multicast destination address? */ if (ip_addr_ismulticast(ip_current_dest_addr())) { accepted = 0; } #endif /* LWIP_MULTICAST_PING */ #if !LWIP_BROADCAST_PING /* broadcast destination address? */ if (ip_addr_isbroadcast(ip_current_dest_addr(), inp)) { accepted = 0; } #endif /* LWIP_BROADCAST_PING */ /* broadcast or multicast destination address not acceptd? */ if (!accepted) { LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: Not echoing to multicast or broadcast pings\n")); ICMP_STATS_INC(icmp.err); pbuf_free(p); return; } } #endif /* !LWIP_MULTICAST_PING || !LWIP_BROADCAST_PING */ LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ping\n")); if (p->tot_len < sizeof(struct icmp_echo_hdr)) { LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: bad ICMP echo received\n")); goto lenerr; } #if CHECKSUM_CHECK_ICMP if (inet_chksum_pbuf(p) != 0) { LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: checksum failed for received ICMP echo\n")); pbuf_free(p); ICMP_STATS_INC(icmp.chkerr); snmp_inc_icmpinerrors(); return; } #endif #if LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN if (pbuf_header(p, (PBUF_IP_HLEN + PBUF_LINK_HLEN))) { /* p is not big enough to contain link headers * allocate a new one and copy p into it */ struct pbuf *r; /* switch p->payload to ip header */ if (pbuf_header(p, hlen)) { LWIP_ASSERT("icmp_input: moving p->payload to ip header failed\n", 0); goto memerr; } /* allocate new packet buffer with space for link headers */ r = pbuf_alloc(PBUF_LINK, p->tot_len, PBUF_RAM); if (r == NULL) { LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: allocating new pbuf failed\n")); goto memerr; } LWIP_ASSERT("check that first pbuf can hold struct the ICMP header", (r->len >= hlen + sizeof(struct icmp_echo_hdr))); /* copy the whole packet including ip header */ if (pbuf_copy(r, p) != ERR_OK) { LWIP_ASSERT("icmp_input: copying to new pbuf failed\n", 0); goto memerr; } iphdr = (struct ip_hdr *)r->payload; /* switch r->payload back to icmp header */ if (pbuf_header(r, -hlen)) { LWIP_ASSERT("icmp_input: restoring original p->payload failed\n", 0); goto memerr; } /* free the original p */ pbuf_free(p); /* we now have an identical copy of p that has room for link headers */ p = r; } else { /* restore p->payload to point to icmp header */ if (pbuf_header(p, -(s16_t)(PBUF_IP_HLEN + PBUF_LINK_HLEN))) { LWIP_ASSERT("icmp_input: restoring original p->payload failed\n", 0); goto memerr; } } #endif /* LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN */ /* At this point, all checks are OK. */ /* We generate an answer by switching the dest and src ip addresses, * setting the icmp type to ECHO_RESPONSE and updating the checksum. */ iecho = (struct icmp_echo_hdr *)p->payload; ip_addr_copy(iphdr->src, *ip_current_dest_addr()); ip_addr_copy(iphdr->dest, *ip_current_src_addr()); ICMPH_TYPE_SET(iecho, ICMP_ER); #if CHECKSUM_GEN_ICMP /* adjust the checksum */ if (iecho->chksum >= PP_HTONS(0xffffU - (ICMP_ECHO << 8))) { iecho->chksum += PP_HTONS(ICMP_ECHO << 8) + 1; } else { iecho->chksum += PP_HTONS(ICMP_ECHO << 8); } #else /* CHECKSUM_GEN_ICMP */ iecho->chksum = 0; #endif /* CHECKSUM_GEN_ICMP */ /* Set the correct TTL and recalculate the header checksum. */ IPH_TTL_SET(iphdr, ICMP_TTL); IPH_CHKSUM_SET(iphdr, 0); #if CHECKSUM_GEN_IP IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN)); #endif /* CHECKSUM_GEN_IP */ ICMP_STATS_INC(icmp.xmit); /* increase number of messages attempted to send */ snmp_inc_icmpoutmsgs(); /* increase number of echo replies attempted to send */ snmp_inc_icmpoutechoreps(); if(pbuf_header(p, hlen)) { LWIP_ASSERT("Can't move over header in packet", 0); } else { err_t ret; /* send an ICMP packet, src addr is the dest addr of the curren packet */ ret = ip_output_if(p, ip_current_dest_addr(), IP_HDRINCL, ICMP_TTL, 0, IP_PROTO_ICMP, inp); if (ret != ERR_OK) { LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ip_output_if returned an error: %c.\n", ret)); } } break; default: LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ICMP type %"S16_F" code %"S16_F" not supported.\n", (s16_t)type, (s16_t)code)); ICMP_STATS_INC(icmp.proterr); ICMP_STATS_INC(icmp.drop); } pbuf_free(p); return; lenerr: pbuf_free(p); ICMP_STATS_INC(icmp.lenerr); snmp_inc_icmpinerrors(); return; #if LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN memerr: pbuf_free(p); ICMP_STATS_INC(icmp.err); snmp_inc_icmpinerrors(); return; #endif /* LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN */ } /** * Send an icmp 'destination unreachable' packet, called from ip_input() if * the transport layer protocol is unknown and from udp_input() if the local * port is not bound. * * @param p the input packet for which the 'unreachable' should be sent, * p->payload pointing to the IP header * @param t type of the 'unreachable' packet */ void icmp_dest_unreach(struct pbuf *p, enum icmp_dur_type t) { icmp_send_response(p, ICMP_DUR, t); } #if IP_FORWARD || IP_REASSEMBLY /** * Send a 'time exceeded' packet, called from ip_forward() if TTL is 0. * * @param p the input packet for which the 'time exceeded' should be sent, * p->payload pointing to the IP header * @param t type of the 'time exceeded' packet */ void icmp_time_exceeded(struct pbuf *p, enum icmp_te_type t) { icmp_send_response(p, ICMP_TE, t); } #endif /* IP_FORWARD || IP_REASSEMBLY */ /** * Send an icmp packet in response to an incoming packet. * * @param p the input packet for which the 'unreachable' should be sent, * p->payload pointing to the IP header * @param type Type of the ICMP header * @param code Code of the ICMP header */ static void icmp_send_response(struct pbuf *p, u8_t type, u8_t code) { struct pbuf *q; struct ip_hdr *iphdr; /* we can use the echo header here */ struct icmp_echo_hdr *icmphdr; ip_addr_t iphdr_src; /* ICMP header + IP header + 8 bytes of data */ q = pbuf_alloc(PBUF_IP, sizeof(struct icmp_echo_hdr) + IP_HLEN + ICMP_DEST_UNREACH_DATASIZE, PBUF_RAM); if (q == NULL) { LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded: failed to allocate pbuf for ICMP packet.\n")); return; } LWIP_ASSERT("check that first pbuf can hold icmp message", (q->len >= (sizeof(struct icmp_echo_hdr) + IP_HLEN + ICMP_DEST_UNREACH_DATASIZE))); iphdr = (struct ip_hdr *)p->payload; LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded from ")); ip_addr_debug_print(ICMP_DEBUG, &(iphdr->src)); LWIP_DEBUGF(ICMP_DEBUG, (" to ")); ip_addr_debug_print(ICMP_DEBUG, &(iphdr->dest)); LWIP_DEBUGF(ICMP_DEBUG, ("\n")); icmphdr = (struct icmp_echo_hdr *)q->payload; icmphdr->type = type; icmphdr->code = code; icmphdr->id = 0; icmphdr->seqno = 0; /* copy fields from original packet */ SMEMCPY((u8_t *)q->payload + sizeof(struct icmp_echo_hdr), (u8_t *)p->payload, IP_HLEN + ICMP_DEST_UNREACH_DATASIZE); /* calculate checksum */ icmphdr->chksum = 0; #if CHECKSUM_GEN_ICMP icmphdr->chksum = inet_chksum(icmphdr, q->len); #endif ICMP_STATS_INC(icmp.xmit); /* increase number of messages attempted to send */ snmp_inc_icmpoutmsgs(); /* increase number of destination unreachable messages attempted to send */ snmp_inc_icmpouttimeexcds(); ip_addr_copy(iphdr_src, iphdr->src); ip_output(q, NULL, &iphdr_src, ICMP_TTL, 0, IP_PROTO_ICMP); pbuf_free(q); } #endif /* LWIP_ICMP */ ocproxy-1.60/lwip/src/core/ipv4/igmp.c000066400000000000000000000655071303453231400176320ustar00rootroot00000000000000/** * @file * IGMP - Internet Group Management Protocol * */ /* * Copyright (c) 2002 CITEL Technologies Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of CITEL Technologies Ltd nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY CITEL TECHNOLOGIES AND CONTRIBUTORS ``AS IS'' * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL CITEL TECHNOLOGIES OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * This file is a contribution to the lwIP TCP/IP stack. * The Swedish Institute of Computer Science and Adam Dunkels * are specifically granted permission to redistribute this * source code. */ /*------------------------------------------------------------- Note 1) Although the rfc requires V1 AND V2 capability we will only support v2 since now V1 is very old (August 1989) V1 can be added if required a debug print and statistic have been implemented to show this up. ------------------------------------------------------------- ------------------------------------------------------------- Note 2) A query for a specific group address (as opposed to ALLHOSTS) has now been implemented as I am unsure if it is required a debug print and statistic have been implemented to show this up. ------------------------------------------------------------- ------------------------------------------------------------- Note 3) The router alert rfc 2113 is implemented in outgoing packets but not checked rigorously incoming ------------------------------------------------------------- Steve Reynolds ------------------------------------------------------------*/ /*----------------------------------------------------------------------------- * RFC 988 - Host extensions for IP multicasting - V0 * RFC 1054 - Host extensions for IP multicasting - * RFC 1112 - Host extensions for IP multicasting - V1 * RFC 2236 - Internet Group Management Protocol, Version 2 - V2 <- this code is based on this RFC (it's the "de facto" standard) * RFC 3376 - Internet Group Management Protocol, Version 3 - V3 * RFC 4604 - Using Internet Group Management Protocol Version 3... - V3+ * RFC 2113 - IP Router Alert Option - *----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------- * Includes *----------------------------------------------------------------------------*/ #include "lwip/opt.h" #if LWIP_IGMP /* don't build if not configured for use in lwipopts.h */ #include "lwip/igmp.h" #include "lwip/debug.h" #include "lwip/def.h" #include "lwip/mem.h" #include "lwip/ip.h" #include "lwip/inet_chksum.h" #include "lwip/netif.h" #include "lwip/icmp.h" #include "lwip/udp.h" #include "lwip/tcp.h" #include "lwip/stats.h" #include "string.h" /* * IGMP constants */ #define IGMP_TTL 1 #define IGMP_MINLEN 8 #define ROUTER_ALERT 0x9404U #define ROUTER_ALERTLEN 4 /* * IGMP message types, including version number. */ #define IGMP_MEMB_QUERY 0x11 /* Membership query */ #define IGMP_V1_MEMB_REPORT 0x12 /* Ver. 1 membership report */ #define IGMP_V2_MEMB_REPORT 0x16 /* Ver. 2 membership report */ #define IGMP_LEAVE_GROUP 0x17 /* Leave-group message */ /* Group membership states */ #define IGMP_GROUP_NON_MEMBER 0 #define IGMP_GROUP_DELAYING_MEMBER 1 #define IGMP_GROUP_IDLE_MEMBER 2 /** * IGMP packet format. */ #ifdef PACK_STRUCT_USE_INCLUDES # include "arch/bpstruct.h" #endif PACK_STRUCT_BEGIN struct igmp_msg { PACK_STRUCT_FIELD(u8_t igmp_msgtype); PACK_STRUCT_FIELD(u8_t igmp_maxresp); PACK_STRUCT_FIELD(u16_t igmp_checksum); PACK_STRUCT_FIELD(ip_addr_p_t igmp_group_address); } PACK_STRUCT_STRUCT; PACK_STRUCT_END #ifdef PACK_STRUCT_USE_INCLUDES # include "arch/epstruct.h" #endif static struct igmp_group *igmp_lookup_group(struct netif *ifp, ip_addr_t *addr); static err_t igmp_remove_group(struct igmp_group *group); static void igmp_timeout( struct igmp_group *group); static void igmp_start_timer(struct igmp_group *group, u8_t max_time); static void igmp_delaying_member(struct igmp_group *group, u8_t maxresp); static err_t igmp_ip_output_if(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, struct netif *netif); static void igmp_send(struct igmp_group *group, u8_t type); static struct igmp_group* igmp_group_list; static ip_addr_t allsystems; static ip_addr_t allrouters; /** * Initialize the IGMP module */ void igmp_init(void) { LWIP_DEBUGF(IGMP_DEBUG, ("igmp_init: initializing\n")); IP4_ADDR(&allsystems, 224, 0, 0, 1); IP4_ADDR(&allrouters, 224, 0, 0, 2); } #ifdef LWIP_DEBUG /** * Dump global IGMP groups list */ void igmp_dump_group_list() { struct igmp_group *group = igmp_group_list; while (group != NULL) { LWIP_DEBUGF(IGMP_DEBUG, ("igmp_dump_group_list: [%"U32_F"] ", (u32_t)(group->group_state))); ip_addr_debug_print(IGMP_DEBUG, &group->group_address); LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", group->netif)); group = group->next; } LWIP_DEBUGF(IGMP_DEBUG, ("\n")); } #else #define igmp_dump_group_list() #endif /* LWIP_DEBUG */ /** * Start IGMP processing on interface * * @param netif network interface on which start IGMP processing */ err_t igmp_start(struct netif *netif) { struct igmp_group* group; LWIP_DEBUGF(IGMP_DEBUG, ("igmp_start: starting IGMP processing on if %p\n", netif)); group = igmp_lookup_group(netif, &allsystems); if (group != NULL) { group->group_state = IGMP_GROUP_IDLE_MEMBER; group->use++; /* Allow the igmp messages at the MAC level */ if (netif->igmp_mac_filter != NULL) { LWIP_DEBUGF(IGMP_DEBUG, ("igmp_start: igmp_mac_filter(ADD ")); ip_addr_debug_print(IGMP_DEBUG, &allsystems); LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", netif)); netif->igmp_mac_filter(netif, &allsystems, IGMP_ADD_MAC_FILTER); } return ERR_OK; } return ERR_MEM; } /** * Stop IGMP processing on interface * * @param netif network interface on which stop IGMP processing */ err_t igmp_stop(struct netif *netif) { struct igmp_group *group = igmp_group_list; struct igmp_group *prev = NULL; struct igmp_group *next; /* look for groups joined on this interface further down the list */ while (group != NULL) { next = group->next; /* is it a group joined on this interface? */ if (group->netif == netif) { /* is it the first group of the list? */ if (group == igmp_group_list) { igmp_group_list = next; } /* is there a "previous" group defined? */ if (prev != NULL) { prev->next = next; } /* disable the group at the MAC level */ if (netif->igmp_mac_filter != NULL) { LWIP_DEBUGF(IGMP_DEBUG, ("igmp_stop: igmp_mac_filter(DEL ")); ip_addr_debug_print(IGMP_DEBUG, &group->group_address); LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", netif)); netif->igmp_mac_filter(netif, &(group->group_address), IGMP_DEL_MAC_FILTER); } /* free group */ memp_free(MEMP_IGMP_GROUP, group); } else { /* change the "previous" */ prev = group; } /* move to "next" */ group = next; } return ERR_OK; } /** * Report IGMP memberships for this interface * * @param netif network interface on which report IGMP memberships */ void igmp_report_groups(struct netif *netif) { struct igmp_group *group = igmp_group_list; LWIP_DEBUGF(IGMP_DEBUG, ("igmp_report_groups: sending IGMP reports on if %p\n", netif)); while (group != NULL) { if ((group->netif == netif) && (!(ip_addr_cmp(&(group->group_address), &allsystems)))) { igmp_delaying_member(group, IGMP_JOIN_DELAYING_MEMBER_TMR); } group = group->next; } } /** * Search for a group in the global igmp_group_list * * @param ifp the network interface for which to look * @param addr the group ip address to search for * @return a struct igmp_group* if the group has been found, * NULL if the group wasn't found. */ struct igmp_group * igmp_lookfor_group(struct netif *ifp, ip_addr_t *addr) { struct igmp_group *group = igmp_group_list; while (group != NULL) { if ((group->netif == ifp) && (ip_addr_cmp(&(group->group_address), addr))) { return group; } group = group->next; } /* to be clearer, we return NULL here instead of * 'group' (which is also NULL at this point). */ return NULL; } /** * Search for a specific igmp group and create a new one if not found- * * @param ifp the network interface for which to look * @param addr the group ip address to search * @return a struct igmp_group*, * NULL on memory error. */ struct igmp_group * igmp_lookup_group(struct netif *ifp, ip_addr_t *addr) { struct igmp_group *group = igmp_group_list; /* Search if the group already exists */ group = igmp_lookfor_group(ifp, addr); if (group != NULL) { /* Group already exists. */ return group; } /* Group doesn't exist yet, create a new one */ group = (struct igmp_group *)memp_malloc(MEMP_IGMP_GROUP); if (group != NULL) { group->netif = ifp; ip_addr_set(&(group->group_address), addr); group->timer = 0; /* Not running */ group->group_state = IGMP_GROUP_NON_MEMBER; group->last_reporter_flag = 0; group->use = 0; group->next = igmp_group_list; igmp_group_list = group; } LWIP_DEBUGF(IGMP_DEBUG, ("igmp_lookup_group: %sallocated a new group with address ", (group?"":"impossible to "))); ip_addr_debug_print(IGMP_DEBUG, addr); LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", ifp)); return group; } /** * Remove a group in the global igmp_group_list * * @param group the group to remove from the global igmp_group_list * @return ERR_OK if group was removed from the list, an err_t otherwise */ static err_t igmp_remove_group(struct igmp_group *group) { err_t err = ERR_OK; /* Is it the first group? */ if (igmp_group_list == group) { igmp_group_list = group->next; } else { /* look for group further down the list */ struct igmp_group *tmpGroup; for (tmpGroup = igmp_group_list; tmpGroup != NULL; tmpGroup = tmpGroup->next) { if (tmpGroup->next == group) { tmpGroup->next = group->next; break; } } /* Group not found in the global igmp_group_list */ if (tmpGroup == NULL) err = ERR_ARG; } /* free group */ memp_free(MEMP_IGMP_GROUP, group); return err; } /** * Called from ip_input() if a new IGMP packet is received. * * @param p received igmp packet, p->payload pointing to the igmp header * @param inp network interface on which the packet was received * @param dest destination ip address of the igmp packet */ void igmp_input(struct pbuf *p, struct netif *inp, ip_addr_t *dest) { struct igmp_msg* igmp; struct igmp_group* group; struct igmp_group* groupref; IGMP_STATS_INC(igmp.recv); /* Note that the length CAN be greater than 8 but only 8 are used - All are included in the checksum */ if (p->len < IGMP_MINLEN) { pbuf_free(p); IGMP_STATS_INC(igmp.lenerr); LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: length error\n")); return; } LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: message from ")); ip_addr_debug_print(IGMP_DEBUG, &(ip_current_header()->src)); LWIP_DEBUGF(IGMP_DEBUG, (" to address ")); ip_addr_debug_print(IGMP_DEBUG, &(ip_current_header()->dest)); LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", inp)); /* Now calculate and check the checksum */ igmp = (struct igmp_msg *)p->payload; if (inet_chksum(igmp, p->len)) { pbuf_free(p); IGMP_STATS_INC(igmp.chkerr); LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: checksum error\n")); return; } /* Packet is ok so find an existing group */ group = igmp_lookfor_group(inp, dest); /* use the destination IP address of incoming packet */ /* If group can be found or create... */ if (!group) { pbuf_free(p); IGMP_STATS_INC(igmp.drop); LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: IGMP frame not for us\n")); return; } /* NOW ACT ON THE INCOMING MESSAGE TYPE... */ switch (igmp->igmp_msgtype) { case IGMP_MEMB_QUERY: { /* IGMP_MEMB_QUERY to the "all systems" address ? */ if ((ip_addr_cmp(dest, &allsystems)) && ip_addr_isany(&igmp->igmp_group_address)) { /* THIS IS THE GENERAL QUERY */ LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: General IGMP_MEMB_QUERY on \"ALL SYSTEMS\" address (224.0.0.1) [igmp_maxresp=%i]\n", (int)(igmp->igmp_maxresp))); if (igmp->igmp_maxresp == 0) { IGMP_STATS_INC(igmp.rx_v1); LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: got an all hosts query with time== 0 - this is V1 and not implemented - treat as v2\n")); igmp->igmp_maxresp = IGMP_V1_DELAYING_MEMBER_TMR; } else { IGMP_STATS_INC(igmp.rx_general); } groupref = igmp_group_list; while (groupref) { /* Do not send messages on the all systems group address! */ if ((groupref->netif == inp) && (!(ip_addr_cmp(&(groupref->group_address), &allsystems)))) { igmp_delaying_member(groupref, igmp->igmp_maxresp); } groupref = groupref->next; } } else { /* IGMP_MEMB_QUERY to a specific group ? */ if (!ip_addr_isany(&igmp->igmp_group_address)) { LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: IGMP_MEMB_QUERY to a specific group ")); ip_addr_debug_print(IGMP_DEBUG, &igmp->igmp_group_address); if (ip_addr_cmp(dest, &allsystems)) { ip_addr_t groupaddr; LWIP_DEBUGF(IGMP_DEBUG, (" using \"ALL SYSTEMS\" address (224.0.0.1) [igmp_maxresp=%i]\n", (int)(igmp->igmp_maxresp))); /* we first need to re-look for the group since we used dest last time */ ip_addr_copy(groupaddr, igmp->igmp_group_address); group = igmp_lookfor_group(inp, &groupaddr); } else { LWIP_DEBUGF(IGMP_DEBUG, (" with the group address as destination [igmp_maxresp=%i]\n", (int)(igmp->igmp_maxresp))); } if (group != NULL) { IGMP_STATS_INC(igmp.rx_group); igmp_delaying_member(group, igmp->igmp_maxresp); } else { IGMP_STATS_INC(igmp.drop); } } else { IGMP_STATS_INC(igmp.proterr); } } break; } case IGMP_V2_MEMB_REPORT: { LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: IGMP_V2_MEMB_REPORT\n")); IGMP_STATS_INC(igmp.rx_report); if (group->group_state == IGMP_GROUP_DELAYING_MEMBER) { /* This is on a specific group we have already looked up */ group->timer = 0; /* stopped */ group->group_state = IGMP_GROUP_IDLE_MEMBER; group->last_reporter_flag = 0; } break; } default: { LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: unexpected msg %d in state %d on group %p on if %p\n", igmp->igmp_msgtype, group->group_state, &group, group->netif)); IGMP_STATS_INC(igmp.proterr); break; } } pbuf_free(p); return; } /** * Join a group on one network interface. * * @param ifaddr ip address of the network interface which should join a new group * @param groupaddr the ip address of the group which to join * @return ERR_OK if group was joined on the netif(s), an err_t otherwise */ err_t igmp_joingroup(ip_addr_t *ifaddr, ip_addr_t *groupaddr) { err_t err = ERR_VAL; /* no matching interface */ struct igmp_group *group; struct netif *netif; /* make sure it is multicast address */ LWIP_ERROR("igmp_joingroup: attempt to join non-multicast address", ip_addr_ismulticast(groupaddr), return ERR_VAL;); LWIP_ERROR("igmp_joingroup: attempt to join allsystems address", (!ip_addr_cmp(groupaddr, &allsystems)), return ERR_VAL;); /* loop through netif's */ netif = netif_list; while (netif != NULL) { /* Should we join this interface ? */ if ((netif->flags & NETIF_FLAG_IGMP) && ((ip_addr_isany(ifaddr) || ip_addr_cmp(&(netif->ip_addr), ifaddr)))) { /* find group or create a new one if not found */ group = igmp_lookup_group(netif, groupaddr); if (group != NULL) { /* This should create a new group, check the state to make sure */ if (group->group_state != IGMP_GROUP_NON_MEMBER) { LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup: join to group not in state IGMP_GROUP_NON_MEMBER\n")); } else { /* OK - it was new group */ LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup: join to new group: ")); ip_addr_debug_print(IGMP_DEBUG, groupaddr); LWIP_DEBUGF(IGMP_DEBUG, ("\n")); /* If first use of the group, allow the group at the MAC level */ if ((group->use==0) && (netif->igmp_mac_filter != NULL)) { LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup: igmp_mac_filter(ADD ")); ip_addr_debug_print(IGMP_DEBUG, groupaddr); LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", netif)); netif->igmp_mac_filter(netif, groupaddr, IGMP_ADD_MAC_FILTER); } IGMP_STATS_INC(igmp.tx_join); igmp_send(group, IGMP_V2_MEMB_REPORT); igmp_start_timer(group, IGMP_JOIN_DELAYING_MEMBER_TMR); /* Need to work out where this timer comes from */ group->group_state = IGMP_GROUP_DELAYING_MEMBER; } /* Increment group use */ group->use++; /* Join on this interface */ err = ERR_OK; } else { /* Return an error even if some network interfaces are joined */ /** @todo undo any other netif already joined */ LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup: Not enought memory to join to group\n")); return ERR_MEM; } } /* proceed to next network interface */ netif = netif->next; } return err; } /** * Leave a group on one network interface. * * @param ifaddr ip address of the network interface which should leave a group * @param groupaddr the ip address of the group which to leave * @return ERR_OK if group was left on the netif(s), an err_t otherwise */ err_t igmp_leavegroup(ip_addr_t *ifaddr, ip_addr_t *groupaddr) { err_t err = ERR_VAL; /* no matching interface */ struct igmp_group *group; struct netif *netif; /* make sure it is multicast address */ LWIP_ERROR("igmp_leavegroup: attempt to leave non-multicast address", ip_addr_ismulticast(groupaddr), return ERR_VAL;); LWIP_ERROR("igmp_leavegroup: attempt to leave allsystems address", (!ip_addr_cmp(groupaddr, &allsystems)), return ERR_VAL;); /* loop through netif's */ netif = netif_list; while (netif != NULL) { /* Should we leave this interface ? */ if ((netif->flags & NETIF_FLAG_IGMP) && ((ip_addr_isany(ifaddr) || ip_addr_cmp(&(netif->ip_addr), ifaddr)))) { /* find group */ group = igmp_lookfor_group(netif, groupaddr); if (group != NULL) { /* Only send a leave if the flag is set according to the state diagram */ LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: Leaving group: ")); ip_addr_debug_print(IGMP_DEBUG, groupaddr); LWIP_DEBUGF(IGMP_DEBUG, ("\n")); /* If there is no other use of the group */ if (group->use <= 1) { /* If we are the last reporter for this group */ if (group->last_reporter_flag) { LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: sending leaving group\n")); IGMP_STATS_INC(igmp.tx_leave); igmp_send(group, IGMP_LEAVE_GROUP); } /* Disable the group at the MAC level */ if (netif->igmp_mac_filter != NULL) { LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: igmp_mac_filter(DEL ")); ip_addr_debug_print(IGMP_DEBUG, groupaddr); LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", netif)); netif->igmp_mac_filter(netif, groupaddr, IGMP_DEL_MAC_FILTER); } LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: remove group: ")); ip_addr_debug_print(IGMP_DEBUG, groupaddr); LWIP_DEBUGF(IGMP_DEBUG, ("\n")); /* Free the group */ igmp_remove_group(group); } else { /* Decrement group use */ group->use--; } /* Leave on this interface */ err = ERR_OK; } else { /* It's not a fatal error on "leavegroup" */ LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: not member of group\n")); } } /* proceed to next network interface */ netif = netif->next; } return err; } /** * The igmp timer function (both for NO_SYS=1 and =0) * Should be called every IGMP_TMR_INTERVAL milliseconds (100 ms is default). */ void igmp_tmr(void) { struct igmp_group *group = igmp_group_list; while (group != NULL) { if (group->timer > 0) { group->timer--; if (group->timer == 0) { igmp_timeout(group); } } group = group->next; } } /** * Called if a timeout for one group is reached. * Sends a report for this group. * * @param group an igmp_group for which a timeout is reached */ static void igmp_timeout(struct igmp_group *group) { /* If the state is IGMP_GROUP_DELAYING_MEMBER then we send a report for this group (unless it is the allsystems group) */ if ((group->group_state == IGMP_GROUP_DELAYING_MEMBER) && (!(ip_addr_cmp(&(group->group_address), &allsystems)))) { LWIP_DEBUGF(IGMP_DEBUG, ("igmp_timeout: report membership for group with address ")); ip_addr_debug_print(IGMP_DEBUG, &(group->group_address)); LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", group->netif)); IGMP_STATS_INC(igmp.tx_report); igmp_send(group, IGMP_V2_MEMB_REPORT); } } /** * Start a timer for an igmp group * * @param group the igmp_group for which to start a timer * @param max_time the time in multiples of IGMP_TMR_INTERVAL (decrease with * every call to igmp_tmr()) */ static void igmp_start_timer(struct igmp_group *group, u8_t max_time) { /* ensure the input value is > 0 */ #ifdef LWIP_RAND if (max_time == 0) { max_time = 1; } /* ensure the random value is > 0 */ group->timer = (LWIP_RAND() % max_time); if (group->timer == 0) { group->timer = 1; } #else /* LWIP_RAND */ /* ATTENTION: use this only if absolutely necessary! */ group->timer = max_time / 2; if (group->timer == 0) { group->timer = 1; } #endif /* LWIP_RAND */ } /** * Delaying membership report for a group if necessary * * @param group the igmp_group for which "delaying" membership report * @param maxresp query delay */ static void igmp_delaying_member(struct igmp_group *group, u8_t maxresp) { if ((group->group_state == IGMP_GROUP_IDLE_MEMBER) || ((group->group_state == IGMP_GROUP_DELAYING_MEMBER) && ((group->timer == 0) || (maxresp < group->timer)))) { igmp_start_timer(group, maxresp); group->group_state = IGMP_GROUP_DELAYING_MEMBER; } } /** * Sends an IP packet on a network interface. This function constructs the IP header * and calculates the IP header checksum. If the source IP address is NULL, * the IP address of the outgoing network interface is filled in as source address. * * @param p the packet to send (p->payload points to the data, e.g. next protocol header; if dest == IP_HDRINCL, p already includes an IP header and p->payload points to that IP header) * @param src the source IP address to send from (if src == IP_ADDR_ANY, the * IP address of the netif used to send is used as source address) * @param dest the destination IP address to send the packet to * @param ttl the TTL value to be set in the IP header * @param proto the PROTOCOL to be set in the IP header * @param netif the netif on which to send this packet * @return ERR_OK if the packet was sent OK * ERR_BUF if p doesn't have enough space for IP/LINK headers * returns errors returned by netif->output */ static err_t igmp_ip_output_if(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, struct netif *netif) { /* This is the "router alert" option */ u16_t ra[2]; ra[0] = PP_HTONS(ROUTER_ALERT); ra[1] = 0x0000; /* Router shall examine packet */ IGMP_STATS_INC(igmp.xmit); return ip_output_if_opt(p, src, dest, IGMP_TTL, 0, IP_PROTO_IGMP, netif, ra, ROUTER_ALERTLEN); } /** * Send an igmp packet to a specific group. * * @param group the group to which to send the packet * @param type the type of igmp packet to send */ static void igmp_send(struct igmp_group *group, u8_t type) { struct pbuf* p = NULL; struct igmp_msg* igmp = NULL; ip_addr_t src = *IP_ADDR_ANY; ip_addr_t* dest = NULL; /* IP header + "router alert" option + IGMP header */ p = pbuf_alloc(PBUF_TRANSPORT, IGMP_MINLEN, PBUF_RAM); if (p) { igmp = (struct igmp_msg *)p->payload; LWIP_ASSERT("igmp_send: check that first pbuf can hold struct igmp_msg", (p->len >= sizeof(struct igmp_msg))); ip_addr_copy(src, group->netif->ip_addr); if (type == IGMP_V2_MEMB_REPORT) { dest = &(group->group_address); ip_addr_copy(igmp->igmp_group_address, group->group_address); group->last_reporter_flag = 1; /* Remember we were the last to report */ } else { if (type == IGMP_LEAVE_GROUP) { dest = &allrouters; ip_addr_copy(igmp->igmp_group_address, group->group_address); } } if ((type == IGMP_V2_MEMB_REPORT) || (type == IGMP_LEAVE_GROUP)) { igmp->igmp_msgtype = type; igmp->igmp_maxresp = 0; igmp->igmp_checksum = 0; igmp->igmp_checksum = inet_chksum(igmp, IGMP_MINLEN); igmp_ip_output_if(p, &src, dest, group->netif); } pbuf_free(p); } else { LWIP_DEBUGF(IGMP_DEBUG, ("igmp_send: not enough memory for igmp_send\n")); IGMP_STATS_INC(igmp.memerr); } } #endif /* LWIP_IGMP */ ocproxy-1.60/lwip/src/core/ipv4/ip4.c000066400000000000000000001024431303453231400173610ustar00rootroot00000000000000/** * @file * This is the IPv4 layer implementation for incoming and outgoing IP traffic. * * @see ip_frag.c * */ /* * Copyright (c) 2001-2004 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #include "lwip/opt.h" #include "lwip/ip.h" #include "lwip/def.h" #include "lwip/mem.h" #include "lwip/ip_frag.h" #include "lwip/inet_chksum.h" #include "lwip/netif.h" #include "lwip/icmp.h" #include "lwip/igmp.h" #include "lwip/raw.h" #include "lwip/udp.h" #include "lwip/tcp_impl.h" #include "lwip/snmp.h" #include "lwip/dhcp.h" #include "lwip/autoip.h" #include "lwip/stats.h" #include "arch/perf.h" #include /** Set this to 0 in the rare case of wanting to call an extra function to * generate the IP checksum (in contrast to calculating it on-the-fly). */ #ifndef LWIP_INLINE_IP_CHKSUM #define LWIP_INLINE_IP_CHKSUM 1 #endif #if LWIP_INLINE_IP_CHKSUM && CHECKSUM_GEN_IP #define CHECKSUM_GEN_IP_INLINE 1 #else #define CHECKSUM_GEN_IP_INLINE 0 #endif #if LWIP_DHCP || defined(LWIP_IP_ACCEPT_UDP_PORT) #define IP_ACCEPT_LINK_LAYER_ADDRESSING 1 /** Some defines for DHCP to let link-layer-addressed packets through while the * netif is down. * To use this in your own application/protocol, define LWIP_IP_ACCEPT_UDP_PORT * to return 1 if the port is accepted and 0 if the port is not accepted. */ #if LWIP_DHCP && defined(LWIP_IP_ACCEPT_UDP_PORT) /* accept DHCP client port and custom port */ #define IP_ACCEPT_LINK_LAYER_ADDRESSED_PORT(port) (((port) == PP_NTOHS(DHCP_CLIENT_PORT)) \ || (LWIP_IP_ACCEPT_UDP_PORT(port))) #elif defined(LWIP_IP_ACCEPT_UDP_PORT) /* LWIP_DHCP && defined(LWIP_IP_ACCEPT_UDP_PORT) */ /* accept custom port only */ #define IP_ACCEPT_LINK_LAYER_ADDRESSED_PORT(port) (LWIP_IP_ACCEPT_UDP_PORT(port)) #else /* LWIP_DHCP && defined(LWIP_IP_ACCEPT_UDP_PORT) */ /* accept DHCP client port only */ #define IP_ACCEPT_LINK_LAYER_ADDRESSED_PORT(port) ((port) == PP_NTOHS(DHCP_CLIENT_PORT)) #endif /* LWIP_DHCP && defined(LWIP_IP_ACCEPT_UDP_PORT) */ #else /* LWIP_DHCP */ #define IP_ACCEPT_LINK_LAYER_ADDRESSING 0 #endif /* LWIP_DHCP */ /** Global data for both IPv4 and IPv6 */ struct ip_globals ip_data; /** The IP header ID of the next outgoing IP packet */ static u16_t ip_id; /** * Finds the appropriate network interface for a given IP address. It * searches the list of network interfaces linearly. A match is found * if the masked IP address of the network interface equals the masked * IP address given to the function. * * @param dest the destination IP address for which to find the route * @return the netif on which to send to reach dest */ struct netif * ip_route(ip_addr_t *dest) { struct netif *netif; #ifdef LWIP_HOOK_IP4_ROUTE netif = LWIP_HOOK_IP4_ROUTE(dest); if (netif != NULL) { return netif; } #endif /* iterate through netifs */ for (netif = netif_list; netif != NULL; netif = netif->next) { /* network mask matches? */ if ((netif_is_up(netif)) #if LWIP_IPV6 /* prevent using IPv6-only interfaces */ && (!ip_addr_isany(&(netif->ip_addr))) #endif /* LWIP_IPV6 */ ) { if (ip_addr_netcmp(dest, &(netif->ip_addr), &(netif->netmask))) { /* return netif on which to forward IP packet */ return netif; } } } if ((netif_default == NULL) || (!netif_is_up(netif_default))) { LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip_route: No route to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", ip4_addr1_16(dest), ip4_addr2_16(dest), ip4_addr3_16(dest), ip4_addr4_16(dest))); IP_STATS_INC(ip.rterr); snmp_inc_ipoutnoroutes(); return NULL; } /* no matching netif found, use default netif */ return netif_default; } #if IP_FORWARD /** * Determine whether an IP address is in a reserved set of addresses * that may not be forwarded, or whether datagrams to that destination * may be forwarded. * @param p the packet to forward * @param dest the destination IP address * @return 1: can forward 0: discard */ static int ip_canforward(struct pbuf *p) { u32_t addr = htonl(ip4_addr_get_u32(ip_current_dest_addr())); if (p->flags & PBUF_FLAG_LLBCAST) { /* don't route link-layer broadcasts */ return 0; } if ((p->flags & PBUF_FLAG_LLMCAST) && !IP_MULTICAST(addr)) { /* don't route link-layer multicasts unless the destination address is an IP multicast address */ return 0; } if (IP_EXPERIMENTAL(addr)) { return 0; } if (IP_CLASSA(addr)) { u32_t net = addr & IP_CLASSA_NET; if ((net == 0) || (net == ((u32_t)IP_LOOPBACKNET << IP_CLASSA_NSHIFT))) { /* don't route loopback packets */ return 0; } } return 1; } /** * Forwards an IP packet. It finds an appropriate route for the * packet, decrements the TTL value of the packet, adjusts the * checksum and outputs the packet on the appropriate interface. * * @param p the packet to forward (p->payload points to IP header) * @param iphdr the IP header of the input packet * @param inp the netif on which this packet was received */ static void ip_forward(struct pbuf *p, struct ip_hdr *iphdr, struct netif *inp) { struct netif *netif; PERF_START; if (!ip_canforward(p)) { goto return_noroute; } /* RFC3927 2.7: do not forward link-local addresses */ if (ip_addr_islinklocal(ip_current_dest_addr())) { LWIP_DEBUGF(IP_DEBUG, ("ip_forward: not forwarding LLA %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", ip4_addr1_16(ip_current_dest_addr()), ip4_addr2_16(ip_current_dest_addr()), ip4_addr3_16(ip_current_dest_addr()), ip4_addr4_16(ip_current_dest_addr()))); goto return_noroute; } /* Find network interface where to forward this IP packet to. */ netif = ip_route(ip_current_dest_addr()); if (netif == NULL) { LWIP_DEBUGF(IP_DEBUG, ("ip_forward: no forwarding route for %"U16_F".%"U16_F".%"U16_F".%"U16_F" found\n", ip4_addr1_16(ip_current_dest_addr()), ip4_addr2_16(ip_current_dest_addr()), ip4_addr3_16(ip_current_dest_addr()), ip4_addr4_16(ip_current_dest_addr()))); /* @todo: send ICMP_DUR_NET? */ goto return_noroute; } #if !IP_FORWARD_ALLOW_TX_ON_RX_NETIF /* Do not forward packets onto the same network interface on which * they arrived. */ if (netif == inp) { LWIP_DEBUGF(IP_DEBUG, ("ip_forward: not bouncing packets back on incoming interface.\n")); goto return_noroute; } #endif /* IP_FORWARD_ALLOW_TX_ON_RX_NETIF */ /* decrement TTL */ IPH_TTL_SET(iphdr, IPH_TTL(iphdr) - 1); /* send ICMP if TTL == 0 */ if (IPH_TTL(iphdr) == 0) { snmp_inc_ipinhdrerrors(); #if LWIP_ICMP /* Don't send ICMP messages in response to ICMP messages */ if (IPH_PROTO(iphdr) != IP_PROTO_ICMP) { icmp_time_exceeded(p, ICMP_TE_TTL); } #endif /* LWIP_ICMP */ return; } /* Incrementally update the IP checksum. */ if (IPH_CHKSUM(iphdr) >= PP_HTONS(0xffffU - 0x100)) { IPH_CHKSUM_SET(iphdr, IPH_CHKSUM(iphdr) + PP_HTONS(0x100) + 1); } else { IPH_CHKSUM_SET(iphdr, IPH_CHKSUM(iphdr) + PP_HTONS(0x100)); } LWIP_DEBUGF(IP_DEBUG, ("ip_forward: forwarding packet to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", ip4_addr1_16(ip_current_dest_addr()), ip4_addr2_16(ip_current_dest_addr()), ip4_addr3_16(ip_current_dest_addr()), ip4_addr4_16(ip_current_dest_addr()))); IP_STATS_INC(ip.fw); IP_STATS_INC(ip.xmit); snmp_inc_ipforwdatagrams(); PERF_STOP("ip_forward"); /* don't fragment if interface has mtu set to 0 [loopif] */ if (netif->mtu && (p->tot_len > netif->mtu)) { if ((IPH_OFFSET(iphdr) & PP_NTOHS(IP_DF)) == 0) { #if IP_FRAG ip_frag(p, netif, ip_current_dest_addr()); #else /* IP_FRAG */ /* @todo: send ICMP Destination Unreacheable code 13 "Communication administratively prohibited"? */ #endif /* IP_FRAG */ } else { /* send ICMP Destination Unreacheable code 4: "Fragmentation Needed and DF Set" */ icmp_dest_unreach(p, ICMP_DUR_FRAG); } return; } /* transmit pbuf on chosen interface */ netif->output(netif, p, ip_current_dest_addr()); return; return_noroute: snmp_inc_ipoutnoroutes(); } #endif /* IP_FORWARD */ /** * This function is called by the network interface device driver when * an IP packet is received. The function does the basic checks of the * IP header such as packet size being at least larger than the header * size etc. If the packet was not destined for us, the packet is * forwarded (using ip_forward). The IP checksum is always checked. * * Finally, the packet is sent to the upper layer protocol input function. * * @param p the received IP packet (p->payload points to IP header) * @param inp the netif on which this packet was received * @return ERR_OK if the packet was processed (could return ERR_* if it wasn't * processed, but currently always returns ERR_OK) */ err_t ip_input(struct pbuf *p, struct netif *inp) { struct ip_hdr *iphdr; struct netif *netif; u16_t iphdr_hlen; u16_t iphdr_len; #if IP_ACCEPT_LINK_LAYER_ADDRESSING int check_ip_src=1; #endif /* IP_ACCEPT_LINK_LAYER_ADDRESSING */ IP_STATS_INC(ip.recv); snmp_inc_ipinreceives(); /* identify the IP header */ iphdr = (struct ip_hdr *)p->payload; if (IPH_V(iphdr) != 4) { LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_WARNING, ("IP packet dropped due to bad version number %"U16_F"\n", IPH_V(iphdr))); ip_debug_print(p); pbuf_free(p); IP_STATS_INC(ip.err); IP_STATS_INC(ip.drop); snmp_inc_ipinhdrerrors(); return ERR_OK; } #ifdef LWIP_HOOK_IP4_INPUT if (LWIP_HOOK_IP4_INPUT(p, inp)) { /* the packet has been eaten */ return ERR_OK; } #endif /* obtain IP header length in number of 32-bit words */ iphdr_hlen = IPH_HL(iphdr); /* calculate IP header length in bytes */ iphdr_hlen *= 4; /* obtain ip length in bytes */ iphdr_len = ntohs(IPH_LEN(iphdr)); /* header length exceeds first pbuf length, or ip length exceeds total pbuf length? */ if ((iphdr_hlen > p->len) || (iphdr_len > p->tot_len)) { if (iphdr_hlen > p->len) { LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("IP header (len %"U16_F") does not fit in first pbuf (len %"U16_F"), IP packet dropped.\n", iphdr_hlen, p->len)); } if (iphdr_len > p->tot_len) { LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("IP (len %"U16_F") is longer than pbuf (len %"U16_F"), IP packet dropped.\n", iphdr_len, p->tot_len)); } /* free (drop) packet pbufs */ pbuf_free(p); IP_STATS_INC(ip.lenerr); IP_STATS_INC(ip.drop); snmp_inc_ipindiscards(); return ERR_OK; } /* verify checksum */ #if CHECKSUM_CHECK_IP if (inet_chksum(iphdr, iphdr_hlen) != 0) { LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("Checksum (0x%"X16_F") failed, IP packet dropped.\n", inet_chksum(iphdr, iphdr_hlen))); ip_debug_print(p); pbuf_free(p); IP_STATS_INC(ip.chkerr); IP_STATS_INC(ip.drop); snmp_inc_ipinhdrerrors(); return ERR_OK; } #endif /* Trim pbuf. This should have been done at the netif layer, * but we'll do it anyway just to be sure that its done. */ pbuf_realloc(p, iphdr_len); /* copy IP addresses to aligned ip_addr_t */ ip_addr_copy(*ipX_2_ip(&ip_data.current_iphdr_dest), iphdr->dest); ip_addr_copy(*ipX_2_ip(&ip_data.current_iphdr_src), iphdr->src); /* match packet against an interface, i.e. is this packet for us? */ #if LWIP_IGMP if (ip_addr_ismulticast(ip_current_dest_addr())) { if ((inp->flags & NETIF_FLAG_IGMP) && (igmp_lookfor_group(inp, ip_current_dest_addr()))) { netif = inp; } else { netif = NULL; } } else #endif /* LWIP_IGMP */ { /* start trying with inp. if that's not acceptable, start walking the list of configured netifs. 'first' is used as a boolean to mark whether we started walking the list */ int first = 1; netif = inp; do { LWIP_DEBUGF(IP_DEBUG, ("ip_input: iphdr->dest 0x%"X32_F" netif->ip_addr 0x%"X32_F" (0x%"X32_F", 0x%"X32_F", 0x%"X32_F")\n", ip4_addr_get_u32(&iphdr->dest), ip4_addr_get_u32(&netif->ip_addr), ip4_addr_get_u32(&iphdr->dest) & ip4_addr_get_u32(&netif->netmask), ip4_addr_get_u32(&netif->ip_addr) & ip4_addr_get_u32(&netif->netmask), ip4_addr_get_u32(&iphdr->dest) & ~ip4_addr_get_u32(&netif->netmask))); /* interface is up and configured? */ if ((netif_is_up(netif)) && (!ip_addr_isany(&(netif->ip_addr)))) { /* unicast to this interface address? */ if (ip_addr_cmp(ip_current_dest_addr(), &(netif->ip_addr)) || /* or broadcast on this interface network address? */ ip_addr_isbroadcast(ip_current_dest_addr(), netif)) { LWIP_DEBUGF(IP_DEBUG, ("ip_input: packet accepted on interface %c%c\n", netif->name[0], netif->name[1])); /* break out of for loop */ break; } #if LWIP_AUTOIP /* connections to link-local addresses must persist after changing the netif's address (RFC3927 ch. 1.9) */ if ((netif->autoip != NULL) && ip_addr_cmp(ip_current_dest_addr(), &(netif->autoip->llipaddr))) { LWIP_DEBUGF(IP_DEBUG, ("ip_input: LLA packet accepted on interface %c%c\n", netif->name[0], netif->name[1])); /* break out of for loop */ break; } #endif /* LWIP_AUTOIP */ } if (first) { first = 0; netif = netif_list; } else { netif = netif->next; } if (netif == inp) { netif = netif->next; } } while(netif != NULL); } #if IP_ACCEPT_LINK_LAYER_ADDRESSING /* Pass DHCP messages regardless of destination address. DHCP traffic is addressed * using link layer addressing (such as Ethernet MAC) so we must not filter on IP. * According to RFC 1542 section 3.1.1, referred by RFC 2131). * * If you want to accept private broadcast communication while a netif is down, * define LWIP_IP_ACCEPT_UDP_PORT(dst_port), e.g.: * * #define LWIP_IP_ACCEPT_UDP_PORT(dst_port) ((dst_port) == PP_NTOHS(12345)) */ if (netif == NULL) { /* remote port is DHCP server? */ if (IPH_PROTO(iphdr) == IP_PROTO_UDP) { struct udp_hdr *udphdr = (struct udp_hdr *)((u8_t *)iphdr + iphdr_hlen); LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE, ("ip_input: UDP packet to DHCP client port %"U16_F"\n", ntohs(udphdr->dest))); if (IP_ACCEPT_LINK_LAYER_ADDRESSED_PORT(udphdr->dest)) { LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE, ("ip_input: DHCP packet accepted.\n")); netif = inp; check_ip_src = 0; } } } #endif /* IP_ACCEPT_LINK_LAYER_ADDRESSING */ /* broadcast or multicast packet source address? Compliant with RFC 1122: 3.2.1.3 */ #if IP_ACCEPT_LINK_LAYER_ADDRESSING /* DHCP servers need 0.0.0.0 to be allowed as source address (RFC 1.1.2.2: 3.2.1.3/a) */ if (check_ip_src && !ip_addr_isany(ip_current_src_addr())) #endif /* IP_ACCEPT_LINK_LAYER_ADDRESSING */ { if ((ip_addr_isbroadcast(ip_current_src_addr(), inp)) || (ip_addr_ismulticast(ip_current_src_addr()))) { /* packet source is not valid */ LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("ip_input: packet source is not valid.\n")); /* free (drop) packet pbufs */ pbuf_free(p); IP_STATS_INC(ip.drop); snmp_inc_ipinaddrerrors(); snmp_inc_ipindiscards(); return ERR_OK; } } /* packet not for us? */ if (netif == NULL) { /* packet not for us, route or discard */ LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE, ("ip_input: packet not for us.\n")); #if IP_FORWARD /* non-broadcast packet? */ if (!ip_addr_isbroadcast(ip_current_dest_addr(), inp)) { /* try to forward IP packet on (other) interfaces */ ip_forward(p, iphdr, inp); } else #endif /* IP_FORWARD */ { snmp_inc_ipinaddrerrors(); snmp_inc_ipindiscards(); } pbuf_free(p); return ERR_OK; } /* packet consists of multiple fragments? */ if ((IPH_OFFSET(iphdr) & PP_HTONS(IP_OFFMASK | IP_MF)) != 0) { #if IP_REASSEMBLY /* packet fragment reassembly code present? */ LWIP_DEBUGF(IP_DEBUG, ("IP packet is a fragment (id=0x%04"X16_F" tot_len=%"U16_F" len=%"U16_F" MF=%"U16_F" offset=%"U16_F"), calling ip_reass()\n", ntohs(IPH_ID(iphdr)), p->tot_len, ntohs(IPH_LEN(iphdr)), !!(IPH_OFFSET(iphdr) & PP_HTONS(IP_MF)), (ntohs(IPH_OFFSET(iphdr)) & IP_OFFMASK)*8)); /* reassemble the packet*/ p = ip_reass(p); /* packet not fully reassembled yet? */ if (p == NULL) { return ERR_OK; } iphdr = (struct ip_hdr *)p->payload; #else /* IP_REASSEMBLY == 0, no packet fragment reassembly code present */ pbuf_free(p); LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("IP packet dropped since it was fragmented (0x%"X16_F") (while IP_REASSEMBLY == 0).\n", ntohs(IPH_OFFSET(iphdr)))); IP_STATS_INC(ip.opterr); IP_STATS_INC(ip.drop); /* unsupported protocol feature */ snmp_inc_ipinunknownprotos(); return ERR_OK; #endif /* IP_REASSEMBLY */ } #if IP_OPTIONS_ALLOWED == 0 /* no support for IP options in the IP header? */ #if LWIP_IGMP /* there is an extra "router alert" option in IGMP messages which we allow for but do not police */ if((iphdr_hlen > IP_HLEN) && (IPH_PROTO(iphdr) != IP_PROTO_IGMP)) { #else if (iphdr_hlen > IP_HLEN) { #endif /* LWIP_IGMP */ LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("IP packet dropped since there were IP options (while IP_OPTIONS_ALLOWED == 0).\n")); pbuf_free(p); IP_STATS_INC(ip.opterr); IP_STATS_INC(ip.drop); /* unsupported protocol feature */ snmp_inc_ipinunknownprotos(); return ERR_OK; } #endif /* IP_OPTIONS_ALLOWED == 0 */ /* send to upper layers */ LWIP_DEBUGF(IP_DEBUG, ("ip_input: \n")); ip_debug_print(p); LWIP_DEBUGF(IP_DEBUG, ("ip_input: p->len %"U16_F" p->tot_len %"U16_F"\n", p->len, p->tot_len)); ip_data.current_netif = inp; ip_data.current_ip4_header = iphdr; ip_data.current_ip_header_tot_len = IPH_HL(iphdr) * 4; #if LWIP_RAW /* raw input did not eat the packet? */ if (raw_input(p, inp) == 0) #endif /* LWIP_RAW */ { pbuf_header(p, -iphdr_hlen); /* Move to payload, no check necessary. */ switch (IPH_PROTO(iphdr)) { #if LWIP_UDP case IP_PROTO_UDP: #if LWIP_UDPLITE case IP_PROTO_UDPLITE: #endif /* LWIP_UDPLITE */ snmp_inc_ipindelivers(); udp_input(p, inp); break; #endif /* LWIP_UDP */ #if LWIP_TCP case IP_PROTO_TCP: snmp_inc_ipindelivers(); tcp_input(p, inp); break; #endif /* LWIP_TCP */ #if LWIP_ICMP case IP_PROTO_ICMP: snmp_inc_ipindelivers(); icmp_input(p, inp); break; #endif /* LWIP_ICMP */ #if LWIP_IGMP case IP_PROTO_IGMP: igmp_input(p, inp, ip_current_dest_addr()); break; #endif /* LWIP_IGMP */ default: #if LWIP_ICMP /* send ICMP destination protocol unreachable unless is was a broadcast */ if (!ip_addr_isbroadcast(ip_current_dest_addr(), inp) && !ip_addr_ismulticast(ip_current_dest_addr())) { pbuf_header(p, iphdr_hlen); /* Move to ip header, no check necessary. */ p->payload = iphdr; icmp_dest_unreach(p, ICMP_DUR_PROTO); } #endif /* LWIP_ICMP */ pbuf_free(p); LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("Unsupported transport protocol %"U16_F"\n", IPH_PROTO(iphdr))); IP_STATS_INC(ip.proterr); IP_STATS_INC(ip.drop); snmp_inc_ipinunknownprotos(); } } /* @todo: this is not really necessary... */ ip_data.current_netif = NULL; ip_data.current_ip4_header = NULL; ip_data.current_ip_header_tot_len = 0; ip_addr_set_any(ip_current_src_addr()); ip_addr_set_any(ip_current_dest_addr()); return ERR_OK; } /** * Sends an IP packet on a network interface. This function constructs * the IP header and calculates the IP header checksum. If the source * IP address is NULL, the IP address of the outgoing network * interface is filled in as source address. * If the destination IP address is IP_HDRINCL, p is assumed to already * include an IP header and p->payload points to it instead of the data. * * @param p the packet to send (p->payload points to the data, e.g. next protocol header; if dest == IP_HDRINCL, p already includes an IP header and p->payload points to that IP header) * @param src the source IP address to send from (if src == IP_ADDR_ANY, the * IP address of the netif used to send is used as source address) * @param dest the destination IP address to send the packet to * @param ttl the TTL value to be set in the IP header * @param tos the TOS value to be set in the IP header * @param proto the PROTOCOL to be set in the IP header * @param netif the netif on which to send this packet * @return ERR_OK if the packet was sent OK * ERR_BUF if p doesn't have enough space for IP/LINK headers * returns errors returned by netif->output * * @note ip_id: RFC791 "some host may be able to simply use * unique identifiers independent of destination" */ err_t ip_output_if(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, u8_t ttl, u8_t tos, u8_t proto, struct netif *netif) { #if IP_OPTIONS_SEND return ip_output_if_opt(p, src, dest, ttl, tos, proto, netif, NULL, 0); } /** * Same as ip_output_if() but with the possibility to include IP options: * * @ param ip_options pointer to the IP options, copied into the IP header * @ param optlen length of ip_options */ err_t ip_output_if_opt(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, u8_t ttl, u8_t tos, u8_t proto, struct netif *netif, void *ip_options, u16_t optlen) { #endif /* IP_OPTIONS_SEND */ ip_addr_t *src_used = src; if (dest != IP_HDRINCL) { if (ip_addr_isany(src)) { src_used = &netif->ip_addr; } } #if IP_OPTIONS_SEND return ip_output_if_opt_src(p, src_used, dest, ttl, tos, proto, netif, ip_options, optlen); #else /* IP_OPTIONS_SEND */ return ip_output_if_src(p, src_used, dest, ttl, tos, proto, netif); #endif /* IP_OPTIONS_SEND */ } /** * Same as ip_output_if() but 'src' address is not replaced by netif address * when it is 'any'. */ err_t ip_output_if_src(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, u8_t ttl, u8_t tos, u8_t proto, struct netif *netif) { #if IP_OPTIONS_SEND return ip_output_if_opt_src(p, src, dest, ttl, tos, proto, netif, NULL, 0); } /** * Same as ip_output_if_opt() but 'src' address is not replaced by netif address * when it is 'any'. */ err_t ip_output_if_opt_src(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, u8_t ttl, u8_t tos, u8_t proto, struct netif *netif, void *ip_options, u16_t optlen) { #endif /* IP_OPTIONS_SEND */ struct ip_hdr *iphdr; ip_addr_t dest_addr; #if CHECKSUM_GEN_IP_INLINE u32_t chk_sum = 0; #endif /* CHECKSUM_GEN_IP_INLINE */ /* pbufs passed to IP must have a ref-count of 1 as their payload pointer gets altered as the packet is passed down the stack */ LWIP_ASSERT("p->ref == 1", p->ref == 1); snmp_inc_ipoutrequests(); /* Should the IP header be generated or is it already included in p? */ if (dest != IP_HDRINCL) { u16_t ip_hlen = IP_HLEN; #if IP_OPTIONS_SEND u16_t optlen_aligned = 0; if (optlen != 0) { #if CHECKSUM_GEN_IP_INLINE int i; #endif /* CHECKSUM_GEN_IP_INLINE */ /* round up to a multiple of 4 */ optlen_aligned = ((optlen + 3) & ~3); ip_hlen += optlen_aligned; /* First write in the IP options */ if (pbuf_header(p, optlen_aligned)) { LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip_output_if_opt: not enough room for IP options in pbuf\n")); IP_STATS_INC(ip.err); snmp_inc_ipoutdiscards(); return ERR_BUF; } MEMCPY(p->payload, ip_options, optlen); if (optlen < optlen_aligned) { /* zero the remaining bytes */ memset(((char*)p->payload) + optlen, 0, optlen_aligned - optlen); } #if CHECKSUM_GEN_IP_INLINE for (i = 0; i < optlen_aligned/2; i++) { chk_sum += ((u16_t*)p->payload)[i]; } #endif /* CHECKSUM_GEN_IP_INLINE */ } #endif /* IP_OPTIONS_SEND */ /* generate IP header */ if (pbuf_header(p, IP_HLEN)) { LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip_output: not enough room for IP header in pbuf\n")); IP_STATS_INC(ip.err); snmp_inc_ipoutdiscards(); return ERR_BUF; } iphdr = (struct ip_hdr *)p->payload; LWIP_ASSERT("check that first pbuf can hold struct ip_hdr", (p->len >= sizeof(struct ip_hdr))); IPH_TTL_SET(iphdr, ttl); IPH_PROTO_SET(iphdr, proto); #if CHECKSUM_GEN_IP_INLINE chk_sum += LWIP_MAKE_U16(proto, ttl); #endif /* CHECKSUM_GEN_IP_INLINE */ /* dest cannot be NULL here */ ip_addr_copy(iphdr->dest, *dest); #if CHECKSUM_GEN_IP_INLINE chk_sum += ip4_addr_get_u32(&iphdr->dest) & 0xFFFF; chk_sum += ip4_addr_get_u32(&iphdr->dest) >> 16; #endif /* CHECKSUM_GEN_IP_INLINE */ IPH_VHL_SET(iphdr, 4, ip_hlen / 4); IPH_TOS_SET(iphdr, tos); #if CHECKSUM_GEN_IP_INLINE chk_sum += LWIP_MAKE_U16(tos, iphdr->_v_hl); #endif /* CHECKSUM_GEN_IP_INLINE */ IPH_LEN_SET(iphdr, htons(p->tot_len)); #if CHECKSUM_GEN_IP_INLINE chk_sum += iphdr->_len; #endif /* CHECKSUM_GEN_IP_INLINE */ IPH_OFFSET_SET(iphdr, 0); IPH_ID_SET(iphdr, htons(ip_id)); #if CHECKSUM_GEN_IP_INLINE chk_sum += iphdr->_id; #endif /* CHECKSUM_GEN_IP_INLINE */ ++ip_id; if (src == NULL) { ip_addr_copy(iphdr->src, ip_addr_any); } else { /* src cannot be NULL here */ ip_addr_copy(iphdr->src, *src); } #if CHECKSUM_GEN_IP_INLINE chk_sum += ip4_addr_get_u32(&iphdr->src) & 0xFFFF; chk_sum += ip4_addr_get_u32(&iphdr->src) >> 16; chk_sum = (chk_sum >> 16) + (chk_sum & 0xFFFF); chk_sum = (chk_sum >> 16) + chk_sum; chk_sum = ~chk_sum; iphdr->_chksum = chk_sum; /* network order */ #else /* CHECKSUM_GEN_IP_INLINE */ IPH_CHKSUM_SET(iphdr, 0); #if CHECKSUM_GEN_IP IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, ip_hlen)); #endif #endif /* CHECKSUM_GEN_IP_INLINE */ } else { /* IP header already included in p */ iphdr = (struct ip_hdr *)p->payload; ip_addr_copy(dest_addr, iphdr->dest); dest = &dest_addr; } IP_STATS_INC(ip.xmit); LWIP_DEBUGF(IP_DEBUG, ("ip_output_if: %c%c%"U16_F"\n", netif->name[0], netif->name[1], netif->num)); ip_debug_print(p); #if ENABLE_LOOPBACK if (ip_addr_cmp(dest, &netif->ip_addr)) { /* Packet to self, enqueue it for loopback */ LWIP_DEBUGF(IP_DEBUG, ("netif_loop_output()")); return netif_loop_output(netif, p); } #if LWIP_IGMP if ((p->flags & PBUF_FLAG_MCASTLOOP) != 0) { netif_loop_output(netif, p); } #endif /* LWIP_IGMP */ #endif /* ENABLE_LOOPBACK */ #if IP_FRAG /* don't fragment if interface has mtu set to 0 [loopif] */ if (netif->mtu && (p->tot_len > netif->mtu)) { return ip_frag(p, netif, dest); } #endif /* IP_FRAG */ LWIP_DEBUGF(IP_DEBUG, ("netif->output()")); return netif->output(netif, p, dest); } /** * Simple interface to ip_output_if. It finds the outgoing network * interface and calls upon ip_output_if to do the actual work. * * @param p the packet to send (p->payload points to the data, e.g. next protocol header; if dest == IP_HDRINCL, p already includes an IP header and p->payload points to that IP header) * @param src the source IP address to send from (if src == IP_ADDR_ANY, the * IP address of the netif used to send is used as source address) * @param dest the destination IP address to send the packet to * @param ttl the TTL value to be set in the IP header * @param tos the TOS value to be set in the IP header * @param proto the PROTOCOL to be set in the IP header * * @return ERR_RTE if no route is found * see ip_output_if() for more return values */ err_t ip_output(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, u8_t ttl, u8_t tos, u8_t proto) { struct netif *netif; /* pbufs passed to IP must have a ref-count of 1 as their payload pointer gets altered as the packet is passed down the stack */ LWIP_ASSERT("p->ref == 1", p->ref == 1); if ((netif = ip_route(dest)) == NULL) { LWIP_DEBUGF(IP_DEBUG, ("ip_output: No route to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", ip4_addr1_16(dest), ip4_addr2_16(dest), ip4_addr3_16(dest), ip4_addr4_16(dest))); IP_STATS_INC(ip.rterr); return ERR_RTE; } return ip_output_if(p, src, dest, ttl, tos, proto, netif); } #if LWIP_NETIF_HWADDRHINT /** Like ip_output, but takes and addr_hint pointer that is passed on to netif->addr_hint * before calling ip_output_if. * * @param p the packet to send (p->payload points to the data, e.g. next protocol header; if dest == IP_HDRINCL, p already includes an IP header and p->payload points to that IP header) * @param src the source IP address to send from (if src == IP_ADDR_ANY, the * IP address of the netif used to send is used as source address) * @param dest the destination IP address to send the packet to * @param ttl the TTL value to be set in the IP header * @param tos the TOS value to be set in the IP header * @param proto the PROTOCOL to be set in the IP header * @param addr_hint address hint pointer set to netif->addr_hint before * calling ip_output_if() * * @return ERR_RTE if no route is found * see ip_output_if() for more return values */ err_t ip_output_hinted(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, u8_t ttl, u8_t tos, u8_t proto, u8_t *addr_hint) { struct netif *netif; err_t err; /* pbufs passed to IP must have a ref-count of 1 as their payload pointer gets altered as the packet is passed down the stack */ LWIP_ASSERT("p->ref == 1", p->ref == 1); if ((netif = ip_route(dest)) == NULL) { LWIP_DEBUGF(IP_DEBUG, ("ip_output: No route to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", ip4_addr1_16(dest), ip4_addr2_16(dest), ip4_addr3_16(dest), ip4_addr4_16(dest))); IP_STATS_INC(ip.rterr); return ERR_RTE; } NETIF_SET_HWADDRHINT(netif, addr_hint); err = ip_output_if(p, src, dest, ttl, tos, proto, netif); NETIF_SET_HWADDRHINT(netif, NULL); return err; } #endif /* LWIP_NETIF_HWADDRHINT*/ #if IP_DEBUG /* Print an IP header by using LWIP_DEBUGF * @param p an IP packet, p->payload pointing to the IP header */ void ip_debug_print(struct pbuf *p) { struct ip_hdr *iphdr = (struct ip_hdr *)p->payload; LWIP_DEBUGF(IP_DEBUG, ("IP header:\n")); LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n")); LWIP_DEBUGF(IP_DEBUG, ("|%2"S16_F" |%2"S16_F" | 0x%02"X16_F" | %5"U16_F" | (v, hl, tos, len)\n", IPH_V(iphdr), IPH_HL(iphdr), IPH_TOS(iphdr), ntohs(IPH_LEN(iphdr)))); LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n")); LWIP_DEBUGF(IP_DEBUG, ("| %5"U16_F" |%"U16_F"%"U16_F"%"U16_F"| %4"U16_F" | (id, flags, offset)\n", ntohs(IPH_ID(iphdr)), ntohs(IPH_OFFSET(iphdr)) >> 15 & 1, ntohs(IPH_OFFSET(iphdr)) >> 14 & 1, ntohs(IPH_OFFSET(iphdr)) >> 13 & 1, ntohs(IPH_OFFSET(iphdr)) & IP_OFFMASK)); LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n")); LWIP_DEBUGF(IP_DEBUG, ("| %3"U16_F" | %3"U16_F" | 0x%04"X16_F" | (ttl, proto, chksum)\n", IPH_TTL(iphdr), IPH_PROTO(iphdr), ntohs(IPH_CHKSUM(iphdr)))); LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n")); LWIP_DEBUGF(IP_DEBUG, ("| %3"U16_F" | %3"U16_F" | %3"U16_F" | %3"U16_F" | (src)\n", ip4_addr1_16(&iphdr->src), ip4_addr2_16(&iphdr->src), ip4_addr3_16(&iphdr->src), ip4_addr4_16(&iphdr->src))); LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n")); LWIP_DEBUGF(IP_DEBUG, ("| %3"U16_F" | %3"U16_F" | %3"U16_F" | %3"U16_F" | (dest)\n", ip4_addr1_16(&iphdr->dest), ip4_addr2_16(&iphdr->dest), ip4_addr3_16(&iphdr->dest), ip4_addr4_16(&iphdr->dest))); LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n")); } #endif /* IP_DEBUG */ ocproxy-1.60/lwip/src/core/ipv4/ip4_addr.c000066400000000000000000000206511303453231400203530ustar00rootroot00000000000000/** * @file * This is the IPv4 address tools implementation. * */ /* * Copyright (c) 2001-2004 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #include "lwip/opt.h" #include "lwip/ip_addr.h" #include "lwip/netif.h" /* used by IP_ADDR_ANY and IP_ADDR_BROADCAST in ip_addr.h */ const ip_addr_t ip_addr_any = { IPADDR_ANY }; const ip_addr_t ip_addr_broadcast = { IPADDR_BROADCAST }; /** * Determine if an address is a broadcast address on a network interface * * @param addr address to be checked * @param netif the network interface against which the address is checked * @return returns non-zero if the address is a broadcast address */ u8_t ip4_addr_isbroadcast(u32_t addr, const struct netif *netif) { ip_addr_t ipaddr; ip4_addr_set_u32(&ipaddr, addr); /* all ones (broadcast) or all zeroes (old skool broadcast) */ if ((~addr == IPADDR_ANY) || (addr == IPADDR_ANY)) { return 1; /* no broadcast support on this network interface? */ } else if ((netif->flags & NETIF_FLAG_BROADCAST) == 0) { /* the given address cannot be a broadcast address * nor can we check against any broadcast addresses */ return 0; /* address matches network interface address exactly? => no broadcast */ } else if (addr == ip4_addr_get_u32(&netif->ip_addr)) { return 0; /* on the same (sub) network... */ } else if (ip_addr_netcmp(&ipaddr, &(netif->ip_addr), &(netif->netmask)) /* ...and host identifier bits are all ones? =>... */ && ((addr & ~ip4_addr_get_u32(&netif->netmask)) == (IPADDR_BROADCAST & ~ip4_addr_get_u32(&netif->netmask)))) { /* => network broadcast address */ return 1; } else { return 0; } } /** Checks if a netmask is valid (starting with ones, then only zeros) * * @param netmask the IPv4 netmask to check (in network byte order!) * @return 1 if the netmask is valid, 0 if it is not */ u8_t ip4_addr_netmask_valid(u32_t netmask) { u32_t mask; u32_t nm_hostorder = lwip_htonl(netmask); /* first, check for the first zero */ for (mask = 1UL << 31 ; mask != 0; mask >>= 1) { if ((nm_hostorder & mask) == 0) { break; } } /* then check that there is no one */ for (; mask != 0; mask >>= 1) { if ((nm_hostorder & mask) != 0) { /* there is a one after the first zero -> invalid */ return 0; } } /* no one after the first zero -> valid */ return 1; } /* Here for now until needed in other places in lwIP */ #ifndef isprint #define in_range(c, lo, up) ((u8_t)c >= lo && (u8_t)c <= up) #define isprint(c) in_range(c, 0x20, 0x7f) #define isdigit(c) in_range(c, '0', '9') #define isxdigit(c) (isdigit(c) || in_range(c, 'a', 'f') || in_range(c, 'A', 'F')) #define islower(c) in_range(c, 'a', 'z') #define isspace(c) (c == ' ' || c == '\f' || c == '\n' || c == '\r' || c == '\t' || c == '\v') #endif /** * Ascii internet address interpretation routine. * The value returned is in network order. * * @param cp IP address in ascii represenation (e.g. "127.0.0.1") * @return ip address in network order */ u32_t ipaddr_addr(const char *cp) { ip_addr_t val; if (ipaddr_aton(cp, &val)) { return ip4_addr_get_u32(&val); } return (IPADDR_NONE); } /** * Check whether "cp" is a valid ascii representation * of an Internet address and convert to a binary address. * Returns 1 if the address is valid, 0 if not. * This replaces inet_addr, the return value from which * cannot distinguish between failure and a local broadcast address. * * @param cp IP address in ascii represenation (e.g. "127.0.0.1") * @param addr pointer to which to save the ip address in network order * @return 1 if cp could be converted to addr, 0 on failure */ int ipaddr_aton(const char *cp, ip_addr_t *addr) { u32_t val; u8_t base; char c; u32_t parts[4]; u32_t *pp = parts; c = *cp; for (;;) { /* * Collect number up to ``.''. * Values are specified as for C: * 0x=hex, 0=octal, 1-9=decimal. */ if (!isdigit(c)) return (0); val = 0; base = 10; if (c == '0') { c = *++cp; if (c == 'x' || c == 'X') { base = 16; c = *++cp; } else base = 8; } for (;;) { if (isdigit(c)) { val = (val * base) + (int)(c - '0'); c = *++cp; } else if (base == 16 && isxdigit(c)) { val = (val << 4) | (int)(c + 10 - (islower(c) ? 'a' : 'A')); c = *++cp; } else break; } if (c == '.') { /* * Internet format: * a.b.c.d * a.b.c (with c treated as 16 bits) * a.b (with b treated as 24 bits) */ if (pp >= parts + 3) { return (0); } *pp++ = val; c = *++cp; } else break; } /* * Check for trailing characters. */ if (c != '\0' && !isspace(c)) { return (0); } /* * Concoct the address according to * the number of parts specified. */ switch (pp - parts + 1) { case 0: return (0); /* initial nondigit */ case 1: /* a -- 32 bits */ break; case 2: /* a.b -- 8.24 bits */ if (val > 0xffffffUL) { return (0); } val |= parts[0] << 24; break; case 3: /* a.b.c -- 8.8.16 bits */ if (val > 0xffff) { return (0); } val |= (parts[0] << 24) | (parts[1] << 16); break; case 4: /* a.b.c.d -- 8.8.8.8 bits */ if (val > 0xff) { return (0); } val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8); break; default: LWIP_ASSERT("unhandled", 0); break; } if (addr) { ip4_addr_set_u32(addr, htonl(val)); } return (1); } /** * Convert numeric IP address into decimal dotted ASCII representation. * returns ptr to static buffer; not reentrant! * * @param addr ip address in network order to convert * @return pointer to a global static (!) buffer that holds the ASCII * represenation of addr */ char * ipaddr_ntoa(const ip_addr_t *addr) { static char str[16]; return ipaddr_ntoa_r(addr, str, 16); } /** * Same as ipaddr_ntoa, but reentrant since a user-supplied buffer is used. * * @param addr ip address in network order to convert * @param buf target buffer where the string is stored * @param buflen length of buf * @return either pointer to buf which now holds the ASCII * representation of addr or NULL if buf was too small */ char *ipaddr_ntoa_r(const ip_addr_t *addr, char *buf, int buflen) { u32_t s_addr; char inv[3]; char *rp; u8_t *ap; u8_t rem; u8_t n; u8_t i; int len = 0; s_addr = ip4_addr_get_u32(addr); rp = buf; ap = (u8_t *)&s_addr; for(n = 0; n < 4; n++) { i = 0; do { rem = *ap % (u8_t)10; *ap /= (u8_t)10; inv[i++] = '0' + rem; } while(*ap); while(i--) { if (len++ >= buflen) { return NULL; } *rp++ = inv[i]; } if (len++ >= buflen) { return NULL; } *rp++ = '.'; ap++; } *--rp = 0; return buf; } ocproxy-1.60/lwip/src/core/ipv4/ip_frag.c000066400000000000000000000710721303453231400202770ustar00rootroot00000000000000/** * @file * This is the IPv4 packet segmentation and reassembly implementation. * */ /* * Copyright (c) 2001-2004 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Jani Monoses * Simon Goldschmidt * original reassembly code by Adam Dunkels * */ #include "lwip/opt.h" #include "lwip/ip_frag.h" #include "lwip/def.h" #include "lwip/inet_chksum.h" #include "lwip/netif.h" #include "lwip/snmp.h" #include "lwip/stats.h" #include "lwip/icmp.h" #include #if IP_REASSEMBLY /** * The IP reassembly code currently has the following limitations: * - IP header options are not supported * - fragments must not overlap (e.g. due to different routes), * currently, overlapping or duplicate fragments are thrown away * if IP_REASS_CHECK_OVERLAP=1 (the default)! * * @todo: work with IP header options */ /** Setting this to 0, you can turn off checking the fragments for overlapping * regions. The code gets a little smaller. Only use this if you know that * overlapping won't occur on your network! */ #ifndef IP_REASS_CHECK_OVERLAP #define IP_REASS_CHECK_OVERLAP 1 #endif /* IP_REASS_CHECK_OVERLAP */ /** Set to 0 to prevent freeing the oldest datagram when the reassembly buffer is * full (IP_REASS_MAX_PBUFS pbufs are enqueued). The code gets a little smaller. * Datagrams will be freed by timeout only. Especially useful when MEMP_NUM_REASSDATA * is set to 1, so one datagram can be reassembled at a time, only. */ #ifndef IP_REASS_FREE_OLDEST #define IP_REASS_FREE_OLDEST 1 #endif /* IP_REASS_FREE_OLDEST */ #define IP_REASS_FLAG_LASTFRAG 0x01 /** This is a helper struct which holds the starting * offset and the ending offset of this fragment to * easily chain the fragments. * It has the same packing requirements as the IP header, since it replaces * the IP header in memory in incoming fragments (after copying it) to keep * track of the various fragments. (-> If the IP header doesn't need packing, * this struct doesn't need packing, too.) */ #ifdef PACK_STRUCT_USE_INCLUDES # include "arch/bpstruct.h" #endif PACK_STRUCT_BEGIN struct ip_reass_helper { PACK_STRUCT_FIELD(struct pbuf *next_pbuf); PACK_STRUCT_FIELD(u16_t start); PACK_STRUCT_FIELD(u16_t end); } PACK_STRUCT_STRUCT; PACK_STRUCT_END #ifdef PACK_STRUCT_USE_INCLUDES # include "arch/epstruct.h" #endif #define IP_ADDRESSES_AND_ID_MATCH(iphdrA, iphdrB) \ (ip_addr_cmp(&(iphdrA)->src, &(iphdrB)->src) && \ ip_addr_cmp(&(iphdrA)->dest, &(iphdrB)->dest) && \ IPH_ID(iphdrA) == IPH_ID(iphdrB)) ? 1 : 0 /* global variables */ static struct ip_reassdata *reassdatagrams; static u16_t ip_reass_pbufcount; /* function prototypes */ static void ip_reass_dequeue_datagram(struct ip_reassdata *ipr, struct ip_reassdata *prev); static int ip_reass_free_complete_datagram(struct ip_reassdata *ipr, struct ip_reassdata *prev); /** * Reassembly timer base function * for both NO_SYS == 0 and 1 (!). * * Should be called every 1000 msec (defined by IP_TMR_INTERVAL). */ void ip_reass_tmr(void) { struct ip_reassdata *r, *prev = NULL; r = reassdatagrams; while (r != NULL) { /* Decrement the timer. Once it reaches 0, * clean up the incomplete fragment assembly */ if (r->timer > 0) { r->timer--; LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_reass_tmr: timer dec %"U16_F"\n",(u16_t)r->timer)); prev = r; r = r->next; } else { /* reassembly timed out */ struct ip_reassdata *tmp; LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_reass_tmr: timer timed out\n")); tmp = r; /* get the next pointer before freeing */ r = r->next; /* free the helper struct and all enqueued pbufs */ ip_reass_free_complete_datagram(tmp, prev); } } } /** * Free a datagram (struct ip_reassdata) and all its pbufs. * Updates the total count of enqueued pbufs (ip_reass_pbufcount), * SNMP counters and sends an ICMP time exceeded packet. * * @param ipr datagram to free * @param prev the previous datagram in the linked list * @return the number of pbufs freed */ static int ip_reass_free_complete_datagram(struct ip_reassdata *ipr, struct ip_reassdata *prev) { u16_t pbufs_freed = 0; u8_t clen; struct pbuf *p; struct ip_reass_helper *iprh; LWIP_ASSERT("prev != ipr", prev != ipr); if (prev != NULL) { LWIP_ASSERT("prev->next == ipr", prev->next == ipr); } snmp_inc_ipreasmfails(); #if LWIP_ICMP iprh = (struct ip_reass_helper *)ipr->p->payload; if (iprh->start == 0) { /* The first fragment was received, send ICMP time exceeded. */ /* First, de-queue the first pbuf from r->p. */ p = ipr->p; ipr->p = iprh->next_pbuf; /* Then, copy the original header into it. */ SMEMCPY(p->payload, &ipr->iphdr, IP_HLEN); icmp_time_exceeded(p, ICMP_TE_FRAG); clen = pbuf_clen(p); LWIP_ASSERT("pbufs_freed + clen <= 0xffff", pbufs_freed + clen <= 0xffff); pbufs_freed += clen; pbuf_free(p); } #endif /* LWIP_ICMP */ /* First, free all received pbufs. The individual pbufs need to be released separately as they have not yet been chained */ p = ipr->p; while (p != NULL) { struct pbuf *pcur; iprh = (struct ip_reass_helper *)p->payload; pcur = p; /* get the next pointer before freeing */ p = iprh->next_pbuf; clen = pbuf_clen(pcur); LWIP_ASSERT("pbufs_freed + clen <= 0xffff", pbufs_freed + clen <= 0xffff); pbufs_freed += clen; pbuf_free(pcur); } /* Then, unchain the struct ip_reassdata from the list and free it. */ ip_reass_dequeue_datagram(ipr, prev); LWIP_ASSERT("ip_reass_pbufcount >= clen", ip_reass_pbufcount >= pbufs_freed); ip_reass_pbufcount -= pbufs_freed; return pbufs_freed; } #if IP_REASS_FREE_OLDEST /** * Free the oldest datagram to make room for enqueueing new fragments. * The datagram 'fraghdr' belongs to is not freed! * * @param fraghdr IP header of the current fragment * @param pbufs_needed number of pbufs needed to enqueue * (used for freeing other datagrams if not enough space) * @return the number of pbufs freed */ static int ip_reass_remove_oldest_datagram(struct ip_hdr *fraghdr, int pbufs_needed) { /* @todo Can't we simply remove the last datagram in the * linked list behind reassdatagrams? */ struct ip_reassdata *r, *oldest, *prev; int pbufs_freed = 0, pbufs_freed_current; int other_datagrams; /* Free datagrams until being allowed to enqueue 'pbufs_needed' pbufs, * but don't free the datagram that 'fraghdr' belongs to! */ do { oldest = NULL; prev = NULL; other_datagrams = 0; r = reassdatagrams; while (r != NULL) { if (!IP_ADDRESSES_AND_ID_MATCH(&r->iphdr, fraghdr)) { /* Not the same datagram as fraghdr */ other_datagrams++; if (oldest == NULL) { oldest = r; } else if (r->timer <= oldest->timer) { /* older than the previous oldest */ oldest = r; } } if (r->next != NULL) { prev = r; } r = r->next; } if (oldest != NULL) { pbufs_freed_current = ip_reass_free_complete_datagram(oldest, prev); pbufs_freed += pbufs_freed_current; } } while ((pbufs_freed < pbufs_needed) && (other_datagrams > 1)); return pbufs_freed; } #endif /* IP_REASS_FREE_OLDEST */ /** * Enqueues a new fragment into the fragment queue * @param fraghdr points to the new fragments IP hdr * @param clen number of pbufs needed to enqueue (used for freeing other datagrams if not enough space) * @return A pointer to the queue location into which the fragment was enqueued */ static struct ip_reassdata* ip_reass_enqueue_new_datagram(struct ip_hdr *fraghdr, int clen) { struct ip_reassdata* ipr; /* No matching previous fragment found, allocate a new reassdata struct */ ipr = (struct ip_reassdata *)memp_malloc(MEMP_REASSDATA); if (ipr == NULL) { #if IP_REASS_FREE_OLDEST if (ip_reass_remove_oldest_datagram(fraghdr, clen) >= clen) { ipr = (struct ip_reassdata *)memp_malloc(MEMP_REASSDATA); } if (ipr == NULL) #endif /* IP_REASS_FREE_OLDEST */ { IPFRAG_STATS_INC(ip_frag.memerr); LWIP_DEBUGF(IP_REASS_DEBUG,("Failed to alloc reassdata struct\n")); return NULL; } } memset(ipr, 0, sizeof(struct ip_reassdata)); ipr->timer = IP_REASS_MAXAGE; /* enqueue the new structure to the front of the list */ ipr->next = reassdatagrams; reassdatagrams = ipr; /* copy the ip header for later tests and input */ /* @todo: no ip options supported? */ SMEMCPY(&(ipr->iphdr), fraghdr, IP_HLEN); return ipr; } /** * Dequeues a datagram from the datagram queue. Doesn't deallocate the pbufs. * @param ipr points to the queue entry to dequeue */ static void ip_reass_dequeue_datagram(struct ip_reassdata *ipr, struct ip_reassdata *prev) { /* dequeue the reass struct */ if (reassdatagrams == ipr) { /* it was the first in the list */ reassdatagrams = ipr->next; } else { /* it wasn't the first, so it must have a valid 'prev' */ LWIP_ASSERT("sanity check linked list", prev != NULL); prev->next = ipr->next; } /* now we can free the ip_reass struct */ memp_free(MEMP_REASSDATA, ipr); } /** * Chain a new pbuf into the pbuf list that composes the datagram. The pbuf list * will grow over time as new pbufs are rx. * Also checks that the datagram passes basic continuity checks (if the last * fragment was received at least once). * @param root_p points to the 'root' pbuf for the current datagram being assembled. * @param new_p points to the pbuf for the current fragment * @return 0 if invalid, >0 otherwise */ static int ip_reass_chain_frag_into_datagram_and_validate(struct ip_reassdata *ipr, struct pbuf *new_p) { struct ip_reass_helper *iprh, *iprh_tmp, *iprh_prev=NULL; struct pbuf *q; u16_t offset,len; struct ip_hdr *fraghdr; int valid = 1; /* Extract length and fragment offset from current fragment */ fraghdr = (struct ip_hdr*)new_p->payload; len = ntohs(IPH_LEN(fraghdr)) - IPH_HL(fraghdr) * 4; offset = (ntohs(IPH_OFFSET(fraghdr)) & IP_OFFMASK) * 8; /* overwrite the fragment's ip header from the pbuf with our helper struct, * and setup the embedded helper structure. */ /* make sure the struct ip_reass_helper fits into the IP header */ LWIP_ASSERT("sizeof(struct ip_reass_helper) <= IP_HLEN", sizeof(struct ip_reass_helper) <= IP_HLEN); iprh = (struct ip_reass_helper*)new_p->payload; iprh->next_pbuf = NULL; iprh->start = offset; iprh->end = offset + len; /* Iterate through until we either get to the end of the list (append), * or we find on with a larger offset (insert). */ for (q = ipr->p; q != NULL;) { iprh_tmp = (struct ip_reass_helper*)q->payload; if (iprh->start < iprh_tmp->start) { /* the new pbuf should be inserted before this */ iprh->next_pbuf = q; if (iprh_prev != NULL) { /* not the fragment with the lowest offset */ #if IP_REASS_CHECK_OVERLAP if ((iprh->start < iprh_prev->end) || (iprh->end > iprh_tmp->start)) { /* fragment overlaps with previous or following, throw away */ goto freepbuf; } #endif /* IP_REASS_CHECK_OVERLAP */ iprh_prev->next_pbuf = new_p; } else { /* fragment with the lowest offset */ ipr->p = new_p; } break; } else if(iprh->start == iprh_tmp->start) { /* received the same datagram twice: no need to keep the datagram */ goto freepbuf; #if IP_REASS_CHECK_OVERLAP } else if(iprh->start < iprh_tmp->end) { /* overlap: no need to keep the new datagram */ goto freepbuf; #endif /* IP_REASS_CHECK_OVERLAP */ } else { /* Check if the fragments received so far have no wholes. */ if (iprh_prev != NULL) { if (iprh_prev->end != iprh_tmp->start) { /* There is a fragment missing between the current * and the previous fragment */ valid = 0; } } } q = iprh_tmp->next_pbuf; iprh_prev = iprh_tmp; } /* If q is NULL, then we made it to the end of the list. Determine what to do now */ if (q == NULL) { if (iprh_prev != NULL) { /* this is (for now), the fragment with the highest offset: * chain it to the last fragment */ #if IP_REASS_CHECK_OVERLAP LWIP_ASSERT("check fragments don't overlap", iprh_prev->end <= iprh->start); #endif /* IP_REASS_CHECK_OVERLAP */ iprh_prev->next_pbuf = new_p; if (iprh_prev->end != iprh->start) { valid = 0; } } else { #if IP_REASS_CHECK_OVERLAP LWIP_ASSERT("no previous fragment, this must be the first fragment!", ipr->p == NULL); #endif /* IP_REASS_CHECK_OVERLAP */ /* this is the first fragment we ever received for this ip datagram */ ipr->p = new_p; } } /* At this point, the validation part begins: */ /* If we already received the last fragment */ if ((ipr->flags & IP_REASS_FLAG_LASTFRAG) != 0) { /* and had no wholes so far */ if (valid) { /* then check if the rest of the fragments is here */ /* Check if the queue starts with the first datagram */ if ((ipr->p == NULL) || (((struct ip_reass_helper*)ipr->p->payload)->start != 0)) { valid = 0; } else { /* and check that there are no wholes after this datagram */ iprh_prev = iprh; q = iprh->next_pbuf; while (q != NULL) { iprh = (struct ip_reass_helper*)q->payload; if (iprh_prev->end != iprh->start) { valid = 0; break; } iprh_prev = iprh; q = iprh->next_pbuf; } /* if still valid, all fragments are received * (because to the MF==0 already arrived */ if (valid) { LWIP_ASSERT("sanity check", ipr->p != NULL); LWIP_ASSERT("sanity check", ((struct ip_reass_helper*)ipr->p->payload) != iprh); LWIP_ASSERT("validate_datagram:next_pbuf!=NULL", iprh->next_pbuf == NULL); LWIP_ASSERT("validate_datagram:datagram end!=datagram len", iprh->end == ipr->datagram_len); } } } /* If valid is 0 here, there are some fragments missing in the middle * (since MF == 0 has already arrived). Such datagrams simply time out if * no more fragments are received... */ return valid; } /* If we come here, not all fragments were received, yet! */ return 0; /* not yet valid! */ #if IP_REASS_CHECK_OVERLAP freepbuf: ip_reass_pbufcount -= pbuf_clen(new_p); pbuf_free(new_p); return 0; #endif /* IP_REASS_CHECK_OVERLAP */ } /** * Reassembles incoming IP fragments into an IP datagram. * * @param p points to a pbuf chain of the fragment * @return NULL if reassembly is incomplete, ? otherwise */ struct pbuf * ip_reass(struct pbuf *p) { struct pbuf *r; struct ip_hdr *fraghdr; struct ip_reassdata *ipr; struct ip_reass_helper *iprh; u16_t offset, len; u8_t clen; IPFRAG_STATS_INC(ip_frag.recv); snmp_inc_ipreasmreqds(); fraghdr = (struct ip_hdr*)p->payload; if ((IPH_HL(fraghdr) * 4) != IP_HLEN) { LWIP_DEBUGF(IP_REASS_DEBUG,("ip_reass: IP options currently not supported!\n")); IPFRAG_STATS_INC(ip_frag.err); goto nullreturn; } offset = (ntohs(IPH_OFFSET(fraghdr)) & IP_OFFMASK) * 8; len = ntohs(IPH_LEN(fraghdr)) - IPH_HL(fraghdr) * 4; /* Check if we are allowed to enqueue more datagrams. */ clen = pbuf_clen(p); if ((ip_reass_pbufcount + clen) > IP_REASS_MAX_PBUFS) { #if IP_REASS_FREE_OLDEST if (!ip_reass_remove_oldest_datagram(fraghdr, clen) || ((ip_reass_pbufcount + clen) > IP_REASS_MAX_PBUFS)) #endif /* IP_REASS_FREE_OLDEST */ { /* No datagram could be freed and still too many pbufs enqueued */ LWIP_DEBUGF(IP_REASS_DEBUG,("ip_reass: Overflow condition: pbufct=%d, clen=%d, MAX=%d\n", ip_reass_pbufcount, clen, IP_REASS_MAX_PBUFS)); IPFRAG_STATS_INC(ip_frag.memerr); /* @todo: send ICMP time exceeded here? */ /* drop this pbuf */ goto nullreturn; } } /* Look for the datagram the fragment belongs to in the current datagram queue, * remembering the previous in the queue for later dequeueing. */ for (ipr = reassdatagrams; ipr != NULL; ipr = ipr->next) { /* Check if the incoming fragment matches the one currently present in the reassembly buffer. If so, we proceed with copying the fragment into the buffer. */ if (IP_ADDRESSES_AND_ID_MATCH(&ipr->iphdr, fraghdr)) { LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_reass: matching previous fragment ID=%"X16_F"\n", ntohs(IPH_ID(fraghdr)))); IPFRAG_STATS_INC(ip_frag.cachehit); break; } } if (ipr == NULL) { /* Enqueue a new datagram into the datagram queue */ ipr = ip_reass_enqueue_new_datagram(fraghdr, clen); /* Bail if unable to enqueue */ if(ipr == NULL) { goto nullreturn; } } else { if (((ntohs(IPH_OFFSET(fraghdr)) & IP_OFFMASK) == 0) && ((ntohs(IPH_OFFSET(&ipr->iphdr)) & IP_OFFMASK) != 0)) { /* ipr->iphdr is not the header from the first fragment, but fraghdr is * -> copy fraghdr into ipr->iphdr since we want to have the header * of the first fragment (for ICMP time exceeded and later, for copying * all options, if supported)*/ SMEMCPY(&ipr->iphdr, fraghdr, IP_HLEN); } } /* Track the current number of pbufs current 'in-flight', in order to limit the number of fragments that may be enqueued at any one time */ ip_reass_pbufcount += clen; /* At this point, we have either created a new entry or pointing * to an existing one */ /* check for 'no more fragments', and update queue entry*/ if ((IPH_OFFSET(fraghdr) & PP_NTOHS(IP_MF)) == 0) { ipr->flags |= IP_REASS_FLAG_LASTFRAG; ipr->datagram_len = offset + len; LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_reass: last fragment seen, total len %"S16_F"\n", ipr->datagram_len)); } /* find the right place to insert this pbuf */ /* @todo: trim pbufs if fragments are overlapping */ if (ip_reass_chain_frag_into_datagram_and_validate(ipr, p)) { struct ip_reassdata *ipr_prev; /* the totally last fragment (flag more fragments = 0) was received at least * once AND all fragments are received */ ipr->datagram_len += IP_HLEN; /* save the second pbuf before copying the header over the pointer */ r = ((struct ip_reass_helper*)ipr->p->payload)->next_pbuf; /* copy the original ip header back to the first pbuf */ fraghdr = (struct ip_hdr*)(ipr->p->payload); SMEMCPY(fraghdr, &ipr->iphdr, IP_HLEN); IPH_LEN_SET(fraghdr, htons(ipr->datagram_len)); IPH_OFFSET_SET(fraghdr, 0); IPH_CHKSUM_SET(fraghdr, 0); /* @todo: do we need to set calculate the correct checksum? */ #if CHECKSUM_GEN_IP IPH_CHKSUM_SET(fraghdr, inet_chksum(fraghdr, IP_HLEN)); #endif /* CHECKSUM_GEN_IP */ p = ipr->p; /* chain together the pbufs contained within the reass_data list. */ while(r != NULL) { iprh = (struct ip_reass_helper*)r->payload; /* hide the ip header for every succeding fragment */ pbuf_header(r, -IP_HLEN); pbuf_cat(p, r); r = iprh->next_pbuf; } /* find the previous entry in the linked list */ if (ipr == reassdatagrams) { ipr_prev = NULL; } else { for (ipr_prev = reassdatagrams; ipr_prev != NULL; ipr_prev = ipr_prev->next) { if (ipr_prev->next == ipr) { break; } } } /* release the sources allocate for the fragment queue entry */ ip_reass_dequeue_datagram(ipr, ipr_prev); /* and adjust the number of pbufs currently queued for reassembly. */ ip_reass_pbufcount -= pbuf_clen(p); /* Return the pbuf chain */ return p; } /* the datagram is not (yet?) reassembled completely */ LWIP_DEBUGF(IP_REASS_DEBUG,("ip_reass_pbufcount: %d out\n", ip_reass_pbufcount)); return NULL; nullreturn: LWIP_DEBUGF(IP_REASS_DEBUG,("ip_reass: nullreturn\n")); IPFRAG_STATS_INC(ip_frag.drop); pbuf_free(p); return NULL; } #endif /* IP_REASSEMBLY */ #if IP_FRAG #if IP_FRAG_USES_STATIC_BUF static u8_t buf[LWIP_MEM_ALIGN_SIZE(IP_FRAG_MAX_MTU + MEM_ALIGNMENT - 1)]; #else /* IP_FRAG_USES_STATIC_BUF */ #if !LWIP_NETIF_TX_SINGLE_PBUF /** Allocate a new struct pbuf_custom_ref */ static struct pbuf_custom_ref* ip_frag_alloc_pbuf_custom_ref(void) { return (struct pbuf_custom_ref*)memp_malloc(MEMP_FRAG_PBUF); } /** Free a struct pbuf_custom_ref */ static void ip_frag_free_pbuf_custom_ref(struct pbuf_custom_ref* p) { LWIP_ASSERT("p != NULL", p != NULL); memp_free(MEMP_FRAG_PBUF, p); } /** Free-callback function to free a 'struct pbuf_custom_ref', called by * pbuf_free. */ static void ipfrag_free_pbuf_custom(struct pbuf *p) { struct pbuf_custom_ref *pcr = (struct pbuf_custom_ref*)p; LWIP_ASSERT("pcr != NULL", pcr != NULL); LWIP_ASSERT("pcr == p", (void*)pcr == (void*)p); if (pcr->original != NULL) { pbuf_free(pcr->original); } ip_frag_free_pbuf_custom_ref(pcr); } #endif /* !LWIP_NETIF_TX_SINGLE_PBUF */ #endif /* IP_FRAG_USES_STATIC_BUF */ /** * Fragment an IP datagram if too large for the netif. * * Chop the datagram in MTU sized chunks and send them in order * by using a fixed size static memory buffer (PBUF_REF) or * point PBUF_REFs into p (depending on IP_FRAG_USES_STATIC_BUF). * * @param p ip packet to send * @param netif the netif on which to send * @param dest destination ip address to which to send * * @return ERR_OK if sent successfully, err_t otherwise */ err_t ip_frag(struct pbuf *p, struct netif *netif, ip_addr_t *dest) { struct pbuf *rambuf; #if IP_FRAG_USES_STATIC_BUF struct pbuf *header; #else #if !LWIP_NETIF_TX_SINGLE_PBUF struct pbuf *newpbuf; #endif struct ip_hdr *original_iphdr; #endif struct ip_hdr *iphdr; u16_t nfb; u16_t left, cop; u16_t mtu = netif->mtu; u16_t ofo, omf; u16_t last; u16_t poff = IP_HLEN; u16_t tmp; #if !IP_FRAG_USES_STATIC_BUF && !LWIP_NETIF_TX_SINGLE_PBUF u16_t newpbuflen = 0; u16_t left_to_copy; #endif /* Get a RAM based MTU sized pbuf */ #if IP_FRAG_USES_STATIC_BUF /* When using a static buffer, we use a PBUF_REF, which we will * use to reference the packet (without link header). * Layer and length is irrelevant. */ rambuf = pbuf_alloc(PBUF_LINK, 0, PBUF_REF); if (rambuf == NULL) { LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_frag: pbuf_alloc(PBUF_LINK, 0, PBUF_REF) failed\n")); return ERR_MEM; } rambuf->tot_len = rambuf->len = mtu; rambuf->payload = LWIP_MEM_ALIGN((void *)buf); /* Copy the IP header in it */ iphdr = (struct ip_hdr *)rambuf->payload; SMEMCPY(iphdr, p->payload, IP_HLEN); #else /* IP_FRAG_USES_STATIC_BUF */ original_iphdr = (struct ip_hdr *)p->payload; iphdr = original_iphdr; #endif /* IP_FRAG_USES_STATIC_BUF */ /* Save original offset */ tmp = ntohs(IPH_OFFSET(iphdr)); ofo = tmp & IP_OFFMASK; omf = tmp & IP_MF; left = p->tot_len - IP_HLEN; nfb = (mtu - IP_HLEN) / 8; while (left) { last = (left <= mtu - IP_HLEN); /* Set new offset and MF flag */ tmp = omf | (IP_OFFMASK & (ofo)); if (!last) { tmp = tmp | IP_MF; } /* Fill this fragment */ cop = last ? left : nfb * 8; #if IP_FRAG_USES_STATIC_BUF poff += pbuf_copy_partial(p, (u8_t*)iphdr + IP_HLEN, cop, poff); #else /* IP_FRAG_USES_STATIC_BUF */ #if LWIP_NETIF_TX_SINGLE_PBUF rambuf = pbuf_alloc(PBUF_IP, cop, PBUF_RAM); if (rambuf == NULL) { return ERR_MEM; } LWIP_ASSERT("this needs a pbuf in one piece!", (rambuf->len == rambuf->tot_len) && (rambuf->next == NULL)); poff += pbuf_copy_partial(p, rambuf->payload, cop, poff); /* make room for the IP header */ if(pbuf_header(rambuf, IP_HLEN)) { pbuf_free(rambuf); return ERR_MEM; } /* fill in the IP header */ SMEMCPY(rambuf->payload, original_iphdr, IP_HLEN); iphdr = rambuf->payload; #else /* LWIP_NETIF_TX_SINGLE_PBUF */ /* When not using a static buffer, create a chain of pbufs. * The first will be a PBUF_RAM holding the link and IP header. * The rest will be PBUF_REFs mirroring the pbuf chain to be fragged, * but limited to the size of an mtu. */ rambuf = pbuf_alloc(PBUF_LINK, IP_HLEN, PBUF_RAM); if (rambuf == NULL) { return ERR_MEM; } LWIP_ASSERT("this needs a pbuf in one piece!", (p->len >= (IP_HLEN))); SMEMCPY(rambuf->payload, original_iphdr, IP_HLEN); iphdr = (struct ip_hdr *)rambuf->payload; /* Can just adjust p directly for needed offset. */ p->payload = (u8_t *)p->payload + poff; p->len -= poff; left_to_copy = cop; while (left_to_copy) { struct pbuf_custom_ref *pcr; newpbuflen = (left_to_copy < p->len) ? left_to_copy : p->len; /* Is this pbuf already empty? */ if (!newpbuflen) { p = p->next; continue; } pcr = ip_frag_alloc_pbuf_custom_ref(); if (pcr == NULL) { pbuf_free(rambuf); return ERR_MEM; } /* Mirror this pbuf, although we might not need all of it. */ newpbuf = pbuf_alloced_custom(PBUF_RAW, newpbuflen, PBUF_REF, &pcr->pc, p->payload, newpbuflen); if (newpbuf == NULL) { ip_frag_free_pbuf_custom_ref(pcr); pbuf_free(rambuf); return ERR_MEM; } pbuf_ref(p); pcr->original = p; pcr->pc.custom_free_function = ipfrag_free_pbuf_custom; /* Add it to end of rambuf's chain, but using pbuf_cat, not pbuf_chain * so that it is removed when pbuf_dechain is later called on rambuf. */ pbuf_cat(rambuf, newpbuf); left_to_copy -= newpbuflen; if (left_to_copy) { p = p->next; } } poff = newpbuflen; #endif /* LWIP_NETIF_TX_SINGLE_PBUF */ #endif /* IP_FRAG_USES_STATIC_BUF */ /* Correct header */ IPH_OFFSET_SET(iphdr, htons(tmp)); IPH_LEN_SET(iphdr, htons(cop + IP_HLEN)); IPH_CHKSUM_SET(iphdr, 0); #if CHECKSUM_GEN_IP IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN)); #endif /* CHECKSUM_GEN_IP */ #if IP_FRAG_USES_STATIC_BUF if (last) { pbuf_realloc(rambuf, left + IP_HLEN); } /* This part is ugly: we alloc a RAM based pbuf for * the link level header for each chunk and then * free it.A PBUF_ROM style pbuf for which pbuf_header * worked would make things simpler. */ header = pbuf_alloc(PBUF_LINK, 0, PBUF_RAM); if (header != NULL) { pbuf_chain(header, rambuf); netif->output(netif, header, dest); IPFRAG_STATS_INC(ip_frag.xmit); snmp_inc_ipfragcreates(); pbuf_free(header); } else { LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_frag: pbuf_alloc() for header failed\n")); pbuf_free(rambuf); return ERR_MEM; } #else /* IP_FRAG_USES_STATIC_BUF */ /* No need for separate header pbuf - we allowed room for it in rambuf * when allocated. */ netif->output(netif, rambuf, dest); IPFRAG_STATS_INC(ip_frag.xmit); /* Unfortunately we can't reuse rambuf - the hardware may still be * using the buffer. Instead we free it (and the ensuing chain) and * recreate it next time round the loop. If we're lucky the hardware * will have already sent the packet, the free will really free, and * there will be zero memory penalty. */ pbuf_free(rambuf); #endif /* IP_FRAG_USES_STATIC_BUF */ left -= cop; ofo += nfb; } #if IP_FRAG_USES_STATIC_BUF pbuf_free(rambuf); #endif /* IP_FRAG_USES_STATIC_BUF */ snmp_inc_ipfragoks(); return ERR_OK; } #endif /* IP_FRAG */ ocproxy-1.60/lwip/src/core/ipv6/000077500000000000000000000000001303453231400165175ustar00rootroot00000000000000ocproxy-1.60/lwip/src/core/ipv6/README000066400000000000000000000000531303453231400173750ustar00rootroot00000000000000IPv6 support in lwIP is very experimental. ocproxy-1.60/lwip/src/core/ipv6/dhcp6.c000066400000000000000000000035401303453231400176710ustar00rootroot00000000000000/** * @file * * DHCPv6. */ /* * Copyright (c) 2010 Inico Technologies Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Ivan Delamer * * * Please coordinate changes and requests with Ivan Delamer * */ #include "lwip/opt.h" #if LWIP_IPV6_DHCP6 /* don't build if not configured for use in lwipopts.h */ #include "lwip/ip6_addr.h" #include "lwip/def.h" #endif /* LWIP_IPV6_DHCP6 */ ocproxy-1.60/lwip/src/core/ipv6/ethip6.c000066400000000000000000000144751303453231400200750ustar00rootroot00000000000000/** * @file * * Ethernet output for IPv6. Uses ND tables for link-layer addressing. */ /* * Copyright (c) 2010 Inico Technologies Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Ivan Delamer * * * Please coordinate changes and requests with Ivan Delamer * */ #include "lwip/opt.h" #if LWIP_IPV6 && LWIP_ETHERNET #include "lwip/ethip6.h" #include "lwip/nd6.h" #include "lwip/pbuf.h" #include "lwip/ip6.h" #include "lwip/ip6_addr.h" #include "lwip/inet_chksum.h" #include "lwip/netif.h" #include "lwip/icmp6.h" #include #define ETHTYPE_IPV6 0x86DD /** The ethernet address */ #ifdef PACK_STRUCT_USE_INCLUDES # include "arch/bpstruct.h" #endif PACK_STRUCT_BEGIN struct eth_addr { PACK_STRUCT_FIELD(u8_t addr[6]); } PACK_STRUCT_STRUCT; PACK_STRUCT_END #ifdef PACK_STRUCT_USE_INCLUDES # include "arch/epstruct.h" #endif /** Ethernet header */ #ifdef PACK_STRUCT_USE_INCLUDES # include "arch/bpstruct.h" #endif PACK_STRUCT_BEGIN struct eth_hdr { #if ETH_PAD_SIZE PACK_STRUCT_FIELD(u8_t padding[ETH_PAD_SIZE]); #endif PACK_STRUCT_FIELD(struct eth_addr dest); PACK_STRUCT_FIELD(struct eth_addr src); PACK_STRUCT_FIELD(u16_t type); } PACK_STRUCT_STRUCT; PACK_STRUCT_END #ifdef PACK_STRUCT_USE_INCLUDES # include "arch/epstruct.h" #endif #define SIZEOF_ETH_HDR (14 + ETH_PAD_SIZE) /** * Send an IPv6 packet on the network using netif->linkoutput * The ethernet header is filled in before sending. * * @params netif the lwIP network interface on which to send the packet * @params p the packet to send, p->payload pointing to the (uninitialized) ethernet header * @params src the source MAC address to be copied into the ethernet header * @params dst the destination MAC address to be copied into the ethernet header * @return ERR_OK if the packet was sent, any other err_t on failure */ static err_t ethip6_send(struct netif *netif, struct pbuf *p, struct eth_addr *src, struct eth_addr *dst) { struct eth_hdr *ethhdr = (struct eth_hdr *)p->payload; LWIP_ASSERT("netif->hwaddr_len must be 6 for ethip6!", (netif->hwaddr_len == 6)); SMEMCPY(ðhdr->dest, dst, 6); SMEMCPY(ðhdr->src, src, 6); ethhdr->type = PP_HTONS(ETHTYPE_IPV6); LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("ethip6_send: sending packet %p\n", (void *)p)); /* send the packet */ return netif->linkoutput(netif, p); } /** * Resolve and fill-in Ethernet address header for outgoing IPv6 packet. * * For IPv6 multicast, corresponding Ethernet addresses * are selected and the packet is transmitted on the link. * * For unicast addresses, ... * * @TODO anycast addresses * * @param netif The lwIP network interface which the IP packet will be sent on. * @param q The pbuf(s) containing the IP packet to be sent. * @param ip6addr The IP address of the packet destination. * * @return * - ERR_RTE No route to destination (no gateway to external networks), * or the return type of either etharp_query() or etharp_send_ip(). */ err_t ethip6_output(struct netif *netif, struct pbuf *q, ip6_addr_t *ip6addr) { struct eth_addr dest; s8_t i; /* make room for Ethernet header - should not fail */ if (pbuf_header(q, sizeof(struct eth_hdr)) != 0) { /* bail out */ LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("etharp_output: could not allocate room for header.\n")); return ERR_BUF; } /* multicast destination IP address? */ if (ip6_addr_ismulticast(ip6addr)) { /* Hash IP multicast address to MAC address.*/ dest.addr[0] = 0x33; dest.addr[1] = 0x33; dest.addr[2] = ((u8_t *)(&(ip6addr->addr[3])))[0]; dest.addr[3] = ((u8_t *)(&(ip6addr->addr[3])))[1]; dest.addr[4] = ((u8_t *)(&(ip6addr->addr[3])))[2]; dest.addr[5] = ((u8_t *)(&(ip6addr->addr[3])))[3]; /* Send out. */ return ethip6_send(netif, q, (struct eth_addr*)(netif->hwaddr), &dest); } /* We have a unicast destination IP address */ /* TODO anycast? */ /* Get next hop record. */ i = nd6_get_next_hop_entry(ip6addr, netif); if (i < 0) { /* failed to get a next hop neighbor record. */ return ERR_MEM; } /* Now that we have a destination record, send or queue the packet. */ if (neighbor_cache[i].state == ND6_STALE) { /* Switch to delay state. */ neighbor_cache[i].state = ND6_DELAY; neighbor_cache[i].counter.delay_time = LWIP_ND6_DELAY_FIRST_PROBE_TIME; } /* TODO should we send or queue if PROBE? send for now, to let unicast NS pass. */ if ((neighbor_cache[i].state == ND6_REACHABLE) || (neighbor_cache[i].state == ND6_DELAY) || (neighbor_cache[i].state == ND6_PROBE)) { /* Send out. */ SMEMCPY(dest.addr, neighbor_cache[i].lladdr, 6); return ethip6_send(netif, q, (struct eth_addr*)(netif->hwaddr), &dest); } /* We should queue packet on this interface. */ pbuf_header(q, -(s16_t)SIZEOF_ETH_HDR); return nd6_queue_packet(i, q); } #endif /* LWIP_IPV6 && LWIP_ETHERNET */ ocproxy-1.60/lwip/src/core/ipv6/icmp6.c000066400000000000000000000235331303453231400177070ustar00rootroot00000000000000/** * @file * * IPv6 version of ICMP, as per RFC 4443. */ /* * Copyright (c) 2010 Inico Technologies Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Ivan Delamer * * * Please coordinate changes and requests with Ivan Delamer * */ #include "lwip/opt.h" #if LWIP_ICMP6 && LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */ #include "lwip/icmp6.h" #include "lwip/ip6.h" #include "lwip/ip6_addr.h" #include "lwip/inet_chksum.h" #include "lwip/pbuf.h" #include "lwip/netif.h" #include "lwip/nd6.h" #include "lwip/mld6.h" #include "lwip/ip.h" #include "lwip/stats.h" #include #ifndef LWIP_ICMP6_DATASIZE #define LWIP_ICMP6_DATASIZE 8 #endif #if LWIP_ICMP6_DATASIZE == 0 #define LWIP_ICMP6_DATASIZE 8 #endif /* Forward declarations */ static void icmp6_send_response(struct pbuf *p, u8_t code, u32_t data, u8_t type); /** * Process an input ICMPv6 message. Called by ip6_input. * * Will generate a reply for echo requests. Other messages are forwarded * to nd6_input, or mld6_input. * * @param p the mld packet, p->payload pointing to the icmpv6 header * @param inp the netif on which this packet was received */ void icmp6_input(struct pbuf *p, struct netif *inp) { struct icmp6_hdr *icmp6hdr; struct pbuf * r; ip6_addr_t * reply_src; ICMP6_STATS_INC(icmp6.recv); /* Check that ICMPv6 header fits in payload */ if (p->len < sizeof(struct icmp6_hdr)) { /* drop short packets */ pbuf_free(p); ICMP6_STATS_INC(icmp6.lenerr); ICMP6_STATS_INC(icmp6.drop); return; } icmp6hdr = (struct icmp6_hdr *)p->payload; #if CHECKSUM_CHECK_ICMP6 if (ip6_chksum_pseudo(p, IP6_NEXTH_ICMP6, p->tot_len, ip6_current_src_addr(), ip6_current_dest_addr()) != 0) { /* Checksum failed */ pbuf_free(p); ICMP6_STATS_INC(icmp6.chkerr); ICMP6_STATS_INC(icmp6.drop); return; } #endif /* CHECKSUM_CHECK_ICMP6 */ switch (icmp6hdr->type) { case ICMP6_TYPE_NA: /* Neighbor advertisement */ case ICMP6_TYPE_NS: /* Neighbor solicitation */ case ICMP6_TYPE_RA: /* Router advertisement */ case ICMP6_TYPE_RD: /* Redirect */ case ICMP6_TYPE_PTB: /* Packet too big */ nd6_input(p, inp); return; break; case ICMP6_TYPE_RS: #if LWIP_IPV6_FORWARD /* TODO implement router functionality */ #endif break; #if LWIP_IPV6_MLD case ICMP6_TYPE_MLQ: case ICMP6_TYPE_MLR: case ICMP6_TYPE_MLD: mld6_input(p, inp); return; break; #endif case ICMP6_TYPE_EREQ: #if !LWIP_MULTICAST_PING /* multicast destination address? */ if (ip6_addr_ismulticast(ip6_current_dest_addr())) { /* drop */ pbuf_free(p); ICMP6_STATS_INC(icmp6.drop); return; } #endif /* LWIP_MULTICAST_PING */ /* Allocate reply. */ r = pbuf_alloc(PBUF_IP, p->tot_len, PBUF_RAM); if (r == NULL) { /* drop */ pbuf_free(p); ICMP6_STATS_INC(icmp6.memerr); return; } /* Copy echo request. */ if (pbuf_copy(r, p) != ERR_OK) { /* drop */ pbuf_free(p); pbuf_free(r); ICMP6_STATS_INC(icmp6.err); return; } /* Determine reply source IPv6 address. */ #if LWIP_MULTICAST_PING if (ip6_addr_ismulticast(ip6_current_dest_addr())) { reply_src = ip6_select_source_address(inp, ip6_current_src_addr()); if (reply_src == NULL) { /* drop */ pbuf_free(p); pbuf_free(r); ICMP6_STATS_INC(icmp6.rterr); return; } } else #endif /* LWIP_MULTICAST_PING */ { reply_src = ip6_current_dest_addr(); } /* Set fields in reply. */ ((struct icmp6_echo_hdr *)(r->payload))->type = ICMP6_TYPE_EREP; ((struct icmp6_echo_hdr *)(r->payload))->chksum = 0; #if CHECKSUM_GEN_ICMP6 ((struct icmp6_echo_hdr *)(r->payload))->chksum = ip6_chksum_pseudo(r, IP6_NEXTH_ICMP6, r->tot_len, reply_src, ip6_current_src_addr()); #endif /* CHECKSUM_GEN_ICMP6 */ /* Send reply. */ ICMP6_STATS_INC(icmp6.xmit); ip6_output_if(r, reply_src, ip6_current_src_addr(), LWIP_ICMP6_HL, 0, IP6_NEXTH_ICMP6, inp); pbuf_free(r); break; default: ICMP6_STATS_INC(icmp6.proterr); ICMP6_STATS_INC(icmp6.drop); break; } pbuf_free(p); } /** * Send an icmpv6 'destination unreachable' packet. * * @param p the input packet for which the 'unreachable' should be sent, * p->payload pointing to the IPv6 header * @param c ICMPv6 code for the unreachable type */ void icmp6_dest_unreach(struct pbuf *p, enum icmp6_dur_code c) { icmp6_send_response(p, c, 0, ICMP6_TYPE_DUR); } /** * Send an icmpv6 'packet too big' packet. * * @param p the input packet for which the 'packet too big' should be sent, * p->payload pointing to the IPv6 header * @param mtu the maximum mtu that we can accept */ void icmp6_packet_too_big(struct pbuf *p, u32_t mtu) { icmp6_send_response(p, 0, mtu, ICMP6_TYPE_PTB); } /** * Send an icmpv6 'time exceeded' packet. * * @param p the input packet for which the 'unreachable' should be sent, * p->payload pointing to the IPv6 header * @param c ICMPv6 code for the time exceeded type */ void icmp6_time_exceeded(struct pbuf *p, enum icmp6_te_code c) { icmp6_send_response(p, c, 0, ICMP6_TYPE_TE); } /** * Send an icmpv6 'parameter problem' packet. * * @param p the input packet for which the 'param problem' should be sent, * p->payload pointing to the IP header * @param c ICMPv6 code for the param problem type * @param pointer the pointer to the byte where the parameter is found */ void icmp6_param_problem(struct pbuf *p, enum icmp6_pp_code c, u32_t pointer) { icmp6_send_response(p, c, pointer, ICMP6_TYPE_PP); } /** * Send an ICMPv6 packet in response to an incoming packet. * * @param p the input packet for which the response should be sent, * p->payload pointing to the IPv6 header * @param code Code of the ICMPv6 header * @param data Additional 32-bit parameter in the ICMPv6 header * @param type Type of the ICMPv6 header */ static void icmp6_send_response(struct pbuf *p, u8_t code, u32_t data, u8_t type) { struct pbuf *q; struct icmp6_hdr *icmp6hdr; ip6_addr_t *reply_src, *reply_dest; ip6_addr_t reply_src_local, reply_dest_local; struct ip6_hdr *ip6hdr; struct netif *netif; /* ICMPv6 header + IPv6 header + data */ q = pbuf_alloc(PBUF_IP, sizeof(struct icmp6_hdr) + IP6_HLEN + LWIP_ICMP6_DATASIZE, PBUF_RAM); if (q == NULL) { LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded: failed to allocate pbuf for ICMPv6 packet.\n")); ICMP6_STATS_INC(icmp6.memerr); return; } LWIP_ASSERT("check that first pbuf can hold icmp 6message", (q->len >= (sizeof(struct icmp6_hdr) + IP6_HLEN + LWIP_ICMP6_DATASIZE))); icmp6hdr = (struct icmp6_hdr *)q->payload; icmp6hdr->type = type; icmp6hdr->code = code; icmp6hdr->data = data; /* copy fields from original packet */ SMEMCPY((u8_t *)q->payload + sizeof(struct icmp6_hdr), (u8_t *)p->payload, IP6_HLEN + LWIP_ICMP6_DATASIZE); /* Get the destination address and netif for this ICMP message. */ if ((ip_current_netif() == NULL) || ((code == ICMP6_TE_FRAG) && (type == ICMP6_TYPE_TE))) { /* Special case, as ip6_current_xxx is either NULL, or points * to a different packet than the one that expired. * We must use the addresses that are stored in the expired packet. */ ip6hdr = (struct ip6_hdr *)p->payload; /* copy from packed address to aligned address */ ip6_addr_copy(reply_dest_local, ip6hdr->src); ip6_addr_copy(reply_src_local, ip6hdr->dest); reply_dest = &reply_dest_local; reply_src = &reply_src_local; netif = ip6_route(reply_src, reply_dest); if (netif == NULL) { /* drop */ pbuf_free(q); ICMP6_STATS_INC(icmp6.rterr); return; } } else { netif = ip_current_netif(); reply_dest = ip6_current_src_addr(); /* Select an address to use as source. */ reply_src = ip6_select_source_address(netif, reply_dest); if (reply_src == NULL) { /* drop */ pbuf_free(q); ICMP6_STATS_INC(icmp6.rterr); return; } } /* calculate checksum */ icmp6hdr->chksum = 0; #if CHECKSUM_GEN_ICMP6 icmp6hdr->chksum = ip6_chksum_pseudo(q, IP6_NEXTH_ICMP6, q->tot_len, reply_src, reply_dest); #endif /* CHECKSUM_GEN_ICMP6 */ ICMP6_STATS_INC(icmp6.xmit); ip6_output_if(q, reply_src, reply_dest, LWIP_ICMP6_HL, 0, IP6_NEXTH_ICMP6, netif); pbuf_free(q); } #endif /* LWIP_ICMP6 && LWIP_IPV6 */ ocproxy-1.60/lwip/src/core/ipv6/inet6.c000066400000000000000000000036611303453231400177160ustar00rootroot00000000000000/** * @file * * INET v6 addresses. */ /* * Copyright (c) 2010 Inico Technologies Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Ivan Delamer * * * Please coordinate changes and requests with Ivan Delamer * */ #include "lwip/opt.h" #if LWIP_IPV6 && LWIP_SOCKET /* don't build if not configured for use in lwipopts.h */ #include "lwip/def.h" #include "lwip/inet6.h" /** @see ip6_addr.c for implementation of functions. */ #endif /* LWIP_IPV6 */ ocproxy-1.60/lwip/src/core/ipv6/ip6.c000066400000000000000000001071051303453231400173650ustar00rootroot00000000000000/** * @file * * IPv6 layer. */ /* * Copyright (c) 2010 Inico Technologies Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Ivan Delamer * * * Please coordinate changes and requests with Ivan Delamer * */ #include "lwip/opt.h" #if LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */ #include "lwip/def.h" #include "lwip/mem.h" #include "lwip/netif.h" #include "lwip/ip6.h" #include "lwip/ip6_addr.h" #include "lwip/ip6_frag.h" #include "lwip/icmp6.h" #include "lwip/raw.h" #include "lwip/udp.h" #include "lwip/tcp_impl.h" #include "lwip/dhcp6.h" #include "lwip/nd6.h" #include "lwip/mld6.h" #include "lwip/debug.h" #include "lwip/stats.h" /** * Finds the appropriate network interface for a given IPv6 address. It tries to select * a netif following a sequence of heuristics: * 1) if there is only 1 netif, return it * 2) if the destination is a link-local address, try to match the src address to a netif. * this is a tricky case because with multiple netifs, link-local addresses only have * meaning within a particular subnet/link. * 3) tries to match the destination subnet to a configured address * 4) tries to find a router * 5) tries to match the source address to the netif * 6) returns the default netif, if configured * * @param src the source IPv6 address, if known * @param dest the destination IPv6 address for which to find the route * @return the netif on which to send to reach dest */ struct netif * ip6_route(struct ip6_addr *src, struct ip6_addr *dest) { struct netif *netif; s8_t i; /* If single netif configuration, fast return. */ if ((netif_list != NULL) && (netif_list->next == NULL)) { return netif_list; } /* Special processing for link-local addresses. */ if (ip6_addr_islinklocal(dest)) { if (ip6_addr_isany(src)) { /* Use default netif. */ return netif_default; } /* Try to find the netif for the source address. */ for(netif = netif_list; netif != NULL; netif = netif->next) { for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i)) && ip6_addr_cmp(src, netif_ip6_addr(netif, i))) { return netif; } } } /* netif not found, use default netif */ return netif_default; } /* See if the destination subnet matches a configured address. */ for(netif = netif_list; netif != NULL; netif = netif->next) { for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i)) && ip6_addr_netcmp(dest, netif_ip6_addr(netif, i))) { return netif; } } } /* Get the netif for a suitable router. */ i = nd6_select_router(dest, NULL); if (i >= 0) { if (default_router_list[i].neighbor_entry != NULL) { if (default_router_list[i].neighbor_entry->netif != NULL) { return default_router_list[i].neighbor_entry->netif; } } } /* try with the netif that matches the source address. */ if (!ip6_addr_isany(src)) { for(netif = netif_list; netif != NULL; netif = netif->next) { for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i)) && ip6_addr_cmp(src, netif_ip6_addr(netif, i))) { return netif; } } } } /* no matching netif found, use default netif */ return netif_default; } /** * Select the best IPv6 source address for a given destination * IPv6 address. Loosely follows RFC 3484. "Strong host" behavior * is assumed. * * @param netif the netif on which to send a packet * @param dest the destination we are trying to reach * @return the most suitable source address to use, or NULL if no suitable * source address is found */ ip6_addr_t * ip6_select_source_address(struct netif *netif, ip6_addr_t * dest) { ip6_addr_t * src = NULL; u8_t i; /* If dest is link-local, choose a link-local source. */ if (ip6_addr_islinklocal(dest) || ip6_addr_ismulticast_linklocal(dest) || ip6_addr_ismulticast_iflocal(dest)) { for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i)) && ip6_addr_islinklocal(netif_ip6_addr(netif, i))) { return netif_ip6_addr(netif, i); } } } /* Choose a site-local with matching prefix. */ if (ip6_addr_issitelocal(dest) || ip6_addr_ismulticast_sitelocal(dest)) { for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i)) && ip6_addr_issitelocal(netif_ip6_addr(netif, i)) && ip6_addr_netcmp(dest, netif_ip6_addr(netif, i))) { return netif_ip6_addr(netif, i); } } } /* Choose a unique-local with matching prefix. */ if (ip6_addr_isuniquelocal(dest) || ip6_addr_ismulticast_orglocal(dest)) { for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i)) && ip6_addr_isuniquelocal(netif_ip6_addr(netif, i)) && ip6_addr_netcmp(dest, netif_ip6_addr(netif, i))) { return netif_ip6_addr(netif, i); } } } /* Choose a global with best matching prefix. */ if (ip6_addr_isglobal(dest) || ip6_addr_ismulticast_global(dest)) { for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i)) && ip6_addr_isglobal(netif_ip6_addr(netif, i))) { if (src == NULL) { src = netif_ip6_addr(netif, i); } else { /* Replace src only if we find a prefix match. */ /* TODO find longest matching prefix. */ if ((!(ip6_addr_netcmp(src, dest))) && ip6_addr_netcmp(netif_ip6_addr(netif, i), dest)) { src = netif_ip6_addr(netif, i); } } } } if (src != NULL) { return src; } } /* Last resort: see if arbitrary prefix matches. */ for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i)) && ip6_addr_netcmp(dest, netif_ip6_addr(netif, i))) { return netif_ip6_addr(netif, i); } } return NULL; } #if LWIP_IPV6_FORWARD /** * Forwards an IPv6 packet. It finds an appropriate route for the * packet, decrements the HL value of the packet, and outputs * the packet on the appropriate interface. * * @param p the packet to forward (p->payload points to IP header) * @param iphdr the IPv6 header of the input packet * @param inp the netif on which this packet was received */ static void ip6_forward(struct pbuf *p, struct ip6_hdr *iphdr, struct netif *inp) { struct netif *netif; /* do not forward link-local addresses */ if (ip6_addr_islinklocal(ip6_current_dest_addr())) { LWIP_DEBUGF(IP6_DEBUG, ("ip6_forward: not forwarding link-local address.\n")); IP6_STATS_INC(ip6.rterr); IP6_STATS_INC(ip6.drop); return; } /* Find network interface where to forward this IP packet to. */ netif = ip6_route(IP6_ADDR_ANY, ip6_current_dest_addr()); if (netif == NULL) { LWIP_DEBUGF(IP6_DEBUG, ("ip6_forward: no route for %"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F"\n", IP6_ADDR_BLOCK1(ip6_current_dest_addr()), IP6_ADDR_BLOCK2(ip6_current_dest_addr()), IP6_ADDR_BLOCK3(ip6_current_dest_addr()), IP6_ADDR_BLOCK4(ip6_current_dest_addr()), IP6_ADDR_BLOCK5(ip6_current_dest_addr()), IP6_ADDR_BLOCK6(ip6_current_dest_addr()), IP6_ADDR_BLOCK7(ip6_current_dest_addr()), IP6_ADDR_BLOCK8(ip6_current_dest_addr()))); #if LWIP_ICMP6 /* Don't send ICMP messages in response to ICMP messages */ if (IP6H_NEXTH(iphdr) != IP6_NEXTH_ICMP6) { icmp6_dest_unreach(p, ICMP6_DUR_NO_ROUTE); } #endif /* LWIP_ICMP6 */ IP6_STATS_INC(ip6.rterr); IP6_STATS_INC(ip6.drop); return; } /* Do not forward packets onto the same network interface on which * they arrived. */ if (netif == inp) { LWIP_DEBUGF(IP6_DEBUG, ("ip6_forward: not bouncing packets back on incoming interface.\n")); IP6_STATS_INC(ip6.rterr); IP6_STATS_INC(ip6.drop); return; } /* decrement HL */ IP6H_HOPLIM_SET(iphdr, IP6H_HOPLIM(iphdr) - 1); /* send ICMP6 if HL == 0 */ if (IP6H_HOPLIM(iphdr) == 0) { #if LWIP_ICMP6 /* Don't send ICMP messages in response to ICMP messages */ if (IP6H_NEXTH(iphdr) != IP6_NEXTH_ICMP6) { icmp6_time_exceeded(p, ICMP6_TE_HL); } #endif /* LWIP_ICMP6 */ IP6_STATS_INC(ip6.drop); return; } if (netif->mtu && (p->tot_len > netif->mtu)) { #if LWIP_ICMP6 /* Don't send ICMP messages in response to ICMP messages */ if (IP6H_NEXTH(iphdr) != IP6_NEXTH_ICMP6) { icmp6_packet_too_big(p, netif->mtu); } #endif /* LWIP_ICMP6 */ IP6_STATS_INC(ip6.drop); return; } LWIP_DEBUGF(IP6_DEBUG, ("ip6_forward: forwarding packet to %"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F"\n", IP6_ADDR_BLOCK1(ip6_current_dest_addr()), IP6_ADDR_BLOCK2(ip6_current_dest_addr()), IP6_ADDR_BLOCK3(ip6_current_dest_addr()), IP6_ADDR_BLOCK4(ip6_current_dest_addr()), IP6_ADDR_BLOCK5(ip6_current_dest_addr()), IP6_ADDR_BLOCK6(ip6_current_dest_addr()), IP6_ADDR_BLOCK7(ip6_current_dest_addr()), IP6_ADDR_BLOCK8(ip6_current_dest_addr()))); /* transmit pbuf on chosen interface */ netif->output_ip6(netif, p, ip6_current_dest_addr()); IP6_STATS_INC(ip6.fw); IP6_STATS_INC(ip6.xmit); return; } #endif /* LWIP_IPV6_FORWARD */ /** * This function is called by the network interface device driver when * an IPv6 packet is received. The function does the basic checks of the * IP header such as packet size being at least larger than the header * size etc. If the packet was not destined for us, the packet is * forwarded (using ip6_forward). * * Finally, the packet is sent to the upper layer protocol input function. * * @param p the received IPv6 packet (p->payload points to IPv6 header) * @param inp the netif on which this packet was received * @return ERR_OK if the packet was processed (could return ERR_* if it wasn't * processed, but currently always returns ERR_OK) */ err_t ip6_input(struct pbuf *p, struct netif *inp) { struct ip6_hdr *ip6hdr; struct netif *netif; u8_t nexth; u16_t hlen; /* the current header length */ u8_t i; #if 0 /*IP_ACCEPT_LINK_LAYER_ADDRESSING*/ @todo int check_ip_src=1; #endif /* IP_ACCEPT_LINK_LAYER_ADDRESSING */ IP6_STATS_INC(ip6.recv); /* identify the IP header */ ip6hdr = (struct ip6_hdr *)p->payload; if (IP6H_V(ip6hdr) != 6) { LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_LEVEL_WARNING, ("IPv6 packet dropped due to bad version number %"U32_F"\n", IP6H_V(ip6hdr))); pbuf_free(p); IP6_STATS_INC(ip6.err); IP6_STATS_INC(ip6.drop); return ERR_OK; } /* header length exceeds first pbuf length, or ip length exceeds total pbuf length? */ if ((IP6_HLEN > p->len) || ((IP6H_PLEN(ip6hdr) + IP6_HLEN) > p->tot_len)) { if (IP6_HLEN > p->len) { LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("IPv6 header (len %"U16_F") does not fit in first pbuf (len %"U16_F"), IP packet dropped.\n", IP6_HLEN, p->len)); } if ((IP6H_PLEN(ip6hdr) + IP6_HLEN) > p->tot_len) { LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("IPv6 (plen %"U16_F") is longer than pbuf (len %"U16_F"), IP packet dropped.\n", IP6H_PLEN(ip6hdr) + IP6_HLEN, p->tot_len)); } /* free (drop) packet pbufs */ pbuf_free(p); IP6_STATS_INC(ip6.lenerr); IP6_STATS_INC(ip6.drop); return ERR_OK; } /* Trim pbuf. This should have been done at the netif layer, * but we'll do it anyway just to be sure that its done. */ pbuf_realloc(p, IP6_HLEN + IP6H_PLEN(ip6hdr)); /* copy IP addresses to aligned ip6_addr_t */ ip6_addr_copy(ip_data.current_iphdr_dest.ip6, ip6hdr->dest); ip6_addr_copy(ip_data.current_iphdr_src.ip6, ip6hdr->src); /* current header pointer. */ ip_data.current_ip6_header = ip6hdr; /* In netif, used in case we need to send ICMPv6 packets back. */ ip_data.current_netif = inp; /* match packet against an interface, i.e. is this packet for us? */ if (ip6_addr_ismulticast(ip6_current_dest_addr())) { /* Always joined to multicast if-local and link-local all-nodes group. */ if (ip6_addr_isallnodes_iflocal(ip6_current_dest_addr()) || ip6_addr_isallnodes_linklocal(ip6_current_dest_addr())) { netif = inp; } #if LWIP_IPV6_MLD else if (mld6_lookfor_group(inp, ip6_current_dest_addr())) { netif = inp; } #else /* LWIP_IPV6_MLD */ else if (ip6_addr_issolicitednode(ip6_current_dest_addr())) { /* Filter solicited node packets when MLD is not enabled * (for Neighbor discovery). */ netif = NULL; for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { if (ip6_addr_isvalid(netif_ip6_addr_state(inp, i)) && ip6_addr_cmp_solicitednode(ip6_current_dest_addr(), netif_ip6_addr(inp, i))) { netif = inp; LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: solicited node packet accepted on interface %c%c\n", netif->name[0], netif->name[1])); break; } } } #endif /* LWIP_IPV6_MLD */ else { netif = NULL; } } else { /* start trying with inp. if that's not acceptable, start walking the list of configured netifs. 'first' is used as a boolean to mark whether we started walking the list */ int first = 1; netif = inp; do { /* interface is up? */ if (netif_is_up(netif)) { /* unicast to this interface address? address configured? */ for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i)) && ip6_addr_cmp(ip6_current_dest_addr(), netif_ip6_addr(netif, i))) { /* exit outer loop */ goto netif_found; } } } if (ip6_addr_islinklocal(ip6_current_dest_addr())) { /* Do not match link-local addresses to other netifs. */ netif = NULL; break; } if (first) { first = 0; netif = netif_list; } else { netif = netif->next; } if (netif == inp) { netif = netif->next; } } while(netif != NULL); netif_found: LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: packet accepted on interface %c%c\n", netif ? netif->name[0] : 'X', netif? netif->name[1] : 'X')); } /* "::" packet source address? (used in duplicate address detection) */ if (ip6_addr_isany(ip6_current_src_addr()) && (!ip6_addr_issolicitednode(ip6_current_dest_addr()))) { /* packet source is not valid */ /* free (drop) packet pbufs */ LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: packet with src ANY_ADDRESS dropped\n")); pbuf_free(p); IP6_STATS_INC(ip6.drop); goto ip6_input_cleanup; } /* packet not for us? */ if (netif == NULL) { /* packet not for us, route or discard */ LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_TRACE, ("ip6_input: packet not for us.\n")); #if LWIP_IPV6_FORWARD /* non-multicast packet? */ if (!ip6_addr_ismulticast(ip6_current_dest_addr())) { /* try to forward IP packet on (other) interfaces */ ip6_forward(p, ip6hdr, inp); } #endif /* LWIP_IPV6_FORWARD */ pbuf_free(p); goto ip6_input_cleanup; } /* current netif pointer. */ ip_data.current_netif = netif; /* Save next header type. */ nexth = IP6H_NEXTH(ip6hdr); /* Init header length. */ hlen = ip_data.current_ip_header_tot_len = IP6_HLEN; /* Move to payload. */ pbuf_header(p, -IP6_HLEN); /* Process known option extension headers, if present. */ while (nexth != IP6_NEXTH_NONE) { switch (nexth) { case IP6_NEXTH_HOPBYHOP: LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: packet with Hop-by-Hop options header\n")); /* Get next header type. */ nexth = *((u8_t *)p->payload); /* Get the header length. */ hlen = 8 * (1 + *((u8_t *)p->payload + 1)); ip_data.current_ip_header_tot_len += hlen; /* Skip over this header. */ if (hlen > p->len) { LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("IPv6 options header (hlen %"U16_F") does not fit in first pbuf (len %"U16_F"), IPv6 packet dropped.\n", hlen, p->len)); /* free (drop) packet pbufs */ pbuf_free(p); IP6_STATS_INC(ip6.lenerr); IP6_STATS_INC(ip6.drop); goto ip6_input_cleanup; } pbuf_header(p, -hlen); break; case IP6_NEXTH_DESTOPTS: LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: packet with Destination options header\n")); /* Get next header type. */ nexth = *((u8_t *)p->payload); /* Get the header length. */ hlen = 8 * (1 + *((u8_t *)p->payload + 1)); ip_data.current_ip_header_tot_len += hlen; /* Skip over this header. */ if (hlen > p->len) { LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("IPv6 options header (hlen %"U16_F") does not fit in first pbuf (len %"U16_F"), IPv6 packet dropped.\n", hlen, p->len)); /* free (drop) packet pbufs */ pbuf_free(p); IP6_STATS_INC(ip6.lenerr); IP6_STATS_INC(ip6.drop); goto ip6_input_cleanup; } pbuf_header(p, -hlen); break; case IP6_NEXTH_ROUTING: LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: packet with Routing header\n")); /* Get next header type. */ nexth = *((u8_t *)p->payload); /* Get the header length. */ hlen = 8 * (1 + *((u8_t *)p->payload + 1)); ip_data.current_ip_header_tot_len += hlen; /* Skip over this header. */ if (hlen > p->len) { LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("IPv6 options header (hlen %"U16_F") does not fit in first pbuf (len %"U16_F"), IPv6 packet dropped.\n", hlen, p->len)); /* free (drop) packet pbufs */ pbuf_free(p); IP6_STATS_INC(ip6.lenerr); IP6_STATS_INC(ip6.drop); goto ip6_input_cleanup; } pbuf_header(p, -hlen); break; case IP6_NEXTH_FRAGMENT: { struct ip6_frag_hdr * frag_hdr; LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: packet with Fragment header\n")); frag_hdr = (struct ip6_frag_hdr *)p->payload; /* Get next header type. */ nexth = frag_hdr->_nexth; /* Fragment Header length. */ hlen = 8; ip_data.current_ip_header_tot_len += hlen; /* Make sure this header fits in current pbuf. */ if (hlen > p->len) { LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("IPv6 options header (hlen %"U16_F") does not fit in first pbuf (len %"U16_F"), IPv6 packet dropped.\n", hlen, p->len)); /* free (drop) packet pbufs */ pbuf_free(p); IP6_FRAG_STATS_INC(ip6_frag.lenerr); IP6_FRAG_STATS_INC(ip6_frag.drop); goto ip6_input_cleanup; } /* Offset == 0 and more_fragments == 0? */ if (((frag_hdr->_fragment_offset & IP6_FRAG_OFFSET_MASK) == 0) && ((frag_hdr->_fragment_offset & IP6_FRAG_MORE_FLAG) == 0)) { /* This is a 1-fragment packet, usually a packet that we have * already reassembled. Skip this header anc continue. */ pbuf_header(p, -hlen); } else { #if LWIP_IPV6_REASS /* reassemble the packet */ p = ip6_reass(p); /* packet not fully reassembled yet? */ if (p == NULL) { goto ip6_input_cleanup; } /* Returned p point to IPv6 header. * Update all our variables and pointers and continue. */ ip6hdr = (struct ip6_hdr *)p->payload; nexth = IP6H_NEXTH(ip6hdr); hlen = ip_data.current_ip_header_tot_len = IP6_HLEN; pbuf_header(p, -IP6_HLEN); #else /* LWIP_IPV6_REASS */ /* free (drop) packet pbufs */ LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: packet with Fragment header dropped (with LWIP_IPV6_REASS==0)\n")); pbuf_free(p); IP6_STATS_INC(ip6.opterr); IP6_STATS_INC(ip6.drop); goto ip6_input_cleanup; #endif /* LWIP_IPV6_REASS */ } break; } default: goto options_done; break; } } options_done: /* p points to IPv6 header again. */ pbuf_header(p, ip_data.current_ip_header_tot_len); /* send to upper layers */ LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: \n")); ip6_debug_print(p); LWIP_DEBUGF(IP6_DEBUG, ("ip6_input: p->len %"U16_F" p->tot_len %"U16_F"\n", p->len, p->tot_len)); #if LWIP_RAW /* raw input did not eat the packet? */ if (raw_input(p, inp) == 0) #endif /* LWIP_RAW */ { switch (nexth) { case IP6_NEXTH_NONE: pbuf_free(p); break; #if LWIP_UDP case IP6_NEXTH_UDP: #if LWIP_UDPLITE case IP6_NEXTH_UDPLITE: #endif /* LWIP_UDPLITE */ /* Point to payload. */ pbuf_header(p, -ip_data.current_ip_header_tot_len); udp_input(p, inp); break; #endif /* LWIP_UDP */ #if LWIP_TCP case IP6_NEXTH_TCP: /* Point to payload. */ pbuf_header(p, -ip_data.current_ip_header_tot_len); tcp_input(p, inp); break; #endif /* LWIP_TCP */ #if LWIP_ICMP6 case IP6_NEXTH_ICMP6: /* Point to payload. */ pbuf_header(p, -ip_data.current_ip_header_tot_len); icmp6_input(p, inp); break; #endif /* LWIP_ICMP */ default: #if LWIP_ICMP6 /* send ICMP parameter problem unless it was a multicast or ICMPv6 */ if ((!ip6_addr_ismulticast(ip6_current_dest_addr())) && (IP6H_NEXTH(ip6hdr) != IP6_NEXTH_ICMP6)) { icmp6_param_problem(p, ICMP6_PP_HEADER, ip_data.current_ip_header_tot_len - hlen); } #endif /* LWIP_ICMP */ LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip6_input: Unsupported transport protocol %"U16_F"\n", IP6H_NEXTH(ip6hdr))); pbuf_free(p); IP6_STATS_INC(ip6.proterr); IP6_STATS_INC(ip6.drop); break; } } ip6_input_cleanup: ip_data.current_netif = NULL; ip_data.current_ip6_header = NULL; ip_data.current_ip_header_tot_len = 0; ip6_addr_set_any(&ip_data.current_iphdr_src.ip6); ip6_addr_set_any(&ip_data.current_iphdr_dest.ip6); return ERR_OK; } /** * Sends an IPv6 packet on a network interface. This function constructs * the IPv6 header. If the source IPv6 address is NULL, the IPv6 "ANY" address is * used as source (usually during network startup). If the source IPv6 address it * IP6_ADDR_ANY, the most appropriate IPv6 address of the outgoing network * interface is filled in as source address. If the destination IPv6 address is * IP_HDRINCL, p is assumed to already include an IPv6 header and p->payload points * to it instead of the data. * * @param p the packet to send (p->payload points to the data, e.g. next protocol header; if dest == IP_HDRINCL, p already includes an IPv6 header and p->payload points to that IPv6 header) * @param src the source IPv6 address to send from (if src == IP6_ADDR_ANY, an * IP address of the netif is selected and used as source address. * if src == NULL, IP6_ADDR_ANY is used as source) * @param dest the destination IPv6 address to send the packet to * @param hl the Hop Limit value to be set in the IPv6 header * @param tc the Traffic Class value to be set in the IPv6 header * @param nexth the Next Header to be set in the IPv6 header * @param netif the netif on which to send this packet * @return ERR_OK if the packet was sent OK * ERR_BUF if p doesn't have enough space for IPv6/LINK headers * returns errors returned by netif->output */ err_t ip6_output_if(struct pbuf *p, ip6_addr_t *src, ip6_addr_t *dest, u8_t hl, u8_t tc, u8_t nexth, struct netif *netif) { ip6_addr_t *src_used = src; if (dest != IP_HDRINCL) { if (src != NULL && ip6_addr_isany(src)) { src = ip6_select_source_address(netif, dest); if ((src == NULL) || ip6_addr_isany(src)) { /* No appropriate source address was found for this packet. */ LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip6_output: No suitable source address for packet.\n")); IP6_STATS_INC(ip6.rterr); return ERR_RTE; } } } return ip6_output_if_src(p, src_used, dest, hl, tc, nexth, netif); } /** * Same as ip6_output_if() but 'src' address is not replaced by netif address * when it is 'any'. */ err_t ip6_output_if_src(struct pbuf *p, ip6_addr_t *src, ip6_addr_t *dest, u8_t hl, u8_t tc, u8_t nexth, struct netif *netif) { struct ip6_hdr *ip6hdr; ip6_addr_t dest_addr; /* pbufs passed to IP must have a ref-count of 1 as their payload pointer gets altered as the packet is passed down the stack */ LWIP_ASSERT("p->ref == 1", p->ref == 1); /* Should the IPv6 header be generated or is it already included in p? */ if (dest != IP_HDRINCL) { /* generate IPv6 header */ if (pbuf_header(p, IP6_HLEN)) { LWIP_DEBUGF(IP6_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip6_output: not enough room for IPv6 header in pbuf\n")); IP6_STATS_INC(ip6.err); return ERR_BUF; } ip6hdr = (struct ip6_hdr *)p->payload; LWIP_ASSERT("check that first pbuf can hold struct ip6_hdr", (p->len >= sizeof(struct ip6_hdr))); IP6H_HOPLIM_SET(ip6hdr, hl); IP6H_NEXTH_SET(ip6hdr, nexth); /* dest cannot be NULL here */ ip6_addr_copy(ip6hdr->dest, *dest); IP6H_VTCFL_SET(ip6hdr, 6, tc, 0); IP6H_PLEN_SET(ip6hdr, p->tot_len - IP6_HLEN); if (src == NULL) { src = IP6_ADDR_ANY; } /* src cannot be NULL here */ ip6_addr_copy(ip6hdr->src, *src); } else { /* IP header already included in p */ ip6hdr = (struct ip6_hdr *)p->payload; ip6_addr_copy(dest_addr, ip6hdr->dest); dest = &dest_addr; } IP6_STATS_INC(ip6.xmit); LWIP_DEBUGF(IP6_DEBUG, ("ip6_output_if: %c%c%"U16_F"\n", netif->name[0], netif->name[1], netif->num)); ip6_debug_print(p); #if ENABLE_LOOPBACK { int i; for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i)) && ip6_addr_cmp(dest, netif_ip6_addr(netif, i))) { /* Packet to self, enqueue it for loopback */ LWIP_DEBUGF(IP6_DEBUG, ("netif_loop_output()\n")); return netif_loop_output(netif, p); } } } #endif /* ENABLE_LOOPBACK */ #if LWIP_IPV6_FRAG /* don't fragment if interface has mtu set to 0 [loopif] */ if (netif->mtu && (p->tot_len > nd6_get_destination_mtu(dest, netif))) { return ip6_frag(p, netif, dest); } #endif /* LWIP_IPV6_FRAG */ LWIP_DEBUGF(IP6_DEBUG, ("netif->output_ip6()\n")); return netif->output_ip6(netif, p, dest); } /** * Simple interface to ip6_output_if. It finds the outgoing network * interface and calls upon ip6_output_if to do the actual work. * * @param p the packet to send (p->payload points to the data, e.g. next protocol header; if dest == IP_HDRINCL, p already includes an IPv6 header and p->payload points to that IPv6 header) * @param src the source IPv6 address to send from (if src == IP6_ADDR_ANY, an * IP address of the netif is selected and used as source address. * if src == NULL, IP6_ADDR_ANY is used as source) * @param dest the destination IPv6 address to send the packet to * @param hl the Hop Limit value to be set in the IPv6 header * @param tc the Traffic Class value to be set in the IPv6 header * @param nexth the Next Header to be set in the IPv6 header * * @return ERR_RTE if no route is found * see ip_output_if() for more return values */ err_t ip6_output(struct pbuf *p, ip6_addr_t *src, ip6_addr_t *dest, u8_t hl, u8_t tc, u8_t nexth) { struct netif *netif; struct ip6_hdr *ip6hdr; ip6_addr_t src_addr, dest_addr; /* pbufs passed to IPv6 must have a ref-count of 1 as their payload pointer gets altered as the packet is passed down the stack */ LWIP_ASSERT("p->ref == 1", p->ref == 1); if (dest != IP_HDRINCL) { netif = ip6_route(src, dest); } else { /* IP header included in p, read addresses. */ ip6hdr = (struct ip6_hdr *)p->payload; ip6_addr_copy(src_addr, ip6hdr->src); ip6_addr_copy(dest_addr, ip6hdr->dest); netif = ip6_route(&src_addr, &dest_addr); } if (netif == NULL) { LWIP_DEBUGF(IP6_DEBUG, ("ip6_output: no route for %"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F"\n", IP6_ADDR_BLOCK1(dest), IP6_ADDR_BLOCK2(dest), IP6_ADDR_BLOCK3(dest), IP6_ADDR_BLOCK4(dest), IP6_ADDR_BLOCK5(dest), IP6_ADDR_BLOCK6(dest), IP6_ADDR_BLOCK7(dest), IP6_ADDR_BLOCK8(dest))); IP6_STATS_INC(ip6.rterr); return ERR_RTE; } return ip6_output_if(p, src, dest, hl, tc, nexth, netif); } #if LWIP_NETIF_HWADDRHINT /** Like ip6_output, but takes and addr_hint pointer that is passed on to netif->addr_hint * before calling ip6_output_if. * * @param p the packet to send (p->payload points to the data, e.g. next protocol header; if dest == IP_HDRINCL, p already includes an IPv6 header and p->payload points to that IPv6 header) * @param src the source IPv6 address to send from (if src == IP6_ADDR_ANY, an * IP address of the netif is selected and used as source address. * if src == NULL, IP6_ADDR_ANY is used as source) * @param dest the destination IPv6 address to send the packet to * @param hl the Hop Limit value to be set in the IPv6 header * @param tc the Traffic Class value to be set in the IPv6 header * @param nexth the Next Header to be set in the IPv6 header * @param addr_hint address hint pointer set to netif->addr_hint before * calling ip_output_if() * * @return ERR_RTE if no route is found * see ip_output_if() for more return values */ err_t ip6_output_hinted(struct pbuf *p, ip6_addr_t *src, ip6_addr_t *dest, u8_t hl, u8_t tc, u8_t nexth, u8_t *addr_hint) { struct netif *netif; struct ip6_hdr *ip6hdr; ip6_addr_t src_addr, dest_addr; err_t err; /* pbufs passed to IP must have a ref-count of 1 as their payload pointer gets altered as the packet is passed down the stack */ LWIP_ASSERT("p->ref == 1", p->ref == 1); if (dest != IP_HDRINCL) { netif = ip6_route(src, dest); } else { /* IP header included in p, read addresses. */ ip6hdr = (struct ip6_hdr *)p->payload; ip6_addr_copy(src_addr, ip6hdr->src); ip6_addr_copy(dest_addr, ip6hdr->dest); netif = ip6_route(&src_addr, &dest_addr); } if (netif == NULL) { LWIP_DEBUGF(IP6_DEBUG, ("ip6_output: no route for %"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F"\n", IP6_ADDR_BLOCK1(dest), IP6_ADDR_BLOCK2(dest), IP6_ADDR_BLOCK3(dest), IP6_ADDR_BLOCK4(dest), IP6_ADDR_BLOCK5(dest), IP6_ADDR_BLOCK6(dest), IP6_ADDR_BLOCK7(dest), IP6_ADDR_BLOCK8(dest))); IP6_STATS_INC(ip6.rterr); return ERR_RTE; } NETIF_SET_HWADDRHINT(netif, addr_hint); err = ip6_output_if(p, src, dest, hl, tc, nexth, netif); NETIF_SET_HWADDRHINT(netif, NULL); return err; } #endif /* LWIP_NETIF_HWADDRHINT*/ #if LWIP_IPV6_MLD /** * Add a hop-by-hop options header with a router alert option and padding. * * Used by MLD when sending a Multicast listener report/done message. * * @param p the packet to which we will prepend the options header * @param nexth the next header protocol number (e.g. IP6_NEXTH_ICMP6) * @param value the value of the router alert option data (e.g. IP6_ROUTER_ALERT_VALUE_MLD) * @return ERR_OK if hop-by-hop header was added, ERR_* otherwise */ err_t ip6_options_add_hbh_ra(struct pbuf * p, u8_t nexth, u8_t value) { struct ip6_hbh_hdr * hbh_hdr; /* Move pointer to make room for hop-by-hop options header. */ if (pbuf_header(p, sizeof(struct ip6_hbh_hdr))) { LWIP_DEBUGF(IP6_DEBUG, ("ip6_options: no space for options header\n")); IP6_STATS_INC(ip6.err); return ERR_BUF; } hbh_hdr = (struct ip6_hbh_hdr *)p->payload; /* Set fields. */ hbh_hdr->_nexth = nexth; hbh_hdr->_hlen = 0; hbh_hdr->_ra_opt_type = IP6_ROUTER_ALERT_OPTION; hbh_hdr->_ra_opt_dlen = 2; hbh_hdr->_ra_opt_data = value; hbh_hdr->_padn_opt_type = IP6_PADN_ALERT_OPTION; hbh_hdr->_padn_opt_dlen = 0; return ERR_OK; } #endif /* LWIP_IPV6_MLD */ #if IP6_DEBUG /* Print an IPv6 header by using LWIP_DEBUGF * @param p an IPv6 packet, p->payload pointing to the IPv6 header */ void ip6_debug_print(struct pbuf *p) { struct ip6_hdr *ip6hdr = (struct ip6_hdr *)p->payload; LWIP_DEBUGF(IP6_DEBUG, ("IPv6 header:\n")); LWIP_DEBUGF(IP6_DEBUG, ("+-------------------------------+\n")); LWIP_DEBUGF(IP6_DEBUG, ("| %2"U16_F" | %3"U16_F" | %7"U32_F" | (ver, class, flow)\n", IP6H_V(ip6hdr), IP6H_TC(ip6hdr), IP6H_FL(ip6hdr))); LWIP_DEBUGF(IP6_DEBUG, ("+-------------------------------+\n")); LWIP_DEBUGF(IP6_DEBUG, ("| %5"U16_F" | %3"U16_F" | %3"U16_F" | (plen, nexth, hopl)\n", IP6H_PLEN(ip6hdr), IP6H_NEXTH(ip6hdr), IP6H_HOPLIM(ip6hdr))); LWIP_DEBUGF(IP6_DEBUG, ("+-------------------------------+\n")); LWIP_DEBUGF(IP6_DEBUG, ("| %4"X32_F" | %4"X32_F" | %4"X32_F" | %4"X32_F" | (src)\n", IP6_ADDR_BLOCK1(&(ip6hdr->src)), IP6_ADDR_BLOCK2(&(ip6hdr->src)), IP6_ADDR_BLOCK3(&(ip6hdr->src)), IP6_ADDR_BLOCK4(&(ip6hdr->src)))); LWIP_DEBUGF(IP6_DEBUG, ("| %4"X32_F" | %4"X32_F" | %4"X32_F" | %4"X32_F" |\n", IP6_ADDR_BLOCK5(&(ip6hdr->src)), IP6_ADDR_BLOCK6(&(ip6hdr->src)), IP6_ADDR_BLOCK7(&(ip6hdr->src)), IP6_ADDR_BLOCK8(&(ip6hdr->src)))); LWIP_DEBUGF(IP6_DEBUG, ("+-------------------------------+\n")); LWIP_DEBUGF(IP6_DEBUG, ("| %4"X32_F" | %4"X32_F" | %4"X32_F" | %4"X32_F" | (dest)\n", IP6_ADDR_BLOCK1(&(ip6hdr->dest)), IP6_ADDR_BLOCK2(&(ip6hdr->dest)), IP6_ADDR_BLOCK3(&(ip6hdr->dest)), IP6_ADDR_BLOCK4(&(ip6hdr->dest)))); LWIP_DEBUGF(IP6_DEBUG, ("| %4"X32_F" | %4"X32_F" | %4"X32_F" | %4"X32_F" |\n", IP6_ADDR_BLOCK5(&(ip6hdr->dest)), IP6_ADDR_BLOCK6(&(ip6hdr->dest)), IP6_ADDR_BLOCK7(&(ip6hdr->dest)), IP6_ADDR_BLOCK8(&(ip6hdr->dest)))); LWIP_DEBUGF(IP6_DEBUG, ("+-------------------------------+\n")); } #endif /* IP6_DEBUG */ #endif /* LWIP_IPV6 */ ocproxy-1.60/lwip/src/core/ipv6/ip6_addr.c000066400000000000000000000164611303453231400203630ustar00rootroot00000000000000/** * @file * * IPv6 addresses. */ /* * Copyright (c) 2010 Inico Technologies Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Ivan Delamer * * Functions for handling IPv6 addresses. * * Please coordinate changes and requests with Ivan Delamer * */ #include "lwip/opt.h" #if LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */ #include "lwip/ip6_addr.h" #include "lwip/def.h" /* used by IP6_ADDR_ANY in ip6_addr.h */ const ip6_addr_t ip6_addr_any = { { 0ul, 0ul, 0ul, 0ul } }; #ifndef isprint #define in_range(c, lo, up) ((u8_t)c >= lo && (u8_t)c <= up) #define isprint(c) in_range(c, 0x20, 0x7f) #define isdigit(c) in_range(c, '0', '9') #define isxdigit(c) (isdigit(c) || in_range(c, 'a', 'f') || in_range(c, 'A', 'F')) #define islower(c) in_range(c, 'a', 'z') #define isspace(c) (c == ' ' || c == '\f' || c == '\n' || c == '\r' || c == '\t' || c == '\v') #define xchar(i) ((i) < 10 ? '0' + (i) : 'A' + (i) - 10) #endif /** * Check whether "cp" is a valid ascii representation * of an IPv6 address and convert to a binary address. * Returns 1 if the address is valid, 0 if not. * * @param cp IPv6 address in ascii represenation (e.g. "FF01::1") * @param addr pointer to which to save the ip address in network order * @return 1 if cp could be converted to addr, 0 on failure */ int ip6addr_aton(const char *cp, ip6_addr_t *addr) { u32_t addr_index, zero_blocks, current_block_index, current_block_value; const char * s; /* Count the number of colons, to count the number of blocks in a "::" sequence zero_blocks may be 1 even if there are no :: sequences */ zero_blocks = 8; for (s = cp; *s != 0; s++) { if (*s == ':') zero_blocks--; else if (!isxdigit(*s)) break; } /* parse each block */ addr_index = 0; current_block_index = 0; current_block_value = 0; for (s = cp; *s != 0; s++) { if (*s == ':') { if (addr) { if (current_block_index & 0x1) { addr->addr[addr_index++] |= current_block_value; } else { addr->addr[addr_index] = current_block_value << 16; } } current_block_index++; current_block_value = 0; if (current_block_index > 7) { /* address too long! */ return 0; } if (s[1] == ':') { s++; /* "::" found, set zeros */ while (zero_blocks-- > 0) { if (current_block_index & 0x1) { addr_index++; } else { if (addr) { addr->addr[addr_index] = 0; } } current_block_index++; } } } else if (isxdigit(*s)) { /* add current digit */ current_block_value = (current_block_value << 4) + (isdigit(*s) ? *s - '0' : 10 + (islower(*s) ? *s - 'a' : *s - 'A')); } else { /* unexpected digit, space? CRLF? */ break; } } if (addr) { if (current_block_index & 0x1) { addr->addr[addr_index++] |= current_block_value; } else { addr->addr[addr_index] = current_block_value << 16; } } /* convert to network byte order. */ if (addr) { for (addr_index = 0; addr_index < 4; addr_index++) { addr->addr[addr_index] = htonl(addr->addr[addr_index]); } } if (current_block_index != 7) { return 0; } return 1; } /** * Convert numeric IPv6 address into ASCII representation. * returns ptr to static buffer; not reentrant! * * @param addr ip6 address in network order to convert * @return pointer to a global static (!) buffer that holds the ASCII * represenation of addr */ char * ip6addr_ntoa(const ip6_addr_t *addr) { static char str[40]; return ip6addr_ntoa_r(addr, str, 40); } /** * Same as ipaddr_ntoa, but reentrant since a user-supplied buffer is used. * * @param addr ip6 address in network order to convert * @param buf target buffer where the string is stored * @param buflen length of buf * @return either pointer to buf which now holds the ASCII * representation of addr or NULL if buf was too small */ char * ip6addr_ntoa_r(const ip6_addr_t *addr, char *buf, int buflen) { u32_t current_block_index, current_block_value; s32_t zero_flag, i; i = 0; zero_flag = 0; /* used to indicate a zero chain for "::' */ for (current_block_index = 0; current_block_index < 8; current_block_index++) { /* get the current 16-bit block */ current_block_value = htonl(addr->addr[current_block_index >> 1]); if ((current_block_index & 0x1) == 0) { current_block_value = current_block_value >> 16; } current_block_value &= 0xffff; if (current_block_value == 0) { /* generate empty block "::" */ if (!zero_flag) { if (current_block_index > 0) { zero_flag = 1; buf[i++] = ':'; if (i >= buflen) return NULL; } } } else { if (current_block_index > 0) { buf[i++] = ':'; if (i >= buflen) return NULL; } if ((current_block_value & 0xf000) == 0) { zero_flag = 1; } else { buf[i++] = xchar(((current_block_value & 0xf000) >> 12)); zero_flag = 0; if (i >= buflen) return NULL; } if (((current_block_value & 0xf00) == 0) && (zero_flag)) { /* do nothing */ } else { buf[i++] = xchar(((current_block_value & 0xf00) >> 8)); zero_flag = 0; if (i >= buflen) return NULL; } if (((current_block_value & 0xf0) == 0) && (zero_flag)) { /* do nothing */ } else { buf[i++] = xchar(((current_block_value & 0xf0) >> 4)); zero_flag = 0; if (i >= buflen) return NULL; } buf[i++] = xchar((current_block_value & 0xf)); if (i >= buflen) return NULL; zero_flag = 0; } } buf[i] = 0; return buf; } #endif /* LWIP_IPV6 */ ocproxy-1.60/lwip/src/core/ipv6/ip6_frag.c000066400000000000000000000546121303453231400203700ustar00rootroot00000000000000/** * @file * * IPv6 fragmentation and reassembly. */ /* * Copyright (c) 2010 Inico Technologies Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Ivan Delamer * * * Please coordinate changes and requests with Ivan Delamer * */ #include "lwip/opt.h" #include "lwip/ip6_frag.h" #include "lwip/ip6.h" #include "lwip/icmp6.h" #include "lwip/nd6.h" #include "lwip/ip.h" #include "lwip/pbuf.h" #include "lwip/memp.h" #include "lwip/stats.h" #include #if LWIP_IPV6 && LWIP_IPV6_REASS /* don't build if not configured for use in lwipopts.h */ /** Setting this to 0, you can turn off checking the fragments for overlapping * regions. The code gets a little smaller. Only use this if you know that * overlapping won't occur on your network! */ #ifndef IP_REASS_CHECK_OVERLAP #define IP_REASS_CHECK_OVERLAP 1 #endif /* IP_REASS_CHECK_OVERLAP */ /** Set to 0 to prevent freeing the oldest datagram when the reassembly buffer is * full (IP_REASS_MAX_PBUFS pbufs are enqueued). The code gets a little smaller. * Datagrams will be freed by timeout only. Especially useful when MEMP_NUM_REASSDATA * is set to 1, so one datagram can be reassembled at a time, only. */ #ifndef IP_REASS_FREE_OLDEST #define IP_REASS_FREE_OLDEST 1 #endif /* IP_REASS_FREE_OLDEST */ #define IP_REASS_FLAG_LASTFRAG 0x01 /** This is a helper struct which holds the starting * offset and the ending offset of this fragment to * easily chain the fragments. * It has the same packing requirements as the IPv6 header, since it replaces * the Fragment Header in memory in incoming fragments to keep * track of the various fragments. */ #ifdef PACK_STRUCT_USE_INCLUDES # include "arch/bpstruct.h" #endif PACK_STRUCT_BEGIN struct ip6_reass_helper { PACK_STRUCT_FIELD(struct pbuf *next_pbuf); PACK_STRUCT_FIELD(u16_t start); PACK_STRUCT_FIELD(u16_t end); } PACK_STRUCT_STRUCT; PACK_STRUCT_END #ifdef PACK_STRUCT_USE_INCLUDES # include "arch/epstruct.h" #endif /* static variables */ static struct ip6_reassdata *reassdatagrams; static u16_t ip6_reass_pbufcount; /* Forward declarations. */ static void ip6_reass_free_complete_datagram(struct ip6_reassdata *ipr); #if IP_REASS_FREE_OLDEST static void ip6_reass_remove_oldest_datagram(struct ip6_reassdata *ipr, int pbufs_needed); #endif /* IP_REASS_FREE_OLDEST */ void ip6_reass_tmr(void) { struct ip6_reassdata *r, *tmp; r = reassdatagrams; while (r != NULL) { /* Decrement the timer. Once it reaches 0, * clean up the incomplete fragment assembly */ if (r->timer > 0) { r->timer--; r = r->next; } else { /* reassembly timed out */ tmp = r; /* get the next pointer before freeing */ r = r->next; /* free the helper struct and all enqueued pbufs */ ip6_reass_free_complete_datagram(tmp); } } } /** * Free a datagram (struct ip6_reassdata) and all its pbufs. * Updates the total count of enqueued pbufs (ip6_reass_pbufcount), * sends an ICMP time exceeded packet. * * @param ipr datagram to free */ static void ip6_reass_free_complete_datagram(struct ip6_reassdata *ipr) { struct ip6_reassdata *prev; u16_t pbufs_freed = 0; u8_t clen; struct pbuf *p; struct ip6_reass_helper *iprh; #if LWIP_ICMP6 iprh = (struct ip6_reass_helper *)ipr->p->payload; if (iprh->start == 0) { /* The first fragment was received, send ICMP time exceeded. */ /* First, de-queue the first pbuf from r->p. */ p = ipr->p; ipr->p = iprh->next_pbuf; /* Then, move back to the original header (we are now pointing to Fragment header). */ if (pbuf_header(p, (u8_t*)p->payload - (u8_t*)ipr->iphdr)) { LWIP_ASSERT("ip6_reass_free: moving p->payload to ip6 header failed\n", 0); } else { icmp6_time_exceeded(p, ICMP6_TE_FRAG); } clen = pbuf_clen(p); LWIP_ASSERT("pbufs_freed + clen <= 0xffff", pbufs_freed + clen <= 0xffff); pbufs_freed += clen; pbuf_free(p); } #endif /* LWIP_ICMP6 */ /* First, free all received pbufs. The individual pbufs need to be released separately as they have not yet been chained */ p = ipr->p; while (p != NULL) { struct pbuf *pcur; iprh = (struct ip6_reass_helper *)p->payload; pcur = p; /* get the next pointer before freeing */ p = iprh->next_pbuf; clen = pbuf_clen(pcur); LWIP_ASSERT("pbufs_freed + clen <= 0xffff", pbufs_freed + clen <= 0xffff); pbufs_freed += clen; pbuf_free(pcur); } /* Then, unchain the struct ip6_reassdata from the list and free it. */ if (ipr == reassdatagrams) { reassdatagrams = ipr->next; } else { prev = reassdatagrams; while (prev != NULL) { if (prev->next == ipr) { break; } prev = prev->next; } if (prev != NULL) { prev->next = ipr->next; } } memp_free(MEMP_IP6_REASSDATA, ipr); /* Finally, update number of pbufs in reassembly queue */ LWIP_ASSERT("ip_reass_pbufcount >= clen", ip6_reass_pbufcount >= pbufs_freed); ip6_reass_pbufcount -= pbufs_freed; } #if IP_REASS_FREE_OLDEST /** * Free the oldest datagram to make room for enqueueing new fragments. * The datagram ipr is not freed! * * @param ipr ip6_reassdata for the current fragment * @param pbufs_needed number of pbufs needed to enqueue * (used for freeing other datagrams if not enough space) */ static void ip6_reass_remove_oldest_datagram(struct ip6_reassdata *ipr, int pbufs_needed) { struct ip6_reassdata *r, *oldest; /* Free datagrams until being allowed to enqueue 'pbufs_needed' pbufs, * but don't free the current datagram! */ do { r = oldest = reassdatagrams; while (r != NULL) { if (r != ipr) { if (r->timer <= oldest->timer) { /* older than the previous oldest */ oldest = r; } } r = r->next; } if (oldest != NULL) { ip6_reass_free_complete_datagram(oldest); } } while (((ip6_reass_pbufcount + pbufs_needed) > IP_REASS_MAX_PBUFS) && (reassdatagrams != NULL)); } #endif /* IP_REASS_FREE_OLDEST */ /** * Reassembles incoming IPv6 fragments into an IPv6 datagram. * * @param p points to the IPv6 Fragment Header * @param len the length of the payload (after Fragment Header) * @return NULL if reassembly is incomplete, pbuf pointing to * IPv6 Header if reassembly is complete */ struct pbuf * ip6_reass(struct pbuf *p) { struct ip6_reassdata *ipr, *ipr_prev; struct ip6_reass_helper *iprh, *iprh_tmp, *iprh_prev=NULL; struct ip6_frag_hdr * frag_hdr; u16_t offset, len; u8_t clen, valid = 1; struct pbuf *q; IP6_FRAG_STATS_INC(ip6_frag.recv); frag_hdr = (struct ip6_frag_hdr *) p->payload; clen = pbuf_clen(p); offset = ntohs(frag_hdr->_fragment_offset); /* Calculate fragment length from IPv6 payload length. * Adjust for headers before Fragment Header. * And finally adjust by Fragment Header length. */ len = ntohs(ip6_current_header()->_plen); len -= ((u8_t*)p->payload - (u8_t*)ip6_current_header()) - IP6_HLEN; len -= IP6_FRAG_HLEN; /* Look for the datagram the fragment belongs to in the current datagram queue, * remembering the previous in the queue for later dequeueing. */ for (ipr = reassdatagrams, ipr_prev = NULL; ipr != NULL; ipr = ipr->next) { /* Check if the incoming fragment matches the one currently present in the reassembly buffer. If so, we proceed with copying the fragment into the buffer. */ if ((frag_hdr->_identification == ipr->identification) && ip6_addr_cmp(ip6_current_src_addr(), &(ipr->iphdr->src)) && ip6_addr_cmp(ip6_current_dest_addr(), &(ipr->iphdr->dest))) { IP6_FRAG_STATS_INC(ip6_frag.cachehit); break; } ipr_prev = ipr; } if (ipr == NULL) { /* Enqueue a new datagram into the datagram queue */ ipr = (struct ip6_reassdata *)memp_malloc(MEMP_IP6_REASSDATA); if (ipr == NULL) { #if IP_REASS_FREE_OLDEST /* Make room and try again. */ ip6_reass_remove_oldest_datagram(ipr, clen); ipr = (struct ip6_reassdata *)memp_malloc(MEMP_IP6_REASSDATA); if (ipr != NULL) { /* re-search ipr_prev since it might have been removed */ for (ipr_prev = reassdatagrams; ipr_prev != NULL; ipr_prev = ipr_prev->next) { if (ipr_prev->next == ipr) { break; } } } else #endif /* IP_REASS_FREE_OLDEST */ { IP6_FRAG_STATS_INC(ip6_frag.memerr); IP6_FRAG_STATS_INC(ip6_frag.drop); goto nullreturn; } } memset(ipr, 0, sizeof(struct ip6_reassdata)); ipr->timer = IP_REASS_MAXAGE; /* enqueue the new structure to the front of the list */ ipr->next = reassdatagrams; reassdatagrams = ipr; /* Use the current IPv6 header for src/dest address reference. * Eventually, we will replace it when we get the first fragment * (it might be this one, in any case, it is done later). */ ipr->iphdr = (struct ip6_hdr *)ip6_current_header(); /* copy the fragmented packet id. */ ipr->identification = frag_hdr->_identification; /* copy the nexth field */ ipr->nexth = frag_hdr->_nexth; } /* Check if we are allowed to enqueue more datagrams. */ if ((ip6_reass_pbufcount + clen) > IP_REASS_MAX_PBUFS) { #if IP_REASS_FREE_OLDEST ip6_reass_remove_oldest_datagram(ipr, clen); if ((ip6_reass_pbufcount + clen) <= IP_REASS_MAX_PBUFS) { /* re-search ipr_prev since it might have been removed */ for (ipr_prev = reassdatagrams; ipr_prev != NULL; ipr_prev = ipr_prev->next) { if (ipr_prev->next == ipr) { break; } } } else #endif /* IP_REASS_FREE_OLDEST */ { /* @todo: send ICMPv6 time exceeded here? */ /* drop this pbuf */ IP6_FRAG_STATS_INC(ip6_frag.memerr); IP6_FRAG_STATS_INC(ip6_frag.drop); goto nullreturn; } } /* Overwrite Fragment Header with our own helper struct. */ iprh = (struct ip6_reass_helper *)p->payload; LWIP_ASSERT("sizeof(struct ip6_reass_helper) <= IP6_FRAG_HLEN", sizeof(struct ip6_reass_helper) <= IP6_FRAG_HLEN); iprh->next_pbuf = NULL; iprh->start = (offset & IP6_FRAG_OFFSET_MASK); iprh->end = (offset & IP6_FRAG_OFFSET_MASK) + len; /* find the right place to insert this pbuf */ /* Iterate through until we either get to the end of the list (append), * or we find on with a larger offset (insert). */ for (q = ipr->p; q != NULL;) { iprh_tmp = (struct ip6_reass_helper*)q->payload; if (iprh->start < iprh_tmp->start) { #if IP_REASS_CHECK_OVERLAP if (iprh->end > iprh_tmp->start) { /* fragment overlaps with following, throw away */ IP6_FRAG_STATS_INC(ip6_frag.proterr); IP6_FRAG_STATS_INC(ip6_frag.drop); goto nullreturn; } if (iprh_prev != NULL) { if (iprh->start < iprh_prev->end) { /* fragment overlaps with previous, throw away */ IP6_FRAG_STATS_INC(ip6_frag.proterr); IP6_FRAG_STATS_INC(ip6_frag.drop); goto nullreturn; } } #endif /* IP_REASS_CHECK_OVERLAP */ /* the new pbuf should be inserted before this */ iprh->next_pbuf = q; if (iprh_prev != NULL) { /* not the fragment with the lowest offset */ iprh_prev->next_pbuf = p; } else { /* fragment with the lowest offset */ ipr->p = p; } break; } else if(iprh->start == iprh_tmp->start) { /* received the same datagram twice: no need to keep the datagram */ IP6_FRAG_STATS_INC(ip6_frag.drop); goto nullreturn; #if IP_REASS_CHECK_OVERLAP } else if(iprh->start < iprh_tmp->end) { /* overlap: no need to keep the new datagram */ IP6_FRAG_STATS_INC(ip6_frag.proterr); IP6_FRAG_STATS_INC(ip6_frag.drop); goto nullreturn; #endif /* IP_REASS_CHECK_OVERLAP */ } else { /* Check if the fragments received so far have no gaps. */ if (iprh_prev != NULL) { if (iprh_prev->end != iprh_tmp->start) { /* There is a fragment missing between the current * and the previous fragment */ valid = 0; } } } q = iprh_tmp->next_pbuf; iprh_prev = iprh_tmp; } /* If q is NULL, then we made it to the end of the list. Determine what to do now */ if (q == NULL) { if (iprh_prev != NULL) { /* this is (for now), the fragment with the highest offset: * chain it to the last fragment */ #if IP_REASS_CHECK_OVERLAP LWIP_ASSERT("check fragments don't overlap", iprh_prev->end <= iprh->start); #endif /* IP_REASS_CHECK_OVERLAP */ iprh_prev->next_pbuf = p; if (iprh_prev->end != iprh->start) { valid = 0; } } else { #if IP_REASS_CHECK_OVERLAP LWIP_ASSERT("no previous fragment, this must be the first fragment!", ipr->p == NULL); #endif /* IP_REASS_CHECK_OVERLAP */ /* this is the first fragment we ever received for this ip datagram */ ipr->p = p; } } /* Track the current number of pbufs current 'in-flight', in order to limit the number of fragments that may be enqueued at any one time */ ip6_reass_pbufcount += clen; /* Remember IPv6 header if this is the first fragment. */ if (iprh->start == 0) { ipr->iphdr = (struct ip6_hdr *)ip6_current_header(); } /* If this is the last fragment, calculate total packet length. */ if ((offset & IP6_FRAG_MORE_FLAG) == 0) { ipr->datagram_len = iprh->end; } /* Additional validity tests: we have received first and last fragment. */ iprh_tmp = (struct ip6_reass_helper*)ipr->p->payload; if (iprh_tmp->start != 0) { valid = 0; } if (ipr->datagram_len == 0) { valid = 0; } /* Final validity test: no gaps between current and last fragment. */ iprh_prev = iprh; q = iprh->next_pbuf; while ((q != NULL) && valid) { iprh = (struct ip6_reass_helper*)q->payload; if (iprh_prev->end != iprh->start) { valid = 0; break; } iprh_prev = iprh; q = iprh->next_pbuf; } if (valid) { /* All fragments have been received */ u8_t* iphdr_ptr; /* chain together the pbufs contained within the ip6_reassdata list. */ iprh = (struct ip6_reass_helper*) ipr->p->payload; while(iprh != NULL) { if (iprh->next_pbuf != NULL) { /* Save next helper struct (will be hidden in next step). */ iprh_tmp = (struct ip6_reass_helper*) iprh->next_pbuf->payload; /* hide the fragment header for every succeding fragment */ pbuf_header(iprh->next_pbuf, -IP6_FRAG_HLEN); pbuf_cat(ipr->p, iprh->next_pbuf); } else { iprh_tmp = NULL; } iprh = iprh_tmp; } /* Adjust datagram length by adding header lengths. */ ipr->datagram_len += ((u8_t*)ipr->p->payload - (u8_t*)ipr->iphdr) + IP6_FRAG_HLEN - IP6_HLEN ; /* Set payload length in ip header. */ ipr->iphdr->_plen = htons(ipr->datagram_len); /* Get the furst pbuf. */ p = ipr->p; /* Restore Fragment Header in first pbuf. Mark as "single fragment" * packet. Restore nexth. */ frag_hdr = (struct ip6_frag_hdr *) p->payload; frag_hdr->_nexth = ipr->nexth; frag_hdr->reserved = 0; frag_hdr->_fragment_offset = 0; frag_hdr->_identification = 0; /* release the sources allocate for the fragment queue entry */ if (reassdatagrams == ipr) { /* it was the first in the list */ reassdatagrams = ipr->next; } else { /* it wasn't the first, so it must have a valid 'prev' */ LWIP_ASSERT("sanity check linked list", ipr_prev != NULL); ipr_prev->next = ipr->next; } iphdr_ptr = (u8_t*)ipr->iphdr; memp_free(MEMP_IP6_REASSDATA, ipr); /* adjust the number of pbufs currently queued for reassembly. */ ip6_reass_pbufcount -= pbuf_clen(p); /* Move pbuf back to IPv6 header. */ if (pbuf_header(p, (u8_t*)p->payload - iphdr_ptr)) { LWIP_ASSERT("ip6_reass: moving p->payload to ip6 header failed\n", 0); pbuf_free(p); return NULL; } /* Return the pbuf chain */ return p; } /* the datagram is not (yet?) reassembled completely */ return NULL; nullreturn: pbuf_free(p); return NULL; } #endif /* LWIP_IPV6 ^^ LWIP_IPV6_REASS */ #if LWIP_IPV6 && LWIP_IPV6_FRAG /** Allocate a new struct pbuf_custom_ref */ static struct pbuf_custom_ref* ip6_frag_alloc_pbuf_custom_ref(void) { return (struct pbuf_custom_ref*)memp_malloc(MEMP_FRAG_PBUF); } /** Free a struct pbuf_custom_ref */ static void ip6_frag_free_pbuf_custom_ref(struct pbuf_custom_ref* p) { LWIP_ASSERT("p != NULL", p != NULL); memp_free(MEMP_FRAG_PBUF, p); } /** Free-callback function to free a 'struct pbuf_custom_ref', called by * pbuf_free. */ static void ip6_frag_free_pbuf_custom(struct pbuf *p) { struct pbuf_custom_ref *pcr = (struct pbuf_custom_ref*)p; LWIP_ASSERT("pcr != NULL", pcr != NULL); LWIP_ASSERT("pcr == p", (void*)pcr == (void*)p); if (pcr->original != NULL) { pbuf_free(pcr->original); } ip6_frag_free_pbuf_custom_ref(pcr); } /** * Fragment an IPv6 datagram if too large for the netif or path MTU. * * Chop the datagram in MTU sized chunks and send them in order * by pointing PBUF_REFs into p * * @param p ipv6 packet to send * @param netif the netif on which to send * @param dest destination ipv6 address to which to send * * @return ERR_OK if sent successfully, err_t otherwise */ err_t ip6_frag(struct pbuf *p, struct netif *netif, ip6_addr_t *dest) { struct ip6_hdr *original_ip6hdr; struct ip6_hdr *ip6hdr; struct ip6_frag_hdr * frag_hdr; struct pbuf *rambuf; struct pbuf *newpbuf; static u32_t identification; u16_t nfb; u16_t left, cop; u16_t mtu; u16_t fragment_offset = 0; u16_t last; u16_t poff = IP6_HLEN; u16_t newpbuflen = 0; u16_t left_to_copy; identification++; original_ip6hdr = (struct ip6_hdr *)p->payload; mtu = nd6_get_destination_mtu(dest, netif); /* TODO we assume there are no options in the unfragmentable part (IPv6 header). */ left = p->tot_len - IP6_HLEN; nfb = (mtu - (IP6_HLEN + IP6_FRAG_HLEN)) & IP6_FRAG_OFFSET_MASK; while (left) { last = (left <= nfb); /* Fill this fragment */ cop = last ? left : nfb; /* When not using a static buffer, create a chain of pbufs. * The first will be a PBUF_RAM holding the link, IPv6, and Fragment header. * The rest will be PBUF_REFs mirroring the pbuf chain to be fragged, * but limited to the size of an mtu. */ rambuf = pbuf_alloc(PBUF_LINK, IP6_HLEN + IP6_FRAG_HLEN, PBUF_RAM); if (rambuf == NULL) { IP6_FRAG_STATS_INC(ip6_frag.memerr); return ERR_MEM; } LWIP_ASSERT("this needs a pbuf in one piece!", (p->len >= (IP6_HLEN + IP6_FRAG_HLEN))); SMEMCPY(rambuf->payload, original_ip6hdr, IP6_HLEN); ip6hdr = (struct ip6_hdr *)rambuf->payload; frag_hdr = (struct ip6_frag_hdr *)((u8_t*)rambuf->payload + IP6_HLEN); /* Can just adjust p directly for needed offset. */ p->payload = (u8_t *)p->payload + poff; p->len -= poff; p->tot_len -= poff; left_to_copy = cop; while (left_to_copy) { struct pbuf_custom_ref *pcr; newpbuflen = (left_to_copy < p->len) ? left_to_copy : p->len; /* Is this pbuf already empty? */ if (!newpbuflen) { p = p->next; continue; } pcr = ip6_frag_alloc_pbuf_custom_ref(); if (pcr == NULL) { pbuf_free(rambuf); IP6_FRAG_STATS_INC(ip6_frag.memerr); return ERR_MEM; } /* Mirror this pbuf, although we might not need all of it. */ newpbuf = pbuf_alloced_custom(PBUF_RAW, newpbuflen, PBUF_REF, &pcr->pc, p->payload, newpbuflen); if (newpbuf == NULL) { ip6_frag_free_pbuf_custom_ref(pcr); pbuf_free(rambuf); IP6_FRAG_STATS_INC(ip6_frag.memerr); return ERR_MEM; } pbuf_ref(p); pcr->original = p; pcr->pc.custom_free_function = ip6_frag_free_pbuf_custom; /* Add it to end of rambuf's chain, but using pbuf_cat, not pbuf_chain * so that it is removed when pbuf_dechain is later called on rambuf. */ pbuf_cat(rambuf, newpbuf); left_to_copy -= newpbuflen; if (left_to_copy) { p = p->next; } } poff = newpbuflen; /* Set headers */ frag_hdr->_nexth = original_ip6hdr->_nexth; frag_hdr->reserved = 0; frag_hdr->_fragment_offset = htons((fragment_offset & IP6_FRAG_OFFSET_MASK) | (last ? 0 : IP6_FRAG_MORE_FLAG)); frag_hdr->_identification = htonl(identification); IP6H_NEXTH_SET(ip6hdr, IP6_NEXTH_FRAGMENT); IP6H_PLEN_SET(ip6hdr, cop + IP6_FRAG_HLEN); /* No need for separate header pbuf - we allowed room for it in rambuf * when allocated. */ IP6_FRAG_STATS_INC(ip6_frag.xmit); netif->output_ip6(netif, rambuf, dest); /* Unfortunately we can't reuse rambuf - the hardware may still be * using the buffer. Instead we free it (and the ensuing chain) and * recreate it next time round the loop. If we're lucky the hardware * will have already sent the packet, the free will really free, and * there will be zero memory penalty. */ pbuf_free(rambuf); left -= cop; fragment_offset += cop; } return ERR_OK; } #endif /* LWIP_IPV6 && LWIP_IPV6_FRAG */ ocproxy-1.60/lwip/src/core/ipv6/mld6.c000066400000000000000000000403571303453231400175360ustar00rootroot00000000000000/** * @file * * Multicast listener discovery for IPv6. Aims to be compliant with RFC 2710. * No support for MLDv2. */ /* * Copyright (c) 2010 Inico Technologies Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Ivan Delamer * * * Please coordinate changes and requests with Ivan Delamer * */ /* Based on igmp.c implementation of igmp v2 protocol */ #include "lwip/opt.h" #if LWIP_IPV6 && LWIP_IPV6_MLD /* don't build if not configured for use in lwipopts.h */ #include "lwip/mld6.h" #include "lwip/icmp6.h" #include "lwip/ip6.h" #include "lwip/ip6_addr.h" #include "lwip/ip.h" #include "lwip/inet_chksum.h" #include "lwip/pbuf.h" #include "lwip/netif.h" #include "lwip/memp.h" #include "lwip/stats.h" #include /* * MLD constants */ #define MLD6_HL 1 #define MLD6_JOIN_DELAYING_MEMBER_TMR_MS (500) #define MLD6_GROUP_NON_MEMBER 0 #define MLD6_GROUP_DELAYING_MEMBER 1 #define MLD6_GROUP_IDLE_MEMBER 2 /* The list of joined groups. */ static struct mld_group* mld_group_list; /* Forward declarations. */ static struct mld_group * mld6_new_group(struct netif *ifp, ip6_addr_t *addr); static err_t mld6_free_group(struct mld_group *group); static void mld6_delayed_report(struct mld_group *group, u16_t maxresp); static void mld6_send(struct mld_group *group, u8_t type); /** * Stop MLD processing on interface * * @param netif network interface on which stop MLD processing */ err_t mld6_stop(struct netif *netif) { struct mld_group *group = mld_group_list; struct mld_group *prev = NULL; struct mld_group *next; /* look for groups joined on this interface further down the list */ while (group != NULL) { next = group->next; /* is it a group joined on this interface? */ if (group->netif == netif) { /* is it the first group of the list? */ if (group == mld_group_list) { mld_group_list = next; } /* is there a "previous" group defined? */ if (prev != NULL) { prev->next = next; } /* disable the group at the MAC level */ if (netif->mld_mac_filter != NULL) { netif->mld_mac_filter(netif, &(group->group_address), MLD6_DEL_MAC_FILTER); } /* free group */ memp_free(MEMP_MLD6_GROUP, group); } else { /* change the "previous" */ prev = group; } /* move to "next" */ group = next; } return ERR_OK; } /** * Report MLD memberships for this interface * * @param netif network interface on which report MLD memberships */ void mld6_report_groups(struct netif *netif) { struct mld_group *group = mld_group_list; while (group != NULL) { if (group->netif == netif) { mld6_delayed_report(group, MLD6_JOIN_DELAYING_MEMBER_TMR_MS); } group = group->next; } } /** * Search for a group that is joined on a netif * * @param ifp the network interface for which to look * @param addr the group ipv6 address to search for * @return a struct mld_group* if the group has been found, * NULL if the group wasn't found. */ struct mld_group * mld6_lookfor_group(struct netif *ifp, ip6_addr_t *addr) { struct mld_group *group = mld_group_list; while (group != NULL) { if ((group->netif == ifp) && (ip6_addr_cmp(&(group->group_address), addr))) { return group; } group = group->next; } return NULL; } /** * create a new group * * @param ifp the network interface for which to create * @param addr the new group ipv6 * @return a struct mld_group*, * NULL on memory error. */ static struct mld_group * mld6_new_group(struct netif *ifp, ip6_addr_t *addr) { struct mld_group *group; group = (struct mld_group *)memp_malloc(MEMP_MLD6_GROUP); if (group != NULL) { group->netif = ifp; ip6_addr_set(&(group->group_address), addr); group->timer = 0; /* Not running */ group->group_state = MLD6_GROUP_IDLE_MEMBER; group->last_reporter_flag = 0; group->use = 0; group->next = mld_group_list; mld_group_list = group; } return group; } /** * Remove a group in the mld_group_list and free * * @param group the group to remove * @return ERR_OK if group was removed from the list, an err_t otherwise */ static err_t mld6_free_group(struct mld_group *group) { err_t err = ERR_OK; /* Is it the first group? */ if (mld_group_list == group) { mld_group_list = group->next; } else { /* look for group further down the list */ struct mld_group *tmpGroup; for (tmpGroup = mld_group_list; tmpGroup != NULL; tmpGroup = tmpGroup->next) { if (tmpGroup->next == group) { tmpGroup->next = group->next; break; } } /* Group not find group */ if (tmpGroup == NULL) err = ERR_ARG; } /* free group */ memp_free(MEMP_MLD6_GROUP, group); return err; } /** * Process an input MLD message. Called by icmp6_input. * * @param p the mld packet, p->payload pointing to the icmpv6 header * @param inp the netif on which this packet was received */ void mld6_input(struct pbuf *p, struct netif *inp) { struct mld_header * mld_hdr; struct mld_group* group; MLD6_STATS_INC(mld6.recv); /* Check that mld header fits in packet. */ if (p->len < sizeof(struct mld_header)) { /* TODO debug message */ pbuf_free(p); MLD6_STATS_INC(mld6.lenerr); MLD6_STATS_INC(mld6.drop); return; } mld_hdr = (struct mld_header *)p->payload; switch (mld_hdr->type) { case ICMP6_TYPE_MLQ: /* Multicast listener query. */ { /* Is it a general query? */ if (ip6_addr_isallnodes_linklocal(ip6_current_dest_addr()) && ip6_addr_isany(&(mld_hdr->multicast_address))) { MLD6_STATS_INC(mld6.rx_general); /* Report all groups, except all nodes group, and if-local groups. */ group = mld_group_list; while (group != NULL) { if ((group->netif == inp) && (!(ip6_addr_ismulticast_iflocal(&(group->group_address)))) && (!(ip6_addr_isallnodes_linklocal(&(group->group_address))))) { mld6_delayed_report(group, mld_hdr->max_resp_delay); } group = group->next; } } else { /* Have we joined this group? * We use IP6 destination address to have a memory aligned copy. * mld_hdr->multicast_address should be the same. */ MLD6_STATS_INC(mld6.rx_group); group = mld6_lookfor_group(inp, ip6_current_dest_addr()); if (group != NULL) { /* Schedule a report. */ mld6_delayed_report(group, mld_hdr->max_resp_delay); } } break; /* ICMP6_TYPE_MLQ */ } case ICMP6_TYPE_MLR: /* Multicast listener report. */ { /* Have we joined this group? * We use IP6 destination address to have a memory aligned copy. * mld_hdr->multicast_address should be the same. */ MLD6_STATS_INC(mld6.rx_report); group = mld6_lookfor_group(inp, ip6_current_dest_addr()); if (group != NULL) { /* If we are waiting to report, cancel it. */ if (group->group_state == MLD6_GROUP_DELAYING_MEMBER) { group->timer = 0; /* stopped */ group->group_state = MLD6_GROUP_IDLE_MEMBER; group->last_reporter_flag = 0; } } break; /* ICMP6_TYPE_MLR */ } case ICMP6_TYPE_MLD: /* Multicast listener done. */ { /* Do nothing, router will query us. */ break; /* ICMP6_TYPE_MLD */ } default: MLD6_STATS_INC(mld6.proterr); MLD6_STATS_INC(mld6.drop); break; } pbuf_free(p); } /** * Join a group on a network interface. * * @param srcaddr ipv6 address of the network interface which should * join a new group. If IP6_ADDR_ANY, join on all netifs * @param groupaddr the ipv6 address of the group to join * @return ERR_OK if group was joined on the netif(s), an err_t otherwise */ err_t mld6_joingroup(ip6_addr_t *srcaddr, ip6_addr_t *groupaddr) { err_t err = ERR_VAL; /* no matching interface */ struct mld_group *group; struct netif *netif; u8_t match; u8_t i; /* loop through netif's */ netif = netif_list; while (netif != NULL) { /* Should we join this interface ? */ match = 0; if (ip6_addr_isany(srcaddr)) { match = 1; } else { for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { if (ip6_addr_cmp(srcaddr, netif_ip6_addr(netif, i))) { match = 1; break; } } } if (match) { /* find group or create a new one if not found */ group = mld6_lookfor_group(netif, groupaddr); if (group == NULL) { /* Joining a new group. Create a new group entry. */ group = mld6_new_group(netif, groupaddr); if (group == NULL) { return ERR_MEM; } /* Activate this address on the MAC layer. */ if (netif->mld_mac_filter != NULL) { netif->mld_mac_filter(netif, groupaddr, MLD6_ADD_MAC_FILTER); } /* Report our membership. */ MLD6_STATS_INC(mld6.tx_report); mld6_send(group, ICMP6_TYPE_MLR); mld6_delayed_report(group, MLD6_JOIN_DELAYING_MEMBER_TMR_MS); } /* Increment group use */ group->use++; err = ERR_OK; } /* proceed to next network interface */ netif = netif->next; } return err; } /** * Leave a group on a network interface. * * @param srcaddr ipv6 address of the network interface which should * leave the group. If IP6_ISANY, leave on all netifs * @param groupaddr the ipv6 address of the group to leave * @return ERR_OK if group was left on the netif(s), an err_t otherwise */ err_t mld6_leavegroup(ip6_addr_t *srcaddr, ip6_addr_t *groupaddr) { err_t err = ERR_VAL; /* no matching interface */ struct mld_group *group; struct netif *netif; u8_t match; u8_t i; /* loop through netif's */ netif = netif_list; while (netif != NULL) { /* Should we leave this interface ? */ match = 0; if (ip6_addr_isany(srcaddr)) { match = 1; } else { for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { if (ip6_addr_cmp(srcaddr, netif_ip6_addr(netif, i))) { match = 1; break; } } } if (match) { /* find group */ group = mld6_lookfor_group(netif, groupaddr); if (group != NULL) { /* Leave if there is no other use of the group */ if (group->use <= 1) { /* If we are the last reporter for this group */ if (group->last_reporter_flag) { MLD6_STATS_INC(mld6.tx_leave); mld6_send(group, ICMP6_TYPE_MLD); } /* Disable the group at the MAC level */ if (netif->mld_mac_filter != NULL) { netif->mld_mac_filter(netif, groupaddr, MLD6_DEL_MAC_FILTER); } /* Free the group */ mld6_free_group(group); } else { /* Decrement group use */ group->use--; } /* Leave on this interface */ err = ERR_OK; } } /* proceed to next network interface */ netif = netif->next; } return err; } /** * Periodic timer for mld processing. Must be called every * MLD6_TMR_INTERVAL milliseconds (100). * * When a delaying member expires, a membership report is sent. */ void mld6_tmr(void) { struct mld_group *group = mld_group_list; while (group != NULL) { if (group->timer > 0) { group->timer--; if (group->timer == 0) { /* If the state is MLD6_GROUP_DELAYING_MEMBER then we send a report for this group */ if (group->group_state == MLD6_GROUP_DELAYING_MEMBER) { MLD6_STATS_INC(mld6.tx_report); mld6_send(group, ICMP6_TYPE_MLR); group->group_state = MLD6_GROUP_IDLE_MEMBER; } } } group = group->next; } } /** * Schedule a delayed membership report for a group * * @param group the mld_group for which "delaying" membership report * should be sent * @param maxresp the max resp delay provided in the query */ static void mld6_delayed_report(struct mld_group *group, u16_t maxresp) { /* Convert maxresp from milliseconds to tmr ticks */ maxresp = maxresp / MLD6_TMR_INTERVAL; if (maxresp == 0) { maxresp = 1; } #ifdef LWIP_RAND /* Randomize maxresp. (if LWIP_RAND is supported) */ maxresp = LWIP_RAND() % maxresp; if (maxresp == 0) { maxresp = 1; } #endif /* LWIP_RAND */ /* Apply timer value if no report has been scheduled already. */ if ((group->group_state == MLD6_GROUP_IDLE_MEMBER) || ((group->group_state == MLD6_GROUP_DELAYING_MEMBER) && ((group->timer == 0) || (maxresp < group->timer)))) { group->timer = maxresp; group->group_state = MLD6_GROUP_DELAYING_MEMBER; } } /** * Send a MLD message (report or done). * * An IPv6 hop-by-hop options header with a router alert option * is prepended. * * @param group the group to report or quit * @param type ICMP6_TYPE_MLR (report) or ICMP6_TYPE_MLD (done) */ static void mld6_send(struct mld_group *group, u8_t type) { struct mld_header * mld_hdr; struct pbuf * p; ip6_addr_t * src_addr; /* Allocate a packet. Size is MLD header + IPv6 Hop-by-hop options header. */ p = pbuf_alloc(PBUF_IP, sizeof(struct mld_header) + sizeof(struct ip6_hbh_hdr), PBUF_RAM); if ((p == NULL) || (p->len < (sizeof(struct mld_header) + sizeof(struct ip6_hbh_hdr)))) { /* We couldn't allocate a suitable pbuf. drop it. */ if (p != NULL) { pbuf_free(p); } MLD6_STATS_INC(mld6.memerr); return; } /* Move to make room for Hop-by-hop options header. */ if (pbuf_header(p, -IP6_HBH_HLEN)) { pbuf_free(p); MLD6_STATS_INC(mld6.lenerr); return; } /* Select our source address. */ if (!ip6_addr_isvalid(netif_ip6_addr_state(group->netif, 0))) { /* This is a special case, when we are performing duplicate address detection. * We must join the multicast group, but we don't have a valid address yet. */ src_addr = IP6_ADDR_ANY; } else { /* Use link-local address as source address. */ src_addr = netif_ip6_addr(group->netif, 0); } /* MLD message header pointer. */ mld_hdr = (struct mld_header *)p->payload; /* Set fields. */ mld_hdr->type = type; mld_hdr->code = 0; mld_hdr->chksum = 0; mld_hdr->max_resp_delay = 0; mld_hdr->reserved = 0; ip6_addr_set(&(mld_hdr->multicast_address), &(group->group_address)); #if CHECKSUM_GEN_ICMP6 mld_hdr->chksum = ip6_chksum_pseudo(p, IP6_NEXTH_ICMP6, p->len, src_addr, &(group->group_address)); #endif /* CHECKSUM_GEN_ICMP6 */ /* Add hop-by-hop headers options: router alert with MLD value. */ ip6_options_add_hbh_ra(p, IP6_NEXTH_ICMP6, IP6_ROUTER_ALERT_VALUE_MLD); /* Send the packet out. */ MLD6_STATS_INC(mld6.xmit); ip6_output_if(p, (ip6_addr_isany(src_addr)) ? NULL : src_addr, &(group->group_address), MLD6_HL, 0, IP6_NEXTH_HOPBYHOP, group->netif); pbuf_free(p); } #endif /* LWIP_IPV6 */ ocproxy-1.60/lwip/src/core/ipv6/nd6.c000066400000000000000000001610421303453231400173560ustar00rootroot00000000000000/** * @file * * Neighbor discovery and stateless address autoconfiguration for IPv6. * Aims to be compliant with RFC 4861 (Neighbor discovery) and RFC 4862 * (Address autoconfiguration). */ /* * Copyright (c) 2010 Inico Technologies Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Ivan Delamer * * * Please coordinate changes and requests with Ivan Delamer * */ #include "lwip/opt.h" #if LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */ #include "lwip/nd6.h" #include "lwip/pbuf.h" #include "lwip/mem.h" #include "lwip/memp.h" #include "lwip/ip6.h" #include "lwip/ip6_addr.h" #include "lwip/inet_chksum.h" #include "lwip/netif.h" #include "lwip/icmp6.h" #include "lwip/mld6.h" #include "lwip/ip.h" #include "lwip/stats.h" #include /* Router tables. */ struct nd6_neighbor_cache_entry neighbor_cache[LWIP_ND6_NUM_NEIGHBORS]; struct nd6_destination_cache_entry destination_cache[LWIP_ND6_NUM_DESTINATIONS]; struct nd6_prefix_list_entry prefix_list[LWIP_ND6_NUM_PREFIXES]; struct nd6_router_list_entry default_router_list[LWIP_ND6_NUM_ROUTERS]; /* Default values, can be updated by a RA message. */ u32_t reachable_time = LWIP_ND6_REACHABLE_TIME; u32_t retrans_timer = LWIP_ND6_RETRANS_TIMER; /* TODO implement this value in timer */ /* Index for cache entries. */ static u8_t nd6_cached_neighbor_index; static u8_t nd6_cached_destination_index; /* Multicast address holder. */ static ip6_addr_t multicast_address; /* Static buffer to parse RA packet options (size of a prefix option, biggest option) */ static u8_t nd6_ra_buffer[sizeof(struct prefix_option)]; /* Forward declarations. */ static s8_t nd6_find_neighbor_cache_entry(ip6_addr_t * ip6addr); static s8_t nd6_new_neighbor_cache_entry(void); static void nd6_free_neighbor_cache_entry(s8_t i); static s8_t nd6_find_destination_cache_entry(ip6_addr_t * ip6addr); static s8_t nd6_new_destination_cache_entry(void); static s8_t nd6_is_prefix_in_netif(ip6_addr_t * ip6addr, struct netif * netif); static s8_t nd6_get_router(ip6_addr_t * router_addr, struct netif * netif); static s8_t nd6_new_router(ip6_addr_t * router_addr, struct netif * netif); static s8_t nd6_get_onlink_prefix(ip6_addr_t * prefix, struct netif * netif); static s8_t nd6_new_onlink_prefix(ip6_addr_t * prefix, struct netif * netif); #define ND6_SEND_FLAG_MULTICAST_DEST 0x01 #define ND6_SEND_FLAG_ALLNODES_DEST 0x02 static void nd6_send_ns(struct netif * netif, ip6_addr_t * target_addr, u8_t flags); static void nd6_send_na(struct netif * netif, ip6_addr_t * target_addr, u8_t flags); #if LWIP_IPV6_SEND_ROUTER_SOLICIT static void nd6_send_rs(struct netif * netif); #endif /* LWIP_IPV6_SEND_ROUTER_SOLICIT */ #if LWIP_ND6_QUEUEING static void nd6_free_q(struct nd6_q_entry *q); #else /* LWIP_ND6_QUEUEING */ #define nd6_free_q(q) pbuf_free(q) #endif /* LWIP_ND6_QUEUEING */ static void nd6_send_q(s8_t i); /** * Process an incoming neighbor discovery message * * @param p the nd packet, p->payload pointing to the icmpv6 header * @param inp the netif on which this packet was received */ void nd6_input(struct pbuf *p, struct netif *inp) { u8_t msg_type; s8_t i; ND6_STATS_INC(nd6.recv); msg_type = *((u8_t *)p->payload); switch (msg_type) { case ICMP6_TYPE_NA: /* Neighbor Advertisement. */ { struct na_header * na_hdr; struct lladdr_option * lladdr_opt; /* Check that na header fits in packet. */ if (p->len < (sizeof(struct na_header))) { /* TODO debug message */ pbuf_free(p); ND6_STATS_INC(nd6.lenerr); ND6_STATS_INC(nd6.drop); return; } na_hdr = (struct na_header *)p->payload; /* Unsolicited NA?*/ if (ip6_addr_ismulticast(ip6_current_dest_addr())) { /* This is an unsolicited NA. * link-layer changed? * part of DAD mechanism? */ /* Check that link-layer address option also fits in packet. */ if (p->len < (sizeof(struct na_header) + sizeof(struct lladdr_option))) { /* TODO debug message */ pbuf_free(p); ND6_STATS_INC(nd6.lenerr); ND6_STATS_INC(nd6.drop); return; } lladdr_opt = (struct lladdr_option *)((u8_t*)p->payload + sizeof(struct na_header)); /* Override ip6_current_dest_addr() so that we have an aligned copy. */ ip6_addr_set(ip6_current_dest_addr(), &(na_hdr->target_address)); #if LWIP_IPV6_DUP_DETECT_ATTEMPTS /* If the target address matches this netif, it is a DAD response. */ for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { if (ip6_addr_cmp(ip6_current_dest_addr(), netif_ip6_addr(inp, i))) { /* We are using a duplicate address. */ netif_ip6_addr_set_state(inp, i, IP6_ADDR_INVALID); #if LWIP_IPV6_MLD /* Leave solicited node multicast group. */ ip6_addr_set_solicitednode(&multicast_address, netif_ip6_addr(inp, i)->addr[3]); mld6_leavegroup(netif_ip6_addr(inp, i), &multicast_address); #endif /* LWIP_IPV6_MLD */ #if LWIP_IPV6_AUTOCONFIG /* Check to see if this address was autoconfigured. */ if (!ip6_addr_islinklocal(ip6_current_dest_addr())) { i = nd6_get_onlink_prefix(ip6_current_dest_addr(), inp); if (i >= 0) { /* Mark this prefix as duplicate, so that we don't use it * to generate this address again. */ prefix_list[i].flags |= ND6_PREFIX_AUTOCONFIG_ADDRESS_DUPLICATE; } } #endif /* LWIP_IPV6_AUTOCONFIG */ pbuf_free(p); return; } } #endif /* LWIP_IPV6_DUP_DETECT_ATTEMPTS */ /* This is an unsolicited NA, most likely there was a LLADDR change. */ i = nd6_find_neighbor_cache_entry(ip6_current_dest_addr()); if (i >= 0) { if (na_hdr->flags & ND6_FLAG_OVERRIDE) { MEMCPY(neighbor_cache[i].lladdr, lladdr_opt->addr, inp->hwaddr_len); } } } else { /* This is a solicited NA. * neighbor address resolution response? * neighbor unreachability detection response? */ /* Override ip6_current_dest_addr() so that we have an aligned copy. */ ip6_addr_set(ip6_current_dest_addr(), &(na_hdr->target_address)); /* Find the cache entry corresponding to this na. */ i = nd6_find_neighbor_cache_entry(ip6_current_dest_addr()); if (i < 0) { /* We no longer care about this target address. drop it. */ pbuf_free(p); return; } /* Update cache entry. */ neighbor_cache[i].netif = inp; neighbor_cache[i].counter.reachable_time = reachable_time; if ((na_hdr->flags & ND6_FLAG_OVERRIDE) || (neighbor_cache[i].state == ND6_INCOMPLETE)) { /* Check that link-layer address option also fits in packet. */ if (p->len < (sizeof(struct na_header) + sizeof(struct lladdr_option))) { /* TODO debug message */ pbuf_free(p); ND6_STATS_INC(nd6.lenerr); ND6_STATS_INC(nd6.drop); return; } lladdr_opt = (struct lladdr_option *)((u8_t*)p->payload + sizeof(struct na_header)); MEMCPY(neighbor_cache[i].lladdr, lladdr_opt->addr, inp->hwaddr_len); } neighbor_cache[i].state = ND6_REACHABLE; /* Send queued packets, if any. */ if (neighbor_cache[i].q != NULL) { nd6_send_q(i); } } break; /* ICMP6_TYPE_NA */ } case ICMP6_TYPE_NS: /* Neighbor solicitation. */ { struct ns_header * ns_hdr; struct lladdr_option * lladdr_opt; u8_t accepted; /* Check that ns header fits in packet. */ if (p->len < sizeof(struct ns_header)) { /* TODO debug message */ pbuf_free(p); ND6_STATS_INC(nd6.lenerr); ND6_STATS_INC(nd6.drop); return; } ns_hdr = (struct ns_header *)p->payload; /* Check if there is a link-layer address provided. Only point to it if in this buffer. */ lladdr_opt = NULL; if (p->len >= (sizeof(struct ns_header) + sizeof(struct lladdr_option))) { lladdr_opt = (struct lladdr_option *)((u8_t*)p->payload + sizeof(struct ns_header)); } /* Check if the target address is configured on the receiving netif. */ accepted = 0; for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; ++i) { if ((ip6_addr_isvalid(netif_ip6_addr_state(inp, i)) || (ip6_addr_istentative(netif_ip6_addr_state(inp, i)) && ip6_addr_isany(ip6_current_src_addr()))) && ip6_addr_cmp(&(ns_hdr->target_address), netif_ip6_addr(inp, i))) { accepted = 1; break; } } /* NS not for us? */ if (!accepted) { pbuf_free(p); return; } /* Check for ANY address in src (DAD algorithm). */ if (ip6_addr_isany(ip6_current_src_addr())) { /* Sender is validating this address. */ for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; ++i) { if (ip6_addr_cmp(&(ns_hdr->target_address), netif_ip6_addr(inp, i))) { /* Send a NA back so that the sender does not use this address. */ nd6_send_na(inp, netif_ip6_addr(inp, i), ND6_FLAG_OVERRIDE | ND6_SEND_FLAG_ALLNODES_DEST); if (ip6_addr_istentative(netif_ip6_addr_state(inp, i))) { /* We shouldn't use this address either. */ netif_ip6_addr_set_state(inp, i, IP6_ADDR_INVALID); } } } } else { /* Sender is trying to resolve our address. */ /* Verify that they included their own link-layer address. */ if (lladdr_opt == NULL) { /* Not a valid message. */ pbuf_free(p); ND6_STATS_INC(nd6.proterr); ND6_STATS_INC(nd6.drop); return; } i = nd6_find_neighbor_cache_entry(ip6_current_src_addr()); if ( i>= 0) { /* We already have a record for the solicitor. */ if (neighbor_cache[i].state == ND6_INCOMPLETE) { neighbor_cache[i].netif = inp; MEMCPY(neighbor_cache[i].lladdr, lladdr_opt->addr, inp->hwaddr_len); /* Delay probe in case we get confirmation of reachability from upper layer (TCP). */ neighbor_cache[i].state = ND6_DELAY; neighbor_cache[i].counter.delay_time = LWIP_ND6_DELAY_FIRST_PROBE_TIME; } } else { /* Add their IPv6 address and link-layer address to neighbor cache. * We will need it at least to send a unicast NA message, but most * likely we will also be communicating with this node soon. */ i = nd6_new_neighbor_cache_entry(); if (i < 0) { /* We couldn't assign a cache entry for this neighbor. * we won't be able to reply. drop it. */ pbuf_free(p); ND6_STATS_INC(nd6.memerr); return; } neighbor_cache[i].netif = inp; MEMCPY(neighbor_cache[i].lladdr, lladdr_opt->addr, inp->hwaddr_len); ip6_addr_set(&(neighbor_cache[i].next_hop_address), ip6_current_src_addr()); /* Receiving a message does not prove reachability: only in one direction. * Delay probe in case we get confirmation of reachability from upper layer (TCP). */ neighbor_cache[i].state = ND6_DELAY; neighbor_cache[i].counter.delay_time = LWIP_ND6_DELAY_FIRST_PROBE_TIME; } /* Override ip6_current_dest_addr() so that we have an aligned copy. */ ip6_addr_set(ip6_current_dest_addr(), &(ns_hdr->target_address)); /* Send back a NA for us. Allocate the reply pbuf. */ nd6_send_na(inp, ip6_current_dest_addr(), ND6_FLAG_SOLICITED | ND6_FLAG_OVERRIDE); } break; /* ICMP6_TYPE_NS */ } case ICMP6_TYPE_RA: /* Router Advertisement. */ { struct ra_header * ra_hdr; u8_t * buffer; /* Used to copy options. */ u16_t offset; /* Check that RA header fits in packet. */ if (p->len < sizeof(struct ra_header)) { /* TODO debug message */ pbuf_free(p); ND6_STATS_INC(nd6.lenerr); ND6_STATS_INC(nd6.drop); return; } ra_hdr = (struct ra_header *)p->payload; /* If we are sending RS messages, stop. */ #if LWIP_IPV6_SEND_ROUTER_SOLICIT inp->rs_count = 0; #endif /* LWIP_IPV6_SEND_ROUTER_SOLICIT */ /* Get the matching default router entry. */ i = nd6_get_router(ip6_current_src_addr(), inp); if (i < 0) { /* Create a new router entry. */ i = nd6_new_router(ip6_current_src_addr(), inp); } if (i < 0) { /* Could not create a new router entry. */ pbuf_free(p); ND6_STATS_INC(nd6.memerr); return; } /* Re-set invalidation timer. */ default_router_list[i].invalidation_timer = ra_hdr->router_lifetime; /* Re-set default timer values. */ #if LWIP_ND6_ALLOW_RA_UPDATES if (ra_hdr->retrans_timer > 0) { retrans_timer = ra_hdr->retrans_timer; } if (ra_hdr->reachable_time > 0) { reachable_time = ra_hdr->reachable_time; } #endif /* LWIP_ND6_ALLOW_RA_UPDATES */ /* TODO set default hop limit... */ /* ra_hdr->current_hop_limit;*/ /* Update flags in local entry (incl. preference). */ default_router_list[i].flags = ra_hdr->flags; /* Offset to options. */ offset = sizeof(struct ra_header); /* Process each option. */ while ((p->tot_len - offset) > 0) { if (p->len == p->tot_len) { /* no need to copy from contiguous pbuf */ buffer = &((u8_t*)p->payload)[offset]; } else { buffer = nd6_ra_buffer; pbuf_copy_partial(p, buffer, sizeof(struct prefix_option), offset); } switch (buffer[0]) { case ND6_OPTION_TYPE_SOURCE_LLADDR: { struct lladdr_option * lladdr_opt; lladdr_opt = (struct lladdr_option *)buffer; if ((default_router_list[i].neighbor_entry != NULL) && (default_router_list[i].neighbor_entry->state == ND6_INCOMPLETE)) { SMEMCPY(default_router_list[i].neighbor_entry->lladdr, lladdr_opt->addr, inp->hwaddr_len); default_router_list[i].neighbor_entry->state = ND6_REACHABLE; default_router_list[i].neighbor_entry->counter.reachable_time = reachable_time; } break; } case ND6_OPTION_TYPE_MTU: { struct mtu_option * mtu_opt; mtu_opt = (struct mtu_option *)buffer; if (mtu_opt->mtu >= 1280) { #if LWIP_ND6_ALLOW_RA_UPDATES inp->mtu = mtu_opt->mtu; #endif /* LWIP_ND6_ALLOW_RA_UPDATES */ } break; } case ND6_OPTION_TYPE_PREFIX_INFO: { struct prefix_option * prefix_opt; prefix_opt = (struct prefix_option *)buffer; if (prefix_opt->flags & ND6_PREFIX_FLAG_ON_LINK) { /* Add to on-link prefix list. */ s8_t prefix; /* Get a memory-aligned copy of the prefix. */ ip6_addr_set(ip6_current_dest_addr(), &(prefix_opt->prefix)); /* find cache entry for this prefix. */ prefix = nd6_get_onlink_prefix(ip6_current_dest_addr(), inp); if (prefix < 0) { /* Create a new cache entry. */ prefix = nd6_new_onlink_prefix(ip6_current_dest_addr(), inp); } if (prefix >= 0) { prefix_list[prefix].invalidation_timer = prefix_opt->valid_lifetime; #if LWIP_IPV6_AUTOCONFIG if (prefix_opt->flags & ND6_PREFIX_FLAG_AUTONOMOUS) { /* Mark prefix as autonomous, so that address autoconfiguration can take place. * Only OR flag, so that we don't over-write other flags (such as ADDRESS_DUPLICATE)*/ prefix_list[prefix].flags |= ND6_PREFIX_AUTOCONFIG_AUTONOMOUS; } #endif /* LWIP_IPV6_AUTOCONFIG */ } } break; } case ND6_OPTION_TYPE_ROUTE_INFO: { /* TODO implement preferred routes. struct route_option * route_opt; route_opt = (struct route_option *)buffer;*/ break; } default: /* Unrecognized option, abort. */ ND6_STATS_INC(nd6.proterr); break; } offset += 8 * ((u16_t)buffer[1]); } break; /* ICMP6_TYPE_RA */ } case ICMP6_TYPE_RD: /* Redirect */ { struct redirect_header * redir_hdr; struct lladdr_option * lladdr_opt; /* Check that Redir header fits in packet. */ if (p->len < sizeof(struct redirect_header)) { /* TODO debug message */ pbuf_free(p); ND6_STATS_INC(nd6.lenerr); ND6_STATS_INC(nd6.drop); return; } redir_hdr = (struct redirect_header *)p->payload; lladdr_opt = NULL; if (p->len >= (sizeof(struct redirect_header) + sizeof(struct lladdr_option))) { lladdr_opt = (struct lladdr_option *)((u8_t*)p->payload + sizeof(struct redirect_header)); } /* Copy original destination address to current source address, to have an aligned copy. */ ip6_addr_set(ip6_current_src_addr(), &(redir_hdr->destination_address)); /* Find dest address in cache */ i = nd6_find_destination_cache_entry(ip6_current_src_addr()); if (i < 0) { /* Destination not in cache, drop packet. */ pbuf_free(p); return; } /* Set the new target address. */ ip6_addr_set(&(destination_cache[i].next_hop_addr), &(redir_hdr->target_address)); /* If Link-layer address of other router is given, try to add to neighbor cache. */ if (lladdr_opt != NULL) { if (lladdr_opt->type == ND6_OPTION_TYPE_TARGET_LLADDR) { /* Copy target address to current source address, to have an aligned copy. */ ip6_addr_set(ip6_current_src_addr(), &(redir_hdr->target_address)); i = nd6_find_neighbor_cache_entry(ip6_current_src_addr()); if (i < 0) { i = nd6_new_neighbor_cache_entry(); if (i >= 0) { neighbor_cache[i].netif = inp; MEMCPY(neighbor_cache[i].lladdr, lladdr_opt->addr, inp->hwaddr_len); ip6_addr_set(&(neighbor_cache[i].next_hop_address), ip6_current_src_addr()); /* Receiving a message does not prove reachability: only in one direction. * Delay probe in case we get confirmation of reachability from upper layer (TCP). */ neighbor_cache[i].state = ND6_DELAY; neighbor_cache[i].counter.delay_time = LWIP_ND6_DELAY_FIRST_PROBE_TIME; } } if (i >= 0) { if (neighbor_cache[i].state == ND6_INCOMPLETE) { MEMCPY(neighbor_cache[i].lladdr, lladdr_opt->addr, inp->hwaddr_len); /* Receiving a message does not prove reachability: only in one direction. * Delay probe in case we get confirmation of reachability from upper layer (TCP). */ neighbor_cache[i].state = ND6_DELAY; neighbor_cache[i].counter.delay_time = LWIP_ND6_DELAY_FIRST_PROBE_TIME; } } } } break; /* ICMP6_TYPE_RD */ } case ICMP6_TYPE_PTB: /* Packet too big */ { struct icmp6_hdr *icmp6hdr; /* Packet too big message */ struct ip6_hdr * ip6hdr; /* IPv6 header of the packet which caused the error */ /* Check that ICMPv6 header + IPv6 header fit in payload */ if (p->len < (sizeof(struct icmp6_hdr) + IP6_HLEN)) { /* drop short packets */ pbuf_free(p); ND6_STATS_INC(nd6.lenerr); ND6_STATS_INC(nd6.drop); return; } icmp6hdr = (struct icmp6_hdr *)p->payload; ip6hdr = (struct ip6_hdr *)((u8_t*)p->payload + sizeof(struct icmp6_hdr)); /* Copy original destination address to current source address, to have an aligned copy. */ ip6_addr_set(ip6_current_src_addr(), &(ip6hdr->dest)); /* Look for entry in destination cache. */ i = nd6_find_destination_cache_entry(ip6_current_src_addr()); if (i < 0) { /* Destination not in cache, drop packet. */ pbuf_free(p); return; } /* Change the Path MTU. */ destination_cache[i].pmtu = icmp6hdr->data; break; /* ICMP6_TYPE_PTB */ } default: ND6_STATS_INC(nd6.proterr); ND6_STATS_INC(nd6.drop); break; /* default */ } pbuf_free(p); } /** * Periodic timer for Neighbor discovery functions: * * - Update neighbor reachability states * - Update destination cache entries age * - Update invalidation timers of default routers and on-link prefixes * - Perform duplicate address detection (DAD) for our addresses * - Send router solicitations */ void nd6_tmr(void) { s8_t i, j; struct netif * netif; /* Process neighbor entries. */ for (i = 0; i < LWIP_ND6_NUM_NEIGHBORS; i++) { switch (neighbor_cache[i].state) { case ND6_INCOMPLETE: if (neighbor_cache[i].counter.probes_sent >= LWIP_ND6_MAX_MULTICAST_SOLICIT) { /* Retries exceeded. */ nd6_free_neighbor_cache_entry(i); } else { /* Send a NS for this entry. */ neighbor_cache[i].counter.probes_sent++; nd6_send_ns(neighbor_cache[i].netif, &(neighbor_cache[i].next_hop_address), ND6_SEND_FLAG_MULTICAST_DEST); } break; case ND6_REACHABLE: /* Send queued packets, if any are left. Should have been sent already. */ if (neighbor_cache[i].q != NULL) { nd6_send_q(i); } if (neighbor_cache[i].counter.reachable_time <= ND6_TMR_INTERVAL) { /* Change to stale state. */ neighbor_cache[i].state = ND6_STALE; neighbor_cache[i].counter.stale_time = 0; } else { neighbor_cache[i].counter.reachable_time -= ND6_TMR_INTERVAL; } break; case ND6_STALE: neighbor_cache[i].counter.stale_time += ND6_TMR_INTERVAL; break; case ND6_DELAY: if (neighbor_cache[i].counter.delay_time <= ND6_TMR_INTERVAL) { /* Change to PROBE state. */ neighbor_cache[i].state = ND6_PROBE; neighbor_cache[i].counter.probes_sent = 0; } else { neighbor_cache[i].counter.delay_time -= ND6_TMR_INTERVAL; } break; case ND6_PROBE: if (neighbor_cache[i].counter.probes_sent >= LWIP_ND6_MAX_MULTICAST_SOLICIT) { /* Retries exceeded. */ nd6_free_neighbor_cache_entry(i); } else { /* Send a NS for this entry. */ neighbor_cache[i].counter.probes_sent++; nd6_send_ns(neighbor_cache[i].netif, &(neighbor_cache[i].next_hop_address), 0); } break; case ND6_NO_ENTRY: default: /* Do nothing. */ break; } } /* Process destination entries. */ for (i = 0; i < LWIP_ND6_NUM_DESTINATIONS; i++) { destination_cache[i].age++; } /* Process router entries. */ for (i = 0; i < LWIP_ND6_NUM_ROUTERS; i++) { if (default_router_list[i].neighbor_entry != NULL) { /* Active entry. */ if (default_router_list[i].invalidation_timer > 0) { default_router_list[i].invalidation_timer -= ND6_TMR_INTERVAL / 1000; } if (default_router_list[i].invalidation_timer < ND6_TMR_INTERVAL / 1000) { /* Less than 1 second remainig. Clear this entry. */ default_router_list[i].neighbor_entry->isrouter = 0; default_router_list[i].neighbor_entry = NULL; default_router_list[i].invalidation_timer = 0; default_router_list[i].flags = 0; } } } /* Process prefix entries. */ for (i = 0; i < LWIP_ND6_NUM_PREFIXES; i++) { if (prefix_list[i].invalidation_timer < ND6_TMR_INTERVAL / 1000) { prefix_list[i].invalidation_timer = 0; } if ((prefix_list[i].invalidation_timer > 0) && (prefix_list[i].netif != NULL)) { prefix_list[i].invalidation_timer -= ND6_TMR_INTERVAL / 1000; #if LWIP_IPV6_AUTOCONFIG /* Initiate address autoconfiguration for this prefix, if conditions are met. */ if (prefix_list[i].netif->ip6_autoconfig_enabled && (prefix_list[i].flags & ND6_PREFIX_AUTOCONFIG_AUTONOMOUS) && !(prefix_list[i].flags & ND6_PREFIX_AUTOCONFIG_ADDRESS_GENERATED)) { /* Try to get an address on this netif that is invalid. * Skip 0 index (link-local address) */ for (j = 1; j < LWIP_IPV6_NUM_ADDRESSES; j++) { if (netif_ip6_addr_state(prefix_list[i].netif, j) == IP6_ADDR_INVALID) { /* Generate an address using this prefix and interface ID from link-local address. */ prefix_list[i].netif->ip6_addr[j].addr[0] = prefix_list[i].prefix.addr[0]; prefix_list[i].netif->ip6_addr[j].addr[1] = prefix_list[i].prefix.addr[1]; prefix_list[i].netif->ip6_addr[j].addr[2] = prefix_list[i].netif->ip6_addr[0].addr[2]; prefix_list[i].netif->ip6_addr[j].addr[3] = prefix_list[i].netif->ip6_addr[0].addr[3]; /* Mark it as tentative (DAD will be performed if configured). */ netif_ip6_addr_set_state(prefix_list[i].netif, j, IP6_ADDR_TENTATIVE); /* Mark this prefix with ADDRESS_GENERATED, so that we don't try again. */ prefix_list[i].flags |= ND6_PREFIX_AUTOCONFIG_ADDRESS_GENERATED; /* Exit loop. */ break; } } } #endif /* LWIP_IPV6_AUTOCONFIG */ } } /* Process our own addresses, if DAD configured. */ for (netif = netif_list; netif != NULL; netif = netif->next) { for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; ++i) { if (ip6_addr_istentative(netif->ip6_addr_state[i])) { if ((netif->ip6_addr_state[i] & 0x07) >= LWIP_IPV6_DUP_DETECT_ATTEMPTS) { /* No NA received in response. Mark address as valid. */ netif->ip6_addr_state[i] = IP6_ADDR_PREFERRED; /* TODO implement preferred and valid lifetimes. */ } else if (netif->flags & NETIF_FLAG_UP) { #if LWIP_IPV6_MLD if ((netif->ip6_addr_state[i] & 0x07) == 0) { /* Join solicited node multicast group. */ ip6_addr_set_solicitednode(&multicast_address, netif_ip6_addr(netif, i)->addr[3]); mld6_joingroup(netif_ip6_addr(netif, i), &multicast_address); } #endif /* LWIP_IPV6_MLD */ /* Send a NS for this address. */ nd6_send_ns(netif, netif_ip6_addr(netif, i), ND6_SEND_FLAG_MULTICAST_DEST); (netif->ip6_addr_state[i])++; /* TODO send max 1 NS per tmr call? enable return*/ /*return;*/ } } } } #if LWIP_IPV6_SEND_ROUTER_SOLICIT /* Send router solicitation messages, if necessary. */ for (netif = netif_list; netif != NULL; netif = netif->next) { if ((netif->rs_count > 0) && (netif->flags & NETIF_FLAG_UP)) { nd6_send_rs(netif); netif->rs_count--; } } #endif /* LWIP_IPV6_SEND_ROUTER_SOLICIT */ } /** * Send a neighbor solicitation message * * @param netif the netif on which to send the message * @param target_addr the IPv6 target address for the ND message * @param flags one of ND6_SEND_FLAG_* */ static void nd6_send_ns(struct netif * netif, ip6_addr_t * target_addr, u8_t flags) { struct ns_header * ns_hdr; struct lladdr_option * lladdr_opt; struct pbuf * p; ip6_addr_t * src_addr; if (ip6_addr_isvalid(netif_ip6_addr_state(netif,0))) { /* Use link-local address as source address. */ src_addr = netif_ip6_addr(netif, 0); } else { src_addr = IP6_ADDR_ANY; } /* Allocate a packet. */ p = pbuf_alloc(PBUF_IP, sizeof(struct ns_header) + sizeof(struct lladdr_option), PBUF_RAM); if ((p == NULL) || (p->len < (sizeof(struct ns_header) + sizeof(struct lladdr_option)))) { /* We couldn't allocate a suitable pbuf for the ns. drop it. */ if (p != NULL) { pbuf_free(p); } ND6_STATS_INC(nd6.memerr); return; } /* Set fields. */ ns_hdr = (struct ns_header *)p->payload; lladdr_opt = (struct lladdr_option *)((u8_t*)p->payload + sizeof(struct ns_header)); ns_hdr->type = ICMP6_TYPE_NS; ns_hdr->code = 0; ns_hdr->chksum = 0; ns_hdr->reserved = 0; ip6_addr_set(&(ns_hdr->target_address), target_addr); lladdr_opt->type = ND6_OPTION_TYPE_SOURCE_LLADDR; lladdr_opt->length = ((netif->hwaddr_len + 2) >> 3) + (((netif->hwaddr_len + 2) & 0x07) ? 1 : 0); SMEMCPY(lladdr_opt->addr, netif->hwaddr, netif->hwaddr_len); /* Generate the solicited node address for the target address. */ if (flags & ND6_SEND_FLAG_MULTICAST_DEST) { ip6_addr_set_solicitednode(&multicast_address, target_addr->addr[3]); target_addr = &multicast_address; } #if CHECKSUM_GEN_ICMP6 ns_hdr->chksum = ip6_chksum_pseudo(p, IP6_NEXTH_ICMP6, p->len, src_addr, target_addr); #endif /* CHECKSUM_GEN_ICMP6 */ /* Send the packet out. */ ND6_STATS_INC(nd6.xmit); ip6_output_if(p, (src_addr == IP6_ADDR_ANY) ? NULL : src_addr, target_addr, LWIP_ICMP6_HL, 0, IP6_NEXTH_ICMP6, netif); pbuf_free(p); } /** * Send a neighbor advertisement message * * @param netif the netif on which to send the message * @param target_addr the IPv6 target address for the ND message * @param flags one of ND6_SEND_FLAG_* */ static void nd6_send_na(struct netif * netif, ip6_addr_t * target_addr, u8_t flags) { struct na_header * na_hdr; struct lladdr_option * lladdr_opt; struct pbuf * p; ip6_addr_t * src_addr; ip6_addr_t * dest_addr; /* Use link-local address as source address. */ /* src_addr = &(netif->ip6_addr[0]); */ /* Use target address as source address. */ src_addr = target_addr; /* Allocate a packet. */ p = pbuf_alloc(PBUF_IP, sizeof(struct na_header) + sizeof(struct lladdr_option), PBUF_RAM); if ((p == NULL) || (p->len < (sizeof(struct na_header) + sizeof(struct lladdr_option)))) { /* We couldn't allocate a suitable pbuf for the ns. drop it. */ if (p != NULL) { pbuf_free(p); } ND6_STATS_INC(nd6.memerr); return; } /* Set fields. */ na_hdr = (struct na_header *)p->payload; lladdr_opt = (struct lladdr_option *)((u8_t*)p->payload + sizeof(struct na_header)); na_hdr->type = ICMP6_TYPE_NA; na_hdr->code = 0; na_hdr->chksum = 0; na_hdr->flags = flags & 0xf0; na_hdr->reserved[0] = 0; na_hdr->reserved[1] = 0; na_hdr->reserved[2] = 0; ip6_addr_set(&(na_hdr->target_address), target_addr); lladdr_opt->type = ND6_OPTION_TYPE_TARGET_LLADDR; lladdr_opt->length = ((netif->hwaddr_len + 2) >> 3) + (((netif->hwaddr_len + 2) & 0x07) ? 1 : 0); SMEMCPY(lladdr_opt->addr, netif->hwaddr, netif->hwaddr_len); /* Generate the solicited node address for the target address. */ if (flags & ND6_SEND_FLAG_MULTICAST_DEST) { ip6_addr_set_solicitednode(&multicast_address, target_addr->addr[3]); dest_addr = &multicast_address; } else if (flags & ND6_SEND_FLAG_ALLNODES_DEST) { ip6_addr_set_allnodes_linklocal(&multicast_address); dest_addr = &multicast_address; } else { dest_addr = ip6_current_src_addr(); } #if CHECKSUM_GEN_ICMP6 na_hdr->chksum = ip6_chksum_pseudo(p, IP6_NEXTH_ICMP6, p->len, src_addr, dest_addr); #endif /* CHECKSUM_GEN_ICMP6 */ /* Send the packet out. */ ND6_STATS_INC(nd6.xmit); ip6_output_if(p, src_addr, dest_addr, LWIP_ICMP6_HL, 0, IP6_NEXTH_ICMP6, netif); pbuf_free(p); } #if LWIP_IPV6_SEND_ROUTER_SOLICIT /** * Send a router solicitation message * * @param netif the netif on which to send the message */ static void nd6_send_rs(struct netif * netif) { struct rs_header * rs_hdr; struct lladdr_option * lladdr_opt; struct pbuf * p; ip6_addr_t * src_addr; u16_t packet_len; /* Link-local source address, or unspecified address? */ if (ip6_addr_isvalid(netif_ip6_addr_state(netif, 0))) { src_addr = netif_ip6_addr(netif, 0); } else { src_addr = IP6_ADDR_ANY; } /* Generate the all routers target address. */ ip6_addr_set_allrouters_linklocal(&multicast_address); /* Allocate a packet. */ packet_len = sizeof(struct rs_header); if (src_addr != IP6_ADDR_ANY) { packet_len += sizeof(struct lladdr_option); } p = pbuf_alloc(PBUF_IP, packet_len, PBUF_RAM); if ((p == NULL) || (p->len < packet_len)) { /* We couldn't allocate a suitable pbuf for the ns. drop it. */ if (p != NULL) { pbuf_free(p); } ND6_STATS_INC(nd6.memerr); return; } /* Set fields. */ rs_hdr = (struct rs_header *)p->payload; rs_hdr->type = ICMP6_TYPE_RS; rs_hdr->code = 0; rs_hdr->chksum = 0; rs_hdr->reserved = 0; if (src_addr != IP6_ADDR_ANY) { /* Include our hw address. */ lladdr_opt = (struct lladdr_option *)((u8_t*)p->payload + sizeof(struct rs_header)); lladdr_opt->type = ND6_OPTION_TYPE_SOURCE_LLADDR; lladdr_opt->length = ((netif->hwaddr_len + 2) >> 3) + (((netif->hwaddr_len + 2) & 0x07) ? 1 : 0); SMEMCPY(lladdr_opt->addr, netif->hwaddr, netif->hwaddr_len); } #if CHECKSUM_GEN_ICMP6 rs_hdr->chksum = ip6_chksum_pseudo(p, IP6_NEXTH_ICMP6, p->len, src_addr, &multicast_address); #endif /* CHECKSUM_GEN_ICMP6 */ /* Send the packet out. */ ND6_STATS_INC(nd6.xmit); ip6_output_if(p, src_addr, &multicast_address, LWIP_ICMP6_HL, 0, IP6_NEXTH_ICMP6, netif); pbuf_free(p); } #endif /* LWIP_IPV6_SEND_ROUTER_SOLICIT */ /** * Search for a neighbor cache entry * * @param ip6addr the IPv6 address of the neighbor * @return The neighbor cache entry index that matched, -1 if no * entry is found */ static s8_t nd6_find_neighbor_cache_entry(ip6_addr_t * ip6addr) { s8_t i; for (i = 0; i < LWIP_ND6_NUM_NEIGHBORS; i++) { if (ip6_addr_cmp(ip6addr, &(neighbor_cache[i].next_hop_address))) { return i; } } return -1; } /** * Create a new neighbor cache entry. * * If no unused entry is found, will try to recycle an old entry * according to ad-hoc "age" heuristic. * * @return The neighbor cache entry index that was created, -1 if no * entry could be created */ static s8_t nd6_new_neighbor_cache_entry(void) { s8_t i; s8_t j; u32_t time; /* First, try to find an empty entry. */ for (i = 0; i < LWIP_ND6_NUM_NEIGHBORS; i++) { if (neighbor_cache[i].state == ND6_NO_ENTRY) { return i; } } /* We need to recycle an entry. in general, do not recycle if it is a router. */ /* Next, try to find a Stale entry. */ for (i = 0; i < LWIP_ND6_NUM_NEIGHBORS; i++) { if ((neighbor_cache[i].state == ND6_STALE) && (!neighbor_cache[i].isrouter)) { nd6_free_neighbor_cache_entry(i); return i; } } /* Next, try to find a Probe entry. */ for (i = 0; i < LWIP_ND6_NUM_NEIGHBORS; i++) { if ((neighbor_cache[i].state == ND6_PROBE) && (!neighbor_cache[i].isrouter)) { nd6_free_neighbor_cache_entry(i); return i; } } /* Next, try to find a Delayed entry. */ for (i = 0; i < LWIP_ND6_NUM_NEIGHBORS; i++) { if ((neighbor_cache[i].state == ND6_DELAY) && (!neighbor_cache[i].isrouter)) { nd6_free_neighbor_cache_entry(i); return i; } } /* Next, try to find the oldest reachable entry. */ time = 0xfffffffful; j = -1; for (i = 0; i < LWIP_ND6_NUM_NEIGHBORS; i++) { if ((neighbor_cache[i].state == ND6_REACHABLE) && (!neighbor_cache[i].isrouter)) { if (neighbor_cache[i].counter.reachable_time < time) { j = i; time = neighbor_cache[i].counter.reachable_time; } } } if (j >= 0) { nd6_free_neighbor_cache_entry(j); return j; } /* Next, find oldest incomplete entry without queued packets. */ time = 0; j = -1; for (i = 0; i < LWIP_ND6_NUM_NEIGHBORS; i++) { if ( (neighbor_cache[i].q == NULL) && (neighbor_cache[i].state == ND6_INCOMPLETE) && (!neighbor_cache[i].isrouter)) { if (neighbor_cache[i].counter.probes_sent >= time) { j = i; time = neighbor_cache[i].counter.probes_sent; } } } if (j >= 0) { nd6_free_neighbor_cache_entry(j); return j; } /* Next, find oldest incomplete entry with queued packets. */ time = 0; j = -1; for (i = 0; i < LWIP_ND6_NUM_NEIGHBORS; i++) { if ((neighbor_cache[i].state == ND6_INCOMPLETE) && (!neighbor_cache[i].isrouter)) { if (neighbor_cache[i].counter.probes_sent >= time) { j = i; time = neighbor_cache[i].counter.probes_sent; } } } if (j >= 0) { nd6_free_neighbor_cache_entry(j); return j; } /* No more entries to try. */ return -1; } /** * Will free any resources associated with a neighbor cache * entry, and will mark it as unused. * * @param i the neighbor cache entry index to free */ static void nd6_free_neighbor_cache_entry(s8_t i) { if ((i < 0) || (i >= LWIP_ND6_NUM_NEIGHBORS)) { return; } /* Free any queued packets. */ if (neighbor_cache[i].q != NULL) { nd6_free_q(neighbor_cache[i].q); neighbor_cache[i].q = NULL; } neighbor_cache[i].state = ND6_NO_ENTRY; neighbor_cache[i].isrouter = 0; neighbor_cache[i].netif = NULL; neighbor_cache[i].counter.reachable_time = 0; ip6_addr_set_zero(&(neighbor_cache[i].next_hop_address)); } /** * Search for a destination cache entry * * @param ip6addr the IPv6 address of the destination * @return The destination cache entry index that matched, -1 if no * entry is found */ static s8_t nd6_find_destination_cache_entry(ip6_addr_t * ip6addr) { s8_t i; for (i = 0; i < LWIP_ND6_NUM_DESTINATIONS; i++) { if (ip6_addr_cmp(ip6addr, &(destination_cache[i].destination_addr))) { return i; } } return -1; } /** * Create a new destination cache entry. If no unused entry is found, * will recycle oldest entry. * * @return The destination cache entry index that was created, -1 if no * entry was created */ static s8_t nd6_new_destination_cache_entry(void) { s8_t i, j; u32_t age; /* Find an empty entry. */ for (i = 0; i < LWIP_ND6_NUM_DESTINATIONS; i++) { if (ip6_addr_isany(&(destination_cache[i].destination_addr))) { return i; } } /* Find oldest entry. */ age = 0; j = LWIP_ND6_NUM_DESTINATIONS - 1; for (i = 0; i < LWIP_ND6_NUM_DESTINATIONS; i++) { if (destination_cache[i].age > age) { j = i; } } return j; } /** * Determine whether an address matches an on-link prefix. * * @param ip6addr the IPv6 address to match * @return 1 if the address is on-link, 0 otherwise */ static s8_t nd6_is_prefix_in_netif(ip6_addr_t * ip6addr, struct netif * netif) { s8_t i; for (i = 0; i < LWIP_ND6_NUM_PREFIXES; i++) { if ((prefix_list[i].netif == netif) && (prefix_list[i].invalidation_timer > 0) && ip6_addr_netcmp(ip6addr, &(prefix_list[i].prefix))) { return 1; } } /* Check to see if address prefix matches a (manually?) configured address. */ for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i)) && ip6_addr_netcmp(ip6addr, netif_ip6_addr(netif, i))) { return 1; } } return 0; } /** * Select a default router for a destination. * * @param ip6addr the destination address * @param netif the netif for the outgoing packet, if known * @return the default router entry index, or -1 if no suitable * router is found */ s8_t nd6_select_router(ip6_addr_t * ip6addr, struct netif * netif) { s8_t i; /* last_router is used for round-robin router selection (as recommended * in RFC). This is more robust in case one router is not reachable, * we are not stuck trying to resolve it. */ static s8_t last_router; (void)ip6addr; /* TODO match preferred routes!! (must implement ND6_OPTION_TYPE_ROUTE_INFO) */ /* TODO: implement default router preference */ /* Look for reachable routers. */ for (i = 0; i < LWIP_ND6_NUM_ROUTERS; i++) { if (++last_router >= LWIP_ND6_NUM_ROUTERS) { last_router = 0; } if ((default_router_list[i].neighbor_entry != NULL) && (netif != NULL ? netif == default_router_list[i].neighbor_entry->netif : 1) && (default_router_list[i].invalidation_timer > 0) && (default_router_list[i].neighbor_entry->state == ND6_REACHABLE)) { return i; } } /* Look for router in other reachability states, but still valid according to timer. */ for (i = 0; i < LWIP_ND6_NUM_ROUTERS; i++) { if (++last_router >= LWIP_ND6_NUM_ROUTERS) { last_router = 0; } if ((default_router_list[i].neighbor_entry != NULL) && (netif != NULL ? netif == default_router_list[i].neighbor_entry->netif : 1) && (default_router_list[i].invalidation_timer > 0)) { return i; } } /* Look for any router for which we have any information at all. */ for (i = 0; i < LWIP_ND6_NUM_ROUTERS; i++) { if (++last_router >= LWIP_ND6_NUM_ROUTERS) { last_router = 0; } if (default_router_list[i].neighbor_entry != NULL && (netif != NULL ? netif == default_router_list[i].neighbor_entry->netif : 1)) { return i; } } /* no suitable router found. */ return -1; } /** * Find an entry for a default router. * * @param router_addr the IPv6 address of the router * @param netif the netif on which the router is found, if known * @return the index of the router entry, or -1 if not found */ static s8_t nd6_get_router(ip6_addr_t * router_addr, struct netif * netif) { s8_t i; /* Look for router. */ for (i = 0; i < LWIP_ND6_NUM_ROUTERS; i++) { if ((default_router_list[i].neighbor_entry != NULL) && ((netif != NULL) ? netif == default_router_list[i].neighbor_entry->netif : 1) && ip6_addr_cmp(router_addr, &(default_router_list[i].neighbor_entry->next_hop_address))) { return i; } } /* router not found. */ return -1; } /** * Create a new entry for a default router. * * @param router_addr the IPv6 address of the router * @param netif the netif on which the router is connected, if known * @return the index on the router table, or -1 if could not be created */ static s8_t nd6_new_router(ip6_addr_t * router_addr, struct netif * netif) { s8_t router_index; s8_t neighbor_index; /* Do we have a neighbor entry for this router? */ neighbor_index = nd6_find_neighbor_cache_entry(router_addr); if (neighbor_index < 0) { /* Create a neighbor entry for this router. */ neighbor_index = nd6_new_neighbor_cache_entry(); if (neighbor_index < 0) { /* Could not create neighbor entry for this router. */ return -1; } ip6_addr_set(&(neighbor_cache[neighbor_index].next_hop_address), router_addr); neighbor_cache[neighbor_index].netif = netif; neighbor_cache[neighbor_index].q = NULL; neighbor_cache[neighbor_index].state = ND6_INCOMPLETE; neighbor_cache[neighbor_index].counter.probes_sent = 0; } /* Mark neighbor as router. */ neighbor_cache[neighbor_index].isrouter = 1; /* Look for empty entry. */ for (router_index = 0; router_index < LWIP_ND6_NUM_ROUTERS; router_index++) { if (default_router_list[router_index].neighbor_entry == NULL) { default_router_list[router_index].neighbor_entry = &(neighbor_cache[neighbor_index]); return router_index; } } /* Could not create a router entry. */ /* Mark neighbor entry as not-router. Entry might be useful as neighbor still. */ neighbor_cache[neighbor_index].isrouter = 0; /* router not found. */ return -1; } /** * Find the cached entry for an on-link prefix. * * @param prefix the IPv6 prefix that is on-link * @param netif the netif on which the prefix is on-link * @return the index on the prefix table, or -1 if not found */ static s8_t nd6_get_onlink_prefix(ip6_addr_t * prefix, struct netif * netif) { s8_t i; /* Look for prefix in list. */ for (i = 0; i < LWIP_ND6_NUM_PREFIXES; ++i) { if ((ip6_addr_netcmp(&(prefix_list[i].prefix), prefix)) && (prefix_list[i].netif == netif)) { return i; } } /* Entry not available. */ return -1; } /** * Creates a new entry for an on-link prefix. * * @param prefix the IPv6 prefix that is on-link * @param netif the netif on which the prefix is on-link * @return the index on the prefix table, or -1 if not created */ static s8_t nd6_new_onlink_prefix(ip6_addr_t * prefix, struct netif * netif) { s8_t i; /* Create new entry. */ for (i = 0; i < LWIP_ND6_NUM_PREFIXES; ++i) { if ((prefix_list[i].netif == NULL) || (prefix_list[i].invalidation_timer == 0)) { /* Found empty prefix entry. */ prefix_list[i].netif = netif; ip6_addr_set(&(prefix_list[i].prefix), prefix); prefix_list[i].flags = 0; return i; } } /* Entry not available. */ return -1; } /** * Determine the next hop for a destination. Will determine if the * destination is on-link, else a suitable on-link router is selected. * * The last entry index is cached for fast entry search. * * @param ip6addr the destination address * @param netif the netif on which the packet will be sent * @return the neighbor cache entry for the next hop, ERR_RTE if no * suitable next hop was found, ERR_MEM if no cache entry * could be created */ s8_t nd6_get_next_hop_entry(ip6_addr_t * ip6addr, struct netif * netif) { s8_t i; #if LWIP_NETIF_HWADDRHINT if (netif->addr_hint != NULL) { /* per-pcb cached entry was given */ u8_t addr_hint = *(netif->addr_hint); if (addr_hint < LWIP_ND6_NUM_DESTINATIONS) { nd6_cached_destination_index = addr_hint; } } #endif /* LWIP_NETIF_HWADDRHINT */ /* Look for ip6addr in destination cache. */ if (ip6_addr_cmp(ip6addr, &(destination_cache[nd6_cached_destination_index].destination_addr))) { /* the cached entry index is the right one! */ /* do nothing. */ ND6_STATS_INC(nd6.cachehit); } else { /* Search destination cache. */ i = nd6_find_destination_cache_entry(ip6addr); if (i >= 0) { /* found destination entry. make it our new cached index. */ nd6_cached_destination_index = i; } else { /* Not found. Create a new destination entry. */ i = nd6_new_destination_cache_entry(); if (i >= 0) { /* got new destination entry. make it our new cached index. */ nd6_cached_destination_index = i; } else { /* Could not create a destination cache entry. */ return ERR_MEM; } /* Copy dest address to destination cache. */ ip6_addr_set(&(destination_cache[nd6_cached_destination_index].destination_addr), ip6addr); /* Now find the next hop. is it a neighbor? */ if (ip6_addr_islinklocal(ip6addr) || nd6_is_prefix_in_netif(ip6addr, netif)) { /* Destination in local link. */ destination_cache[nd6_cached_destination_index].pmtu = netif->mtu; ip6_addr_copy(destination_cache[nd6_cached_destination_index].next_hop_addr, destination_cache[nd6_cached_destination_index].destination_addr); } else { /* We need to select a router. */ i = nd6_select_router(ip6addr, netif); if (i < 0) { /* No router found. */ ip6_addr_set_any(&(destination_cache[nd6_cached_destination_index].destination_addr)); return ERR_RTE; } destination_cache[nd6_cached_destination_index].pmtu = netif->mtu; /* Start with netif mtu, correct through ICMPv6 if necessary */ ip6_addr_copy(destination_cache[nd6_cached_destination_index].next_hop_addr, default_router_list[i].neighbor_entry->next_hop_address); } } } #if LWIP_NETIF_HWADDRHINT if (netif->addr_hint != NULL) { /* per-pcb cached entry was given */ *(netif->addr_hint) = nd6_cached_destination_index; } #endif /* LWIP_NETIF_HWADDRHINT */ /* Look in neighbor cache for the next-hop address. */ if (ip6_addr_cmp(&(destination_cache[nd6_cached_destination_index].next_hop_addr), &(neighbor_cache[nd6_cached_neighbor_index].next_hop_address))) { /* Cache hit. */ /* Do nothing. */ ND6_STATS_INC(nd6.cachehit); } else { i = nd6_find_neighbor_cache_entry(&(destination_cache[nd6_cached_destination_index].next_hop_addr)); if (i >= 0) { /* Found a matching record, make it new cached entry. */ nd6_cached_neighbor_index = i; } else { /* Neighbor not in cache. Make a new entry. */ i = nd6_new_neighbor_cache_entry(); if (i >= 0) { /* got new neighbor entry. make it our new cached index. */ nd6_cached_neighbor_index = i; } else { /* Could not create a neighbor cache entry. */ return ERR_MEM; } /* Initialize fields. */ ip6_addr_copy(neighbor_cache[i].next_hop_address, destination_cache[nd6_cached_destination_index].next_hop_addr); neighbor_cache[i].isrouter = 0; neighbor_cache[i].netif = netif; neighbor_cache[i].state = ND6_INCOMPLETE; neighbor_cache[i].counter.probes_sent = 0; } } /* Reset this destination's age. */ destination_cache[nd6_cached_destination_index].age = 0; return nd6_cached_neighbor_index; } /** * Queue a packet for a neighbor. * * @param neighbor_index the index in the neighbor cache table * @param q packet to be queued * @return ERR_OK if succeeded, ERR_MEM if out of memory */ err_t nd6_queue_packet(s8_t neighbor_index, struct pbuf * q) { err_t result = ERR_MEM; struct pbuf *p; int copy_needed = 0; #if LWIP_ND6_QUEUEING struct nd6_q_entry *new_entry, *r; #endif /* LWIP_ND6_QUEUEING */ if ((neighbor_index < 0) || (neighbor_index >= LWIP_ND6_NUM_NEIGHBORS)) { return ERR_ARG; } /* IF q includes a PBUF_REF, PBUF_POOL or PBUF_RAM, we have no choice but * to copy the whole queue into a new PBUF_RAM (see bug #11400) * PBUF_ROMs can be left as they are, since ROM must not get changed. */ p = q; while (p) { if(p->type != PBUF_ROM) { copy_needed = 1; break; } p = p->next; } if(copy_needed) { /* copy the whole packet into new pbufs */ p = pbuf_alloc(PBUF_LINK, q->tot_len, PBUF_RAM); while ((p == NULL) && (neighbor_cache[neighbor_index].q != NULL)) { /* Free oldest packet (as per RFC recommendation) */ #if LWIP_ND6_QUEUEING r = neighbor_cache[neighbor_index].q; neighbor_cache[neighbor_index].q = r->next; r->next = NULL; nd6_free_q(r); #else /* LWIP_ND6_QUEUEING */ pbuf_free(neighbor_cache[neighbor_index].q); neighbor_cache[neighbor_index].q = NULL; #endif /* LWIP_ND6_QUEUEING */ p = pbuf_alloc(PBUF_LINK, q->tot_len, PBUF_RAM); } if(p != NULL) { if (pbuf_copy(p, q) != ERR_OK) { pbuf_free(p); p = NULL; } } } else { /* referencing the old pbuf is enough */ p = q; pbuf_ref(p); } /* packet was copied/ref'd? */ if (p != NULL) { /* queue packet ... */ #if LWIP_ND6_QUEUEING /* allocate a new nd6 queue entry */ new_entry = (struct nd6_q_entry *)memp_malloc(MEMP_ND6_QUEUE); if ((new_entry == NULL) && (neighbor_cache[neighbor_index].q != NULL)) { /* Free oldest packet (as per RFC recommendation) */ r = neighbor_cache[neighbor_index].q; neighbor_cache[neighbor_index].q = r->next; r->next = NULL; nd6_free_q(r); new_entry = (struct nd6_q_entry *)memp_malloc(MEMP_ND6_QUEUE); } if (new_entry != NULL) { new_entry->next = NULL; new_entry->p = p; if(neighbor_cache[neighbor_index].q != NULL) { /* queue was already existent, append the new entry to the end */ r = neighbor_cache[neighbor_index].q; while (r->next != NULL) { r = r->next; } r->next = new_entry; } else { /* queue did not exist, first item in queue */ neighbor_cache[neighbor_index].q = new_entry; } LWIP_DEBUGF(LWIP_DBG_TRACE, ("ipv6: queued packet %p on neighbor entry %"S16_F"\n", (void *)p, (s16_t)neighbor_index)); result = ERR_OK; } else { /* the pool MEMP_ND6_QUEUE is empty */ pbuf_free(p); LWIP_DEBUGF(LWIP_DBG_TRACE, ("ipv6: could not queue a copy of packet %p (out of memory)\n", (void *)p)); /* { result == ERR_MEM } through initialization */ } #else /* LWIP_ND6_QUEUEING */ /* Queue a single packet. If an older packet is already queued, free it as per RFC. */ if (neighbor_cache[neighbor_index].q != NULL) { pbuf_free(neighbor_cache[neighbor_index].q); } neighbor_cache[neighbor_index].q = p; LWIP_DEBUGF(LWIP_DBG_TRACE, ("ipv6: queued packet %p on neighbor entry %"S16_F"\n", (void *)p, (s16_t)neighbor_index)); result = ERR_OK; #endif /* LWIP_ND6_QUEUEING */ } else { LWIP_DEBUGF(LWIP_DBG_TRACE, ("ipv6: could not queue a copy of packet %p (out of memory)\n", (void *)q)); /* { result == ERR_MEM } through initialization */ } return result; } #if LWIP_ND6_QUEUEING /** * Free a complete queue of nd6 q entries * * @param q a queue of nd6_q_entry to free */ static void nd6_free_q(struct nd6_q_entry *q) { struct nd6_q_entry *r; LWIP_ASSERT("q != NULL", q != NULL); LWIP_ASSERT("q->p != NULL", q->p != NULL); while (q) { r = q; q = q->next; LWIP_ASSERT("r->p != NULL", (r->p != NULL)); pbuf_free(r->p); memp_free(MEMP_ND6_QUEUE, r); } } #endif /* LWIP_ND6_QUEUEING */ /** * Send queued packets for a neighbor * * @param i the neighbor to send packets to */ static void nd6_send_q(s8_t i) { struct ip6_hdr *ip6hdr; #if LWIP_ND6_QUEUEING struct nd6_q_entry *q; #endif /* LWIP_ND6_QUEUEING */ if ((i < 0) || (i >= LWIP_ND6_NUM_NEIGHBORS)) { return; } #if LWIP_ND6_QUEUEING while (neighbor_cache[i].q != NULL) { /* remember first in queue */ q = neighbor_cache[i].q; /* pop first item off the queue */ neighbor_cache[i].q = q->next; /* Get ipv6 header. */ ip6hdr = (struct ip6_hdr *)(q->p->payload); /* Override ip6_current_dest_addr() so that we have an aligned copy. */ ip6_addr_set(ip6_current_dest_addr(), &(ip6hdr->dest)); /* send the queued IPv6 packet */ (neighbor_cache[i].netif)->output_ip6(neighbor_cache[i].netif, q->p, ip6_current_dest_addr()); /* free the queued IP packet */ pbuf_free(q->p); /* now queue entry can be freed */ memp_free(MEMP_ND6_QUEUE, q); } #else /* LWIP_ND6_QUEUEING */ if (neighbor_cache[i].q != NULL) { /* Get ipv6 header. */ ip6hdr = (struct ip6_hdr *)(neighbor_cache[i].q->payload); /* Override ip6_current_dest_addr() so that we have an aligned copy. */ ip6_addr_set(ip6_current_dest_addr(), &(ip6hdr->dest)); /* send the queued IPv6 packet */ (neighbor_cache[i].netif)->output_ip6(neighbor_cache[i].netif, neighbor_cache[i].q, ip6_current_dest_addr()); /* free the queued IP packet */ pbuf_free(neighbor_cache[i].q); neighbor_cache[i].q = NULL; } #endif /* LWIP_ND6_QUEUEING */ } /** * Get the Path MTU for a destination. * * @param ip6addr the destination address * @param netif the netif on which the packet will be sent * @return the Path MTU, if known, or the netif default MTU */ u16_t nd6_get_destination_mtu(ip6_addr_t * ip6addr, struct netif * netif) { s8_t i; i = nd6_find_destination_cache_entry(ip6addr); if (i >= 0) { if (destination_cache[i].pmtu > 0) { return destination_cache[i].pmtu; } } if (netif != NULL) { return netif->mtu; } return 1280; /* Minimum MTU */ } #if LWIP_ND6_TCP_REACHABILITY_HINTS /** * Provide the Neighbor discovery process with a hint that a * destination is reachable. Called by tcp_receive when ACKs are * received or sent (as per RFC). This is useful to avoid sending * NS messages every 30 seconds. * * @param ip6addr the destination address which is know to be reachable * by an upper layer protocol (TCP) */ void nd6_reachability_hint(ip6_addr_t * ip6addr) { s8_t i; /* Find destination in cache. */ if (ip6_addr_cmp(ip6addr, &(destination_cache[nd6_cached_destination_index].destination_addr))) { i = nd6_cached_destination_index; ND6_STATS_INC(nd6.cachehit); } else { i = nd6_find_destination_cache_entry(ip6addr); } if (i < 0) { return; } /* Find next hop neighbor in cache. */ if (ip6_addr_cmp(&(destination_cache[i].next_hop_addr), &(neighbor_cache[nd6_cached_neighbor_index].next_hop_address))) { i = nd6_cached_neighbor_index; ND6_STATS_INC(nd6.cachehit); } else { i = nd6_find_neighbor_cache_entry(&(destination_cache[i].next_hop_addr)); } if (i < 0) { return; } /* Set reachability state. */ neighbor_cache[i].state = ND6_REACHABLE; neighbor_cache[i].counter.reachable_time = reachable_time; } #endif /* LWIP_ND6_TCP_REACHABILITY_HINTS */ #endif /* LWIP_IPV6 */ ocproxy-1.60/lwip/src/core/mem.c000066400000000000000000000557141303453231400165710ustar00rootroot00000000000000/** * @file * Dynamic memory manager * * This is a lightweight replacement for the standard C library malloc(). * * If you want to use the standard C library malloc() instead, define * MEM_LIBC_MALLOC to 1 in your lwipopts.h * * To let mem_malloc() use pools (prevents fragmentation and is much faster than * a heap but might waste some memory), define MEM_USE_POOLS to 1, define * MEM_USE_CUSTOM_POOLS to 1 and create a file "lwippools.h" that includes a list * of pools like this (more pools can be added between _START and _END): * * Define three pools with sizes 256, 512, and 1512 bytes * LWIP_MALLOC_MEMPOOL_START * LWIP_MALLOC_MEMPOOL(20, 256) * LWIP_MALLOC_MEMPOOL(10, 512) * LWIP_MALLOC_MEMPOOL(5, 1512) * LWIP_MALLOC_MEMPOOL_END */ /* * Copyright (c) 2001-2004 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * Simon Goldschmidt * */ #include "lwip/opt.h" #if !MEM_LIBC_MALLOC /* don't build if not configured for use in lwipopts.h */ #include "lwip/def.h" #include "lwip/mem.h" #include "lwip/sys.h" #include "lwip/stats.h" #include "lwip/err.h" #include #if MEM_USE_POOLS /* lwIP head implemented with different sized pools */ /** * Allocate memory: determine the smallest pool that is big enough * to contain an element of 'size' and get an element from that pool. * * @param size the size in bytes of the memory needed * @return a pointer to the allocated memory or NULL if the pool is empty */ void * mem_malloc(mem_size_t size) { void *ret; struct memp_malloc_helper *element; memp_t poolnr; mem_size_t required_size = size + LWIP_MEM_ALIGN_SIZE(sizeof(struct memp_malloc_helper)); for (poolnr = MEMP_POOL_FIRST; poolnr <= MEMP_POOL_LAST; poolnr = (memp_t)(poolnr + 1)) { #if MEM_USE_POOLS_TRY_BIGGER_POOL again: #endif /* MEM_USE_POOLS_TRY_BIGGER_POOL */ /* is this pool big enough to hold an element of the required size plus a struct memp_malloc_helper that saves the pool this element came from? */ if (required_size <= memp_sizes[poolnr]) { break; } } if (poolnr > MEMP_POOL_LAST) { LWIP_ASSERT("mem_malloc(): no pool is that big!", 0); return NULL; } element = (struct memp_malloc_helper*)memp_malloc(poolnr); if (element == NULL) { /* No need to DEBUGF or ASSERT: This error is already taken care of in memp.c */ #if MEM_USE_POOLS_TRY_BIGGER_POOL /** Try a bigger pool if this one is empty! */ if (poolnr < MEMP_POOL_LAST) { poolnr++; goto again; } #endif /* MEM_USE_POOLS_TRY_BIGGER_POOL */ return NULL; } /* save the pool number this element came from */ element->poolnr = poolnr; /* and return a pointer to the memory directly after the struct memp_malloc_helper */ ret = (u8_t*)element + LWIP_MEM_ALIGN_SIZE(sizeof(struct memp_malloc_helper)); return ret; } /** * Free memory previously allocated by mem_malloc. Loads the pool number * and calls memp_free with that pool number to put the element back into * its pool * * @param rmem the memory element to free */ void mem_free(void *rmem) { struct memp_malloc_helper *hmem; LWIP_ASSERT("rmem != NULL", (rmem != NULL)); LWIP_ASSERT("rmem == MEM_ALIGN(rmem)", (rmem == LWIP_MEM_ALIGN(rmem))); /* get the original struct memp_malloc_helper */ hmem = (struct memp_malloc_helper*)(void*)((u8_t*)rmem - LWIP_MEM_ALIGN_SIZE(sizeof(struct memp_malloc_helper))); LWIP_ASSERT("hmem != NULL", (hmem != NULL)); LWIP_ASSERT("hmem == MEM_ALIGN(hmem)", (hmem == LWIP_MEM_ALIGN(hmem))); LWIP_ASSERT("hmem->poolnr < MEMP_MAX", (hmem->poolnr < MEMP_MAX)); /* and put it in the pool we saved earlier */ memp_free(hmem->poolnr, hmem); } #else /* MEM_USE_POOLS */ /* lwIP replacement for your libc malloc() */ /** * The heap is made up as a list of structs of this type. * This does not have to be aligned since for getting its size, * we only use the macro SIZEOF_STRUCT_MEM, which automatically alignes. */ struct mem { /** index (-> ram[next]) of the next struct */ mem_size_t next; /** index (-> ram[prev]) of the previous struct */ mem_size_t prev; /** 1: this area is used; 0: this area is unused */ u8_t used; }; /** All allocated blocks will be MIN_SIZE bytes big, at least! * MIN_SIZE can be overridden to suit your needs. Smaller values save space, * larger values could prevent too small blocks to fragment the RAM too much. */ #ifndef MIN_SIZE #define MIN_SIZE 12 #endif /* MIN_SIZE */ /* some alignment macros: we define them here for better source code layout */ #define MIN_SIZE_ALIGNED LWIP_MEM_ALIGN_SIZE(MIN_SIZE) #define SIZEOF_STRUCT_MEM LWIP_MEM_ALIGN_SIZE(sizeof(struct mem)) #define MEM_SIZE_ALIGNED LWIP_MEM_ALIGN_SIZE(MEM_SIZE) /** If you want to relocate the heap to external memory, simply define * LWIP_RAM_HEAP_POINTER as a void-pointer to that location. * If so, make sure the memory at that location is big enough (see below on * how that space is calculated). */ #ifndef LWIP_RAM_HEAP_POINTER /** the heap. we need one struct mem at the end and some room for alignment */ u8_t ram_heap[MEM_SIZE_ALIGNED + (2*SIZEOF_STRUCT_MEM) + MEM_ALIGNMENT]; #define LWIP_RAM_HEAP_POINTER ram_heap #endif /* LWIP_RAM_HEAP_POINTER */ /** pointer to the heap (ram_heap): for alignment, ram is now a pointer instead of an array */ static u8_t *ram; /** the last entry, always unused! */ static struct mem *ram_end; /** pointer to the lowest free block, this is used for faster search */ static struct mem *lfree; /** concurrent access protection */ #if !NO_SYS static sys_mutex_t mem_mutex; #endif #if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT static volatile u8_t mem_free_count; /* Allow mem_free from other (e.g. interrupt) context */ #define LWIP_MEM_FREE_DECL_PROTECT() SYS_ARCH_DECL_PROTECT(lev_free) #define LWIP_MEM_FREE_PROTECT() SYS_ARCH_PROTECT(lev_free) #define LWIP_MEM_FREE_UNPROTECT() SYS_ARCH_UNPROTECT(lev_free) #define LWIP_MEM_ALLOC_DECL_PROTECT() SYS_ARCH_DECL_PROTECT(lev_alloc) #define LWIP_MEM_ALLOC_PROTECT() SYS_ARCH_PROTECT(lev_alloc) #define LWIP_MEM_ALLOC_UNPROTECT() SYS_ARCH_UNPROTECT(lev_alloc) #else /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ /* Protect the heap only by using a semaphore */ #define LWIP_MEM_FREE_DECL_PROTECT() #define LWIP_MEM_FREE_PROTECT() sys_mutex_lock(&mem_mutex) #define LWIP_MEM_FREE_UNPROTECT() sys_mutex_unlock(&mem_mutex) /* mem_malloc is protected using semaphore AND LWIP_MEM_ALLOC_PROTECT */ #define LWIP_MEM_ALLOC_DECL_PROTECT() #define LWIP_MEM_ALLOC_PROTECT() #define LWIP_MEM_ALLOC_UNPROTECT() #endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ /** * "Plug holes" by combining adjacent empty struct mems. * After this function is through, there should not exist * one empty struct mem pointing to another empty struct mem. * * @param mem this points to a struct mem which just has been freed * @internal this function is only called by mem_free() and mem_trim() * * This assumes access to the heap is protected by the calling function * already. */ static void plug_holes(struct mem *mem) { struct mem *nmem; struct mem *pmem; LWIP_ASSERT("plug_holes: mem >= ram", (u8_t *)mem >= ram); LWIP_ASSERT("plug_holes: mem < ram_end", (u8_t *)mem < (u8_t *)ram_end); LWIP_ASSERT("plug_holes: mem->used == 0", mem->used == 0); /* plug hole forward */ LWIP_ASSERT("plug_holes: mem->next <= MEM_SIZE_ALIGNED", mem->next <= MEM_SIZE_ALIGNED); nmem = (struct mem *)(void *)&ram[mem->next]; if (mem != nmem && nmem->used == 0 && (u8_t *)nmem != (u8_t *)ram_end) { /* if mem->next is unused and not end of ram, combine mem and mem->next */ if (lfree == nmem) { lfree = mem; } mem->next = nmem->next; ((struct mem *)(void *)&ram[nmem->next])->prev = (mem_size_t)((u8_t *)mem - ram); } /* plug hole backward */ pmem = (struct mem *)(void *)&ram[mem->prev]; if (pmem != mem && pmem->used == 0) { /* if mem->prev is unused, combine mem and mem->prev */ if (lfree == mem) { lfree = pmem; } pmem->next = mem->next; ((struct mem *)(void *)&ram[mem->next])->prev = (mem_size_t)((u8_t *)pmem - ram); } } /** * Zero the heap and initialize start, end and lowest-free */ void mem_init(void) { struct mem *mem; LWIP_ASSERT("Sanity check alignment", (SIZEOF_STRUCT_MEM & (MEM_ALIGNMENT-1)) == 0); /* align the heap */ ram = (u8_t *)LWIP_MEM_ALIGN(LWIP_RAM_HEAP_POINTER); /* initialize the start of the heap */ mem = (struct mem *)(void *)ram; mem->next = MEM_SIZE_ALIGNED; mem->prev = 0; mem->used = 0; /* initialize the end of the heap */ ram_end = (struct mem *)(void *)&ram[MEM_SIZE_ALIGNED]; ram_end->used = 1; ram_end->next = MEM_SIZE_ALIGNED; ram_end->prev = MEM_SIZE_ALIGNED; /* initialize the lowest-free pointer to the start of the heap */ lfree = (struct mem *)(void *)ram; MEM_STATS_AVAIL(avail, MEM_SIZE_ALIGNED); if(sys_mutex_new(&mem_mutex) != ERR_OK) { LWIP_ASSERT("failed to create mem_mutex", 0); } } /** * Put a struct mem back on the heap * * @param rmem is the data portion of a struct mem as returned by a previous * call to mem_malloc() */ void mem_free(void *rmem) { struct mem *mem; LWIP_MEM_FREE_DECL_PROTECT(); if (rmem == NULL) { LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("mem_free(p == NULL) was called.\n")); return; } LWIP_ASSERT("mem_free: sanity check alignment", (((mem_ptr_t)rmem) & (MEM_ALIGNMENT-1)) == 0); LWIP_ASSERT("mem_free: legal memory", (u8_t *)rmem >= (u8_t *)ram && (u8_t *)rmem < (u8_t *)ram_end); if ((u8_t *)rmem < (u8_t *)ram || (u8_t *)rmem >= (u8_t *)ram_end) { SYS_ARCH_DECL_PROTECT(lev); LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_LEVEL_SEVERE, ("mem_free: illegal memory\n")); /* protect mem stats from concurrent access */ SYS_ARCH_PROTECT(lev); MEM_STATS_INC(illegal); SYS_ARCH_UNPROTECT(lev); return; } /* protect the heap from concurrent access */ LWIP_MEM_FREE_PROTECT(); /* Get the corresponding struct mem ... */ mem = (struct mem *)(void *)((u8_t *)rmem - SIZEOF_STRUCT_MEM); /* ... which has to be in a used state ... */ LWIP_ASSERT("mem_free: mem->used", mem->used); /* ... and is now unused. */ mem->used = 0; if (mem < lfree) { /* the newly freed struct is now the lowest */ lfree = mem; } MEM_STATS_DEC_USED(used, mem->next - (mem_size_t)(((u8_t *)mem - ram))); /* finally, see if prev or next are free also */ plug_holes(mem); #if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT mem_free_count = 1; #endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ LWIP_MEM_FREE_UNPROTECT(); } /** * Shrink memory returned by mem_malloc(). * * @param rmem pointer to memory allocated by mem_malloc the is to be shrinked * @param newsize required size after shrinking (needs to be smaller than or * equal to the previous size) * @return for compatibility reasons: is always == rmem, at the moment * or NULL if newsize is > old size, in which case rmem is NOT touched * or freed! */ void * mem_trim(void *rmem, mem_size_t newsize) { mem_size_t size; mem_size_t ptr, ptr2; struct mem *mem, *mem2; /* use the FREE_PROTECT here: it protects with sem OR SYS_ARCH_PROTECT */ LWIP_MEM_FREE_DECL_PROTECT(); /* Expand the size of the allocated memory region so that we can adjust for alignment. */ newsize = LWIP_MEM_ALIGN_SIZE(newsize); if(newsize < MIN_SIZE_ALIGNED) { /* every data block must be at least MIN_SIZE_ALIGNED long */ newsize = MIN_SIZE_ALIGNED; } if (newsize > MEM_SIZE_ALIGNED) { return NULL; } LWIP_ASSERT("mem_trim: legal memory", (u8_t *)rmem >= (u8_t *)ram && (u8_t *)rmem < (u8_t *)ram_end); if ((u8_t *)rmem < (u8_t *)ram || (u8_t *)rmem >= (u8_t *)ram_end) { SYS_ARCH_DECL_PROTECT(lev); LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_LEVEL_SEVERE, ("mem_trim: illegal memory\n")); /* protect mem stats from concurrent access */ SYS_ARCH_PROTECT(lev); MEM_STATS_INC(illegal); SYS_ARCH_UNPROTECT(lev); return rmem; } /* Get the corresponding struct mem ... */ mem = (struct mem *)(void *)((u8_t *)rmem - SIZEOF_STRUCT_MEM); /* ... and its offset pointer */ ptr = (mem_size_t)((u8_t *)mem - ram); size = mem->next - ptr - SIZEOF_STRUCT_MEM; LWIP_ASSERT("mem_trim can only shrink memory", newsize <= size); if (newsize > size) { /* not supported */ return NULL; } if (newsize == size) { /* No change in size, simply return */ return rmem; } /* protect the heap from concurrent access */ LWIP_MEM_FREE_PROTECT(); mem2 = (struct mem *)(void *)&ram[mem->next]; if(mem2->used == 0) { /* The next struct is unused, we can simply move it at little */ mem_size_t next; /* remember the old next pointer */ next = mem2->next; /* create new struct mem which is moved directly after the shrinked mem */ ptr2 = ptr + SIZEOF_STRUCT_MEM + newsize; if (lfree == mem2) { lfree = (struct mem *)(void *)&ram[ptr2]; } mem2 = (struct mem *)(void *)&ram[ptr2]; mem2->used = 0; /* restore the next pointer */ mem2->next = next; /* link it back to mem */ mem2->prev = ptr; /* link mem to it */ mem->next = ptr2; /* last thing to restore linked list: as we have moved mem2, * let 'mem2->next->prev' point to mem2 again. but only if mem2->next is not * the end of the heap */ if (mem2->next != MEM_SIZE_ALIGNED) { ((struct mem *)(void *)&ram[mem2->next])->prev = ptr2; } MEM_STATS_DEC_USED(used, (size - newsize)); /* no need to plug holes, we've already done that */ } else if (newsize + SIZEOF_STRUCT_MEM + MIN_SIZE_ALIGNED <= size) { /* Next struct is used but there's room for another struct mem with * at least MIN_SIZE_ALIGNED of data. * Old size ('size') must be big enough to contain at least 'newsize' plus a struct mem * ('SIZEOF_STRUCT_MEM') with some data ('MIN_SIZE_ALIGNED'). * @todo we could leave out MIN_SIZE_ALIGNED. We would create an empty * region that couldn't hold data, but when mem->next gets freed, * the 2 regions would be combined, resulting in more free memory */ ptr2 = ptr + SIZEOF_STRUCT_MEM + newsize; mem2 = (struct mem *)(void *)&ram[ptr2]; if (mem2 < lfree) { lfree = mem2; } mem2->used = 0; mem2->next = mem->next; mem2->prev = ptr; mem->next = ptr2; if (mem2->next != MEM_SIZE_ALIGNED) { ((struct mem *)(void *)&ram[mem2->next])->prev = ptr2; } MEM_STATS_DEC_USED(used, (size - newsize)); /* the original mem->next is used, so no need to plug holes! */ } /* else { next struct mem is used but size between mem and mem2 is not big enough to create another struct mem -> don't do anyhting. -> the remaining space stays unused since it is too small } */ #if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT mem_free_count = 1; #endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ LWIP_MEM_FREE_UNPROTECT(); return rmem; } /** * Adam's mem_malloc() plus solution for bug #17922 * Allocate a block of memory with a minimum of 'size' bytes. * * @param size is the minimum size of the requested block in bytes. * @return pointer to allocated memory or NULL if no free memory was found. * * Note that the returned value will always be aligned (as defined by MEM_ALIGNMENT). */ void * mem_malloc(mem_size_t size) { mem_size_t ptr, ptr2; struct mem *mem, *mem2; #if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT u8_t local_mem_free_count = 0; #endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ LWIP_MEM_ALLOC_DECL_PROTECT(); if (size == 0) { return NULL; } /* Expand the size of the allocated memory region so that we can adjust for alignment. */ size = LWIP_MEM_ALIGN_SIZE(size); if(size < MIN_SIZE_ALIGNED) { /* every data block must be at least MIN_SIZE_ALIGNED long */ size = MIN_SIZE_ALIGNED; } if (size > MEM_SIZE_ALIGNED) { return NULL; } /* protect the heap from concurrent access */ sys_mutex_lock(&mem_mutex); LWIP_MEM_ALLOC_PROTECT(); #if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT /* run as long as a mem_free disturbed mem_malloc or mem_trim */ do { local_mem_free_count = 0; #endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ /* Scan through the heap searching for a free block that is big enough, * beginning with the lowest free block. */ for (ptr = (mem_size_t)((u8_t *)lfree - ram); ptr < MEM_SIZE_ALIGNED - size; ptr = ((struct mem *)(void *)&ram[ptr])->next) { mem = (struct mem *)(void *)&ram[ptr]; #if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT mem_free_count = 0; LWIP_MEM_ALLOC_UNPROTECT(); /* allow mem_free or mem_trim to run */ LWIP_MEM_ALLOC_PROTECT(); if (mem_free_count != 0) { /* If mem_free or mem_trim have run, we have to restart since they could have altered our current struct mem. */ local_mem_free_count = 1; break; } #endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ if ((!mem->used) && (mem->next - (ptr + SIZEOF_STRUCT_MEM)) >= size) { /* mem is not used and at least perfect fit is possible: * mem->next - (ptr + SIZEOF_STRUCT_MEM) gives us the 'user data size' of mem */ if (mem->next - (ptr + SIZEOF_STRUCT_MEM) >= (size + SIZEOF_STRUCT_MEM + MIN_SIZE_ALIGNED)) { /* (in addition to the above, we test if another struct mem (SIZEOF_STRUCT_MEM) containing * at least MIN_SIZE_ALIGNED of data also fits in the 'user data space' of 'mem') * -> split large block, create empty remainder, * remainder must be large enough to contain MIN_SIZE_ALIGNED data: if * mem->next - (ptr + (2*SIZEOF_STRUCT_MEM)) == size, * struct mem would fit in but no data between mem2 and mem2->next * @todo we could leave out MIN_SIZE_ALIGNED. We would create an empty * region that couldn't hold data, but when mem->next gets freed, * the 2 regions would be combined, resulting in more free memory */ ptr2 = ptr + SIZEOF_STRUCT_MEM + size; /* create mem2 struct */ mem2 = (struct mem *)(void *)&ram[ptr2]; mem2->used = 0; mem2->next = mem->next; mem2->prev = ptr; /* and insert it between mem and mem->next */ mem->next = ptr2; mem->used = 1; if (mem2->next != MEM_SIZE_ALIGNED) { ((struct mem *)(void *)&ram[mem2->next])->prev = ptr2; } MEM_STATS_INC_USED(used, (size + SIZEOF_STRUCT_MEM)); } else { /* (a mem2 struct does no fit into the user data space of mem and mem->next will always * be used at this point: if not we have 2 unused structs in a row, plug_holes should have * take care of this). * -> near fit or excact fit: do not split, no mem2 creation * also can't move mem->next directly behind mem, since mem->next * will always be used at this point! */ mem->used = 1; MEM_STATS_INC_USED(used, mem->next - (mem_size_t)((u8_t *)mem - ram)); } #if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT mem_malloc_adjust_lfree: #endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ if (mem == lfree) { struct mem *cur = lfree; /* Find next free block after mem and update lowest free pointer */ while (cur->used && cur != ram_end) { #if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT mem_free_count = 0; LWIP_MEM_ALLOC_UNPROTECT(); /* prevent high interrupt latency... */ LWIP_MEM_ALLOC_PROTECT(); if (mem_free_count != 0) { /* If mem_free or mem_trim have run, we have to restart since they could have altered our current struct mem or lfree. */ goto mem_malloc_adjust_lfree; } #endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ cur = (struct mem *)(void *)&ram[cur->next]; } lfree = cur; LWIP_ASSERT("mem_malloc: !lfree->used", ((lfree == ram_end) || (!lfree->used))); } LWIP_MEM_ALLOC_UNPROTECT(); sys_mutex_unlock(&mem_mutex); LWIP_ASSERT("mem_malloc: allocated memory not above ram_end.", (mem_ptr_t)mem + SIZEOF_STRUCT_MEM + size <= (mem_ptr_t)ram_end); LWIP_ASSERT("mem_malloc: allocated memory properly aligned.", ((mem_ptr_t)mem + SIZEOF_STRUCT_MEM) % MEM_ALIGNMENT == 0); LWIP_ASSERT("mem_malloc: sanity check alignment", (((mem_ptr_t)mem) & (MEM_ALIGNMENT-1)) == 0); return (u8_t *)mem + SIZEOF_STRUCT_MEM; } } #if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT /* if we got interrupted by a mem_free, try again */ } while(local_mem_free_count != 0); #endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("mem_malloc: could not allocate %"S16_F" bytes\n", (s16_t)size)); MEM_STATS_INC(err); LWIP_MEM_ALLOC_UNPROTECT(); sys_mutex_unlock(&mem_mutex); return NULL; } #endif /* MEM_USE_POOLS */ /** * Contiguously allocates enough space for count objects that are size bytes * of memory each and returns a pointer to the allocated memory. * * The allocated memory is filled with bytes of value zero. * * @param count number of objects to allocate * @param size size of the objects to allocate * @return pointer to allocated memory / NULL pointer if there is an error */ void *mem_calloc(mem_size_t count, mem_size_t size) { void *p; /* allocate 'count' objects of size 'size' */ p = mem_malloc(count * size); if (p) { /* zero the memory */ memset(p, 0, count * size); } return p; } #endif /* !MEM_LIBC_MALLOC */ ocproxy-1.60/lwip/src/core/memp.c000066400000000000000000000340321303453231400167370ustar00rootroot00000000000000/** * @file * Dynamic pool memory manager * * lwIP has dedicated pools for many structures (netconn, protocol control blocks, * packet buffers, ...). All these pools are managed here. */ /* * Copyright (c) 2001-2004 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #include "lwip/opt.h" #include "lwip/memp.h" #include "lwip/pbuf.h" #include "lwip/udp.h" #include "lwip/raw.h" #include "lwip/tcp_impl.h" #include "lwip/igmp.h" #include "lwip/api.h" #include "lwip/api_msg.h" #include "lwip/sockets.h" #include "lwip/tcpip.h" #include "lwip/sys.h" #include "lwip/timers.h" #include "lwip/stats.h" #include "netif/etharp.h" #include "lwip/ip_frag.h" #include "lwip/snmp_structs.h" #include "lwip/snmp_msg.h" #include "lwip/dns.h" #include "netif/ppp/ppp.h" #include "netif/ppp/pppoe.h" #include "netif/ppp/pppol2tp.h" #include "lwip/nd6.h" #include "lwip/ip6_frag.h" #include "lwip/mld6.h" #include #if !MEMP_MEM_MALLOC /* don't build if not configured for use in lwipopts.h */ struct memp { struct memp *next; #if MEMP_OVERFLOW_CHECK const char *file; int line; #endif /* MEMP_OVERFLOW_CHECK */ }; #if MEMP_OVERFLOW_CHECK /* if MEMP_OVERFLOW_CHECK is turned on, we reserve some bytes at the beginning * and at the end of each element, initialize them as 0xcd and check * them later. */ /* If MEMP_OVERFLOW_CHECK is >= 2, on every call to memp_malloc or memp_free, * every single element in each pool is checked! * This is VERY SLOW but also very helpful. */ /* MEMP_SANITY_REGION_BEFORE and MEMP_SANITY_REGION_AFTER can be overridden in * lwipopts.h to change the amount reserved for checking. */ #ifndef MEMP_SANITY_REGION_BEFORE #define MEMP_SANITY_REGION_BEFORE 16 #endif /* MEMP_SANITY_REGION_BEFORE*/ #if MEMP_SANITY_REGION_BEFORE > 0 #define MEMP_SANITY_REGION_BEFORE_ALIGNED LWIP_MEM_ALIGN_SIZE(MEMP_SANITY_REGION_BEFORE) #else #define MEMP_SANITY_REGION_BEFORE_ALIGNED 0 #endif /* MEMP_SANITY_REGION_BEFORE*/ #ifndef MEMP_SANITY_REGION_AFTER #define MEMP_SANITY_REGION_AFTER 16 #endif /* MEMP_SANITY_REGION_AFTER*/ #if MEMP_SANITY_REGION_AFTER > 0 #define MEMP_SANITY_REGION_AFTER_ALIGNED LWIP_MEM_ALIGN_SIZE(MEMP_SANITY_REGION_AFTER) #else #define MEMP_SANITY_REGION_AFTER_ALIGNED 0 #endif /* MEMP_SANITY_REGION_AFTER*/ /* MEMP_SIZE: save space for struct memp and for sanity check */ #define MEMP_SIZE (LWIP_MEM_ALIGN_SIZE(sizeof(struct memp)) + MEMP_SANITY_REGION_BEFORE_ALIGNED) #define MEMP_ALIGN_SIZE(x) (LWIP_MEM_ALIGN_SIZE(x) + MEMP_SANITY_REGION_AFTER_ALIGNED) #else /* MEMP_OVERFLOW_CHECK */ /* No sanity checks * We don't need to preserve the struct memp while not allocated, so we * can save a little space and set MEMP_SIZE to 0. */ #define MEMP_SIZE 0 #define MEMP_ALIGN_SIZE(x) (LWIP_MEM_ALIGN_SIZE(x)) #endif /* MEMP_OVERFLOW_CHECK */ /** This array holds the first free element of each pool. * Elements form a linked list. */ static struct memp *memp_tab[MEMP_MAX]; #else /* MEMP_MEM_MALLOC */ #define MEMP_ALIGN_SIZE(x) (LWIP_MEM_ALIGN_SIZE(x)) #endif /* MEMP_MEM_MALLOC */ /** This array holds the element sizes of each pool. */ #if !MEM_USE_POOLS && !MEMP_MEM_MALLOC static #endif const u16_t memp_sizes[MEMP_MAX] = { #define LWIP_MEMPOOL(name,num,size,desc) LWIP_MEM_ALIGN_SIZE(size), #include "lwip/memp_std.h" }; #if !MEMP_MEM_MALLOC /* don't build if not configured for use in lwipopts.h */ /** This array holds the number of elements in each pool. */ static const u16_t memp_num[MEMP_MAX] = { #define LWIP_MEMPOOL(name,num,size,desc) (num), #include "lwip/memp_std.h" }; /** This array holds a textual description of each pool. */ #ifdef LWIP_DEBUG static const char *memp_desc[MEMP_MAX] = { #define LWIP_MEMPOOL(name,num,size,desc) (desc), #include "lwip/memp_std.h" }; #endif /* LWIP_DEBUG */ #if MEMP_SEPARATE_POOLS /** This creates each memory pool. These are named memp_memory_XXX_base (where * XXX is the name of the pool defined in memp_std.h). * To relocate a pool, declare it as extern in cc.h. Example for GCC: * extern u8_t __attribute__((section(".onchip_mem"))) memp_memory_UDP_PCB_base[]; */ #define LWIP_MEMPOOL(name,num,size,desc) u8_t memp_memory_ ## name ## _base \ [((num) * (MEMP_SIZE + MEMP_ALIGN_SIZE(size)))]; #include "lwip/memp_std.h" /** This array holds the base of each memory pool. */ static u8_t *const memp_bases[] = { #define LWIP_MEMPOOL(name,num,size,desc) memp_memory_ ## name ## _base, #include "lwip/memp_std.h" }; #else /* MEMP_SEPARATE_POOLS */ /** This is the actual memory used by the pools (all pools in one big block). */ static u8_t memp_memory[MEM_ALIGNMENT - 1 #define LWIP_MEMPOOL(name,num,size,desc) + ( (num) * (MEMP_SIZE + MEMP_ALIGN_SIZE(size) ) ) #include "lwip/memp_std.h" ]; #endif /* MEMP_SEPARATE_POOLS */ #if MEMP_SANITY_CHECK /** * Check that memp-lists don't form a circle, using "Floyd's cycle-finding algorithm". */ static int memp_sanity(void) { s16_t i; struct memp *t, *h; for (i = 0; i < MEMP_MAX; i++) { t = memp_tab[i]; if(t != NULL) { for (h = t->next; (t != NULL) && (h != NULL); t = t->next, h = (((h->next != NULL) && (h->next->next != NULL)) ? h->next->next : NULL)) { if (t == h) { return 0; } } } } return 1; } #endif /* MEMP_SANITY_CHECK*/ #if MEMP_OVERFLOW_CHECK #if defined(LWIP_DEBUG) && MEMP_STATS static const char * memp_overflow_names[] = { #define LWIP_MEMPOOL(name,num,size,desc) "/"desc, #include "lwip/memp_std.h" }; #endif /** * Check if a memp element was victim of an overflow * (e.g. the restricted area after it has been altered) * * @param p the memp element to check * @param memp_type the pool p comes from */ static void memp_overflow_check_element_overflow(struct memp *p, u16_t memp_type) { u16_t k; u8_t *m; #if MEMP_SANITY_REGION_AFTER_ALIGNED > 0 m = (u8_t*)p + MEMP_SIZE + memp_sizes[memp_type]; for (k = 0; k < MEMP_SANITY_REGION_AFTER_ALIGNED; k++) { if (m[k] != 0xcd) { char errstr[128] = "detected memp overflow in pool "; char digit[] = "0"; if(memp_type >= 10) { digit[0] = '0' + (memp_type/10); strcat(errstr, digit); } digit[0] = '0' + (memp_type%10); strcat(errstr, digit); #if defined(LWIP_DEBUG) && MEMP_STATS strcat(errstr, memp_overflow_names[memp_type]); #endif LWIP_ASSERT(errstr, 0); } } #endif } /** * Check if a memp element was victim of an underflow * (e.g. the restricted area before it has been altered) * * @param p the memp element to check * @param memp_type the pool p comes from */ static void memp_overflow_check_element_underflow(struct memp *p, u16_t memp_type) { u16_t k; u8_t *m; #if MEMP_SANITY_REGION_BEFORE_ALIGNED > 0 m = (u8_t*)p + MEMP_SIZE - MEMP_SANITY_REGION_BEFORE_ALIGNED; for (k = 0; k < MEMP_SANITY_REGION_BEFORE_ALIGNED; k++) { if (m[k] != 0xcd) { char errstr[128] = "detected memp underflow in pool "; char digit[] = "0"; if(memp_type >= 10) { digit[0] = '0' + (memp_type/10); strcat(errstr, digit); } digit[0] = '0' + (memp_type%10); strcat(errstr, digit); #if defined(LWIP_DEBUG) && MEMP_STATS strcat(errstr, memp_overflow_names[memp_type]); #endif LWIP_ASSERT(errstr, 0); } } #endif } /** * Do an overflow check for all elements in every pool. * * @see memp_overflow_check_element for a description of the check */ static void memp_overflow_check_all(void) { u16_t i, j; struct memp *p; #if !MEMP_SEPARATE_POOLS p = (struct memp *)LWIP_MEM_ALIGN(memp_memory); #endif /* !MEMP_SEPARATE_POOLS */ for (i = 0; i < MEMP_MAX; ++i) { #if MEMP_SEPARATE_POOLS p = (struct memp *)(memp_bases[i]); #endif /* MEMP_SEPARATE_POOLS */ for (j = 0; j < memp_num[i]; ++j) { memp_overflow_check_element_overflow(p, i); p = (struct memp*)((u8_t*)p + MEMP_SIZE + memp_sizes[i] + MEMP_SANITY_REGION_AFTER_ALIGNED); } } #if !MEMP_SEPARATE_POOLS p = (struct memp *)LWIP_MEM_ALIGN(memp_memory); #endif /* !MEMP_SEPARATE_POOLS */ for (i = 0; i < MEMP_MAX; ++i) { #if MEMP_SEPARATE_POOLS p = (struct memp *)(memp_bases[i]); #endif /* MEMP_SEPARATE_POOLS */ for (j = 0; j < memp_num[i]; ++j) { memp_overflow_check_element_underflow(p, i); p = (struct memp*)((u8_t*)p + MEMP_SIZE + memp_sizes[i] + MEMP_SANITY_REGION_AFTER_ALIGNED); } } } /** * Initialize the restricted areas of all memp elements in every pool. */ static void memp_overflow_init(void) { u16_t i, j; struct memp *p; u8_t *m; #if !MEMP_SEPARATE_POOLS p = (struct memp *)LWIP_MEM_ALIGN(memp_memory); #endif /* !MEMP_SEPARATE_POOLS */ for (i = 0; i < MEMP_MAX; ++i) { #if MEMP_SEPARATE_POOLS p = (struct memp *)(memp_bases[i]); #endif /* MEMP_SEPARATE_POOLS */ for (j = 0; j < memp_num[i]; ++j) { #if MEMP_SANITY_REGION_BEFORE_ALIGNED > 0 m = (u8_t*)p + MEMP_SIZE - MEMP_SANITY_REGION_BEFORE_ALIGNED; memset(m, 0xcd, MEMP_SANITY_REGION_BEFORE_ALIGNED); #endif #if MEMP_SANITY_REGION_AFTER_ALIGNED > 0 m = (u8_t*)p + MEMP_SIZE + memp_sizes[i]; memset(m, 0xcd, MEMP_SANITY_REGION_AFTER_ALIGNED); #endif p = (struct memp*)((u8_t*)p + MEMP_SIZE + memp_sizes[i] + MEMP_SANITY_REGION_AFTER_ALIGNED); } } } #endif /* MEMP_OVERFLOW_CHECK */ /** * Initialize this module. * * Carves out memp_memory into linked lists for each pool-type. */ void memp_init(void) { struct memp *memp; u16_t i, j; for (i = 0; i < MEMP_MAX; ++i) { MEMP_STATS_AVAIL(used, i, 0); MEMP_STATS_AVAIL(max, i, 0); MEMP_STATS_AVAIL(err, i, 0); MEMP_STATS_AVAIL(avail, i, memp_num[i]); } #if !MEMP_SEPARATE_POOLS memp = (struct memp *)LWIP_MEM_ALIGN(memp_memory); #endif /* !MEMP_SEPARATE_POOLS */ /* for every pool: */ for (i = 0; i < MEMP_MAX; ++i) { memp_tab[i] = NULL; #if MEMP_SEPARATE_POOLS memp = (struct memp*)LWIP_MEM_ALIGN(memp_bases[i]); #endif /* MEMP_SEPARATE_POOLS */ /* create a linked list of memp elements */ for (j = 0; j < memp_num[i]; ++j) { memp->next = memp_tab[i]; memp_tab[i] = memp; memp = (struct memp *)(void *)((u8_t *)memp + MEMP_SIZE + memp_sizes[i] #if MEMP_OVERFLOW_CHECK + MEMP_SANITY_REGION_AFTER_ALIGNED #endif ); } } #if MEMP_OVERFLOW_CHECK memp_overflow_init(); /* check everything a first time to see if it worked */ memp_overflow_check_all(); #endif /* MEMP_OVERFLOW_CHECK */ } /** * Get an element from a specific pool. * * @param type the pool to get an element from * * the debug version has two more parameters: * @param file file name calling this function * @param line number of line where this function is called * * @return a pointer to the allocated memory or a NULL pointer on error */ void * #if !MEMP_OVERFLOW_CHECK memp_malloc(memp_t type) #else memp_malloc_fn(memp_t type, const char* file, const int line) #endif { struct memp *memp; SYS_ARCH_DECL_PROTECT(old_level); LWIP_ERROR("memp_malloc: type < MEMP_MAX", (type < MEMP_MAX), return NULL;); SYS_ARCH_PROTECT(old_level); #if MEMP_OVERFLOW_CHECK >= 2 memp_overflow_check_all(); #endif /* MEMP_OVERFLOW_CHECK >= 2 */ memp = memp_tab[type]; if (memp != NULL) { memp_tab[type] = memp->next; #if MEMP_OVERFLOW_CHECK memp->next = NULL; memp->file = file; memp->line = line; #endif /* MEMP_OVERFLOW_CHECK */ MEMP_STATS_INC_USED(used, type); LWIP_ASSERT("memp_malloc: memp properly aligned", ((mem_ptr_t)memp % MEM_ALIGNMENT) == 0); memp = (struct memp*)(void *)((u8_t*)memp + MEMP_SIZE); } else { LWIP_DEBUGF(MEMP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("memp_malloc: out of memory in pool %s\n", memp_desc[type])); MEMP_STATS_INC(err, type); } SYS_ARCH_UNPROTECT(old_level); return memp; } /** * Put an element back into its pool. * * @param type the pool where to put mem * @param mem the memp element to free */ void memp_free(memp_t type, void *mem) { struct memp *memp; SYS_ARCH_DECL_PROTECT(old_level); if (mem == NULL) { return; } LWIP_ASSERT("memp_free: mem properly aligned", ((mem_ptr_t)mem % MEM_ALIGNMENT) == 0); memp = (struct memp *)(void *)((u8_t*)mem - MEMP_SIZE); SYS_ARCH_PROTECT(old_level); #if MEMP_OVERFLOW_CHECK #if MEMP_OVERFLOW_CHECK >= 2 memp_overflow_check_all(); #else memp_overflow_check_element_overflow(memp, type); memp_overflow_check_element_underflow(memp, type); #endif /* MEMP_OVERFLOW_CHECK >= 2 */ #endif /* MEMP_OVERFLOW_CHECK */ MEMP_STATS_DEC(used, type); memp->next = memp_tab[type]; memp_tab[type] = memp; #if MEMP_SANITY_CHECK LWIP_ASSERT("memp sanity", memp_sanity()); #endif /* MEMP_SANITY_CHECK */ SYS_ARCH_UNPROTECT(old_level); } #endif /* MEMP_MEM_MALLOC */ ocproxy-1.60/lwip/src/core/netif.c000066400000000000000000000646451303453231400171230ustar00rootroot00000000000000/** * @file * lwIP network interface abstraction * */ /* * Copyright (c) 2001-2004 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #include "lwip/opt.h" #include "lwip/def.h" #include "lwip/ip_addr.h" #include "lwip/ip6_addr.h" #include "lwip/netif.h" #include "lwip/tcp_impl.h" #include "lwip/snmp.h" #include "lwip/igmp.h" #include "netif/etharp.h" #include "lwip/stats.h" #if ENABLE_LOOPBACK #include "lwip/sys.h" #if LWIP_NETIF_LOOPBACK_MULTITHREADING #include "lwip/tcpip.h" #endif /* LWIP_NETIF_LOOPBACK_MULTITHREADING */ #endif /* ENABLE_LOOPBACK */ #if LWIP_AUTOIP #include "lwip/autoip.h" #endif /* LWIP_AUTOIP */ #if LWIP_DHCP #include "lwip/dhcp.h" #endif /* LWIP_DHCP */ #if LWIP_IPV6_DHCP6 #include "lwip/dhcp6.h" #endif /* LWIP_IPV6_DHCP6 */ #if LWIP_IPV6_MLD #include "lwip/mld6.h" #endif /* LWIP_IPV6_MLD */ #if LWIP_NETIF_STATUS_CALLBACK #define NETIF_STATUS_CALLBACK(n) do{ if (n->status_callback) { (n->status_callback)(n); }}while(0) #else #define NETIF_STATUS_CALLBACK(n) #endif /* LWIP_NETIF_STATUS_CALLBACK */ #if LWIP_NETIF_LINK_CALLBACK #define NETIF_LINK_CALLBACK(n) do{ if (n->link_callback) { (n->link_callback)(n); }}while(0) #else #define NETIF_LINK_CALLBACK(n) #endif /* LWIP_NETIF_LINK_CALLBACK */ struct netif *netif_list; struct netif *netif_default; static u8_t netif_num; #if LWIP_IPV6 static err_t netif_null_output_ip6(struct netif *netif, struct pbuf *p, ip6_addr_t *ipaddr); #endif /* LWIP_IPV6 */ #if LWIP_IPV6 #define ipX_input(in, netif) (IP6H_V((const struct ip6_hdr *)in->payload) == 6) ? ip6_input(in, netif) : ip_input(in, netif) #else #define ipX_input(in, netif) ip_input(in, netif) #endif #if LWIP_HAVE_LOOPIF static err_t netif_loop_output_ipv4(struct netif *netif, struct pbuf *p, ip_addr_t* addr); #if LWIP_IPV6 static err_t netif_loop_output_ipv6(struct netif *netif, struct pbuf *p, ip6_addr_t* addr); #endif static struct netif loop_netif; /** * Initialize a lwip network interface structure for a loopback interface * * @param netif the lwip network interface structure for this loopif * @return ERR_OK if the loopif is initialized * ERR_MEM if private data couldn't be allocated */ static err_t netif_loopif_init(struct netif *netif) { /* initialize the snmp variables and counters inside the struct netif * ifSpeed: no assumption can be made! */ NETIF_INIT_SNMP(netif, snmp_ifType_softwareLoopback, 0); netif->name[0] = 'l'; netif->name[1] = 'o'; netif->output = netif_loop_output_ipv4; #if LWIP_IPV6 netif->output_ip6 = netif_loop_output_ipv6; #endif return ERR_OK; } #endif /* LWIP_HAVE_LOOPIF */ void netif_init(void) { #if LWIP_HAVE_LOOPIF ip_addr_t loop_ipaddr, loop_netmask, loop_gw; IP4_ADDR(&loop_gw, 127,0,0,1); IP4_ADDR(&loop_ipaddr, 127,0,0,1); IP4_ADDR(&loop_netmask, 255,0,0,0); #if NO_SYS netif_add(&loop_netif, &loop_ipaddr, &loop_netmask, &loop_gw, NULL, netif_loopif_init, ip_input); #else /* NO_SYS */ netif_add(&loop_netif, &loop_ipaddr, &loop_netmask, &loop_gw, NULL, netif_loopif_init, tcpip_input); #endif /* NO_SYS */ #if LWIP_IPV6 loop_netif.ip6_addr[0].addr[0] = 0; loop_netif.ip6_addr[0].addr[1] = 0; loop_netif.ip6_addr[0].addr[2] = 0; loop_netif.ip6_addr[0].addr[3] = PP_HTONL(0x00000001UL); loop_netif.ip6_addr_state[0] = IP6_ADDR_VALID; #endif /* LWIP_IPV6 */ netif_set_up(&loop_netif); #endif /* LWIP_HAVE_LOOPIF */ } /** * Add a network interface to the list of lwIP netifs. * * @param netif a pre-allocated netif structure * @param ipaddr IP address for the new netif * @param netmask network mask for the new netif * @param gw default gateway IP address for the new netif * @param state opaque data passed to the new netif * @param init callback function that initializes the interface * @param input callback function that is called to pass * ingress packets up in the protocol layer stack. * * @return netif, or NULL if failed. */ struct netif * netif_add(struct netif *netif, ip_addr_t *ipaddr, ip_addr_t *netmask, ip_addr_t *gw, void *state, netif_init_fn init, netif_input_fn input) { #if LWIP_IPV6 u32_t i; #endif LWIP_ASSERT("No init function given", init != NULL); /* reset new interface configuration state */ ip_addr_set_zero(&netif->ip_addr); ip_addr_set_zero(&netif->netmask); ip_addr_set_zero(&netif->gw); #if LWIP_IPV6 for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { ip6_addr_set_zero(&netif->ip6_addr[i]); netif_ip6_addr_set_state(netif, i, IP6_ADDR_INVALID); } netif->output_ip6 = netif_null_output_ip6; #endif /* LWIP_IPV6 */ netif->flags = 0; #if LWIP_DHCP /* netif not under DHCP control by default */ netif->dhcp = NULL; #endif /* LWIP_DHCP */ #if LWIP_AUTOIP /* netif not under AutoIP control by default */ netif->autoip = NULL; #endif /* LWIP_AUTOIP */ #if LWIP_IPV6_AUTOCONFIG /* IPv6 address autoconfiguration not enabled by default */ netif->ip6_autoconfig_enabled = 0; #endif /* LWIP_IPV6_AUTOCONFIG */ #if LWIP_IPV6_SEND_ROUTER_SOLICIT netif->rs_count = LWIP_ND6_MAX_MULTICAST_SOLICIT; #endif /* LWIP_IPV6_SEND_ROUTER_SOLICIT */ #if LWIP_IPV6_DHCP6 /* netif not under DHCPv6 control by default */ netif->dhcp6 = NULL; #endif /* LWIP_IPV6_DHCP6 */ #if LWIP_NETIF_STATUS_CALLBACK netif->status_callback = NULL; #endif /* LWIP_NETIF_STATUS_CALLBACK */ #if LWIP_NETIF_LINK_CALLBACK netif->link_callback = NULL; #endif /* LWIP_NETIF_LINK_CALLBACK */ #if LWIP_IGMP netif->igmp_mac_filter = NULL; #endif /* LWIP_IGMP */ #if LWIP_IPV6 && LWIP_IPV6_MLD netif->mld_mac_filter = NULL; #endif /* LWIP_IPV6 && LWIP_IPV6_MLD */ #if ENABLE_LOOPBACK netif->loop_first = NULL; netif->loop_last = NULL; #endif /* ENABLE_LOOPBACK */ /* remember netif specific state information data */ netif->state = state; netif->num = netif_num++; netif->input = input; NETIF_SET_HWADDRHINT(netif, NULL); #if ENABLE_LOOPBACK && LWIP_LOOPBACK_MAX_PBUFS netif->loop_cnt_current = 0; #endif /* ENABLE_LOOPBACK && LWIP_LOOPBACK_MAX_PBUFS */ netif_set_addr(netif, ipaddr, netmask, gw); /* call user specified initialization function for netif */ if (init(netif) != ERR_OK) { return NULL; } /* add this netif to the list */ netif->next = netif_list; netif_list = netif; snmp_inc_iflist(); #if LWIP_IGMP /* start IGMP processing */ if (netif->flags & NETIF_FLAG_IGMP) { igmp_start(netif); } #endif /* LWIP_IGMP */ LWIP_DEBUGF(NETIF_DEBUG, ("netif: added interface %c%c IP addr ", netif->name[0], netif->name[1])); ip_addr_debug_print(NETIF_DEBUG, ipaddr); LWIP_DEBUGF(NETIF_DEBUG, (" netmask ")); ip_addr_debug_print(NETIF_DEBUG, netmask); LWIP_DEBUGF(NETIF_DEBUG, (" gw ")); ip_addr_debug_print(NETIF_DEBUG, gw); LWIP_DEBUGF(NETIF_DEBUG, ("\n")); return netif; } /** * Change IP address configuration for a network interface (including netmask * and default gateway). * * @param netif the network interface to change * @param ipaddr the new IP address * @param netmask the new netmask * @param gw the new default gateway */ void netif_set_addr(struct netif *netif, ip_addr_t *ipaddr, ip_addr_t *netmask, ip_addr_t *gw) { netif_set_ipaddr(netif, ipaddr); netif_set_netmask(netif, netmask); netif_set_gw(netif, gw); } /** * Remove a network interface from the list of lwIP netifs. * * @param netif the network interface to remove */ void netif_remove(struct netif *netif) { if (netif == NULL) { return; } #if LWIP_IGMP /* stop IGMP processing */ if (netif->flags & NETIF_FLAG_IGMP) { igmp_stop(netif); } #endif /* LWIP_IGMP */ #if LWIP_IPV6 && LWIP_IPV6_MLD /* stop MLD processing */ mld6_stop(netif); #endif /* LWIP_IPV6 && LWIP_IPV6_MLD */ if (netif_is_up(netif)) { /* set netif down before removing (call callback function) */ netif_set_down(netif); } snmp_delete_ipaddridx_tree(netif); /* is it the first netif? */ if (netif_list == netif) { netif_list = netif->next; } else { /* look for netif further down the list */ struct netif * tmpNetif; for (tmpNetif = netif_list; tmpNetif != NULL; tmpNetif = tmpNetif->next) { if (tmpNetif->next == netif) { tmpNetif->next = netif->next; break; } } if (tmpNetif == NULL) return; /* we didn't find any netif today */ } snmp_dec_iflist(); /* this netif is default? */ if (netif_default == netif) { /* reset default netif */ netif_set_default(NULL); } #if LWIP_NETIF_REMOVE_CALLBACK if (netif->remove_callback) { netif->remove_callback(netif); } #endif /* LWIP_NETIF_REMOVE_CALLBACK */ LWIP_DEBUGF( NETIF_DEBUG, ("netif_remove: removed netif\n") ); } /** * Find a network interface by searching for its name * * @param name the name of the netif (like netif->name) plus concatenated number * in ascii representation (e.g. 'en0') */ struct netif * netif_find(char *name) { struct netif *netif; u8_t num; if (name == NULL) { return NULL; } num = name[2] - '0'; for(netif = netif_list; netif != NULL; netif = netif->next) { if (num == netif->num && name[0] == netif->name[0] && name[1] == netif->name[1]) { LWIP_DEBUGF(NETIF_DEBUG, ("netif_find: found %c%c\n", name[0], name[1])); return netif; } } LWIP_DEBUGF(NETIF_DEBUG, ("netif_find: didn't find %c%c\n", name[0], name[1])); return NULL; } /** * Change the IP address of a network interface * * @param netif the network interface to change * @param ipaddr the new IP address * * @note call netif_set_addr() if you also want to change netmask and * default gateway */ void netif_set_ipaddr(struct netif *netif, ip_addr_t *ipaddr) { /* TODO: Handling of obsolete pcbs */ /* See: http://mail.gnu.org/archive/html/lwip-users/2003-03/msg00118.html */ #if LWIP_TCP struct tcp_pcb *pcb; struct tcp_pcb_listen *lpcb; /* address is actually being changed? */ if (ipaddr && (ip_addr_cmp(ipaddr, &(netif->ip_addr))) == 0) { /* extern struct tcp_pcb *tcp_active_pcbs; defined by tcp.h */ LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_STATE, ("netif_set_ipaddr: netif address being changed\n")); pcb = tcp_active_pcbs; while (pcb != NULL) { /* PCB bound to current local interface address? */ if (ip_addr_cmp(ipX_2_ip(&pcb->local_ip), &(netif->ip_addr)) #if LWIP_AUTOIP /* connections to link-local addresses must persist (RFC3927 ch. 1.9) */ && !ip_addr_islinklocal(ipX_2_ip(&pcb->local_ip)) #endif /* LWIP_AUTOIP */ ) { /* this connection must be aborted */ struct tcp_pcb *next = pcb->next; LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_STATE, ("netif_set_ipaddr: aborting TCP pcb %p\n", (void *)pcb)); tcp_abort(pcb); pcb = next; } else { pcb = pcb->next; } } for (lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) { /* PCB bound to current local interface address? */ if ((!(ip_addr_isany(ipX_2_ip(&lpcb->local_ip)))) && (ip_addr_cmp(ipX_2_ip(&lpcb->local_ip), &(netif->ip_addr)))) { /* The PCB is listening to the old ipaddr and * is set to listen to the new one instead */ ip_addr_set(ipX_2_ip(&lpcb->local_ip), ipaddr); } } } #endif snmp_delete_ipaddridx_tree(netif); snmp_delete_iprteidx_tree(0,netif); /* set new IP address to netif */ ip_addr_set(&(netif->ip_addr), ipaddr); snmp_insert_ipaddridx_tree(netif); snmp_insert_iprteidx_tree(0,netif); LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("netif: IP address of interface %c%c set to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", netif->name[0], netif->name[1], ip4_addr1_16(&netif->ip_addr), ip4_addr2_16(&netif->ip_addr), ip4_addr3_16(&netif->ip_addr), ip4_addr4_16(&netif->ip_addr))); } /** * Change the default gateway for a network interface * * @param netif the network interface to change * @param gw the new default gateway * * @note call netif_set_addr() if you also want to change ip address and netmask */ void netif_set_gw(struct netif *netif, ip_addr_t *gw) { ip_addr_set(&(netif->gw), gw); LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("netif: GW address of interface %c%c set to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", netif->name[0], netif->name[1], ip4_addr1_16(&netif->gw), ip4_addr2_16(&netif->gw), ip4_addr3_16(&netif->gw), ip4_addr4_16(&netif->gw))); } /** * Change the netmask of a network interface * * @param netif the network interface to change * @param netmask the new netmask * * @note call netif_set_addr() if you also want to change ip address and * default gateway */ void netif_set_netmask(struct netif *netif, ip_addr_t *netmask) { snmp_delete_iprteidx_tree(0, netif); /* set new netmask to netif */ ip_addr_set(&(netif->netmask), netmask); snmp_insert_iprteidx_tree(0, netif); LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("netif: netmask of interface %c%c set to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", netif->name[0], netif->name[1], ip4_addr1_16(&netif->netmask), ip4_addr2_16(&netif->netmask), ip4_addr3_16(&netif->netmask), ip4_addr4_16(&netif->netmask))); } /** * Set a network interface as the default network interface * (used to output all packets for which no specific route is found) * * @param netif the default network interface */ void netif_set_default(struct netif *netif) { if (netif == NULL) { /* remove default route */ snmp_delete_iprteidx_tree(1, netif); } else { /* install default route */ snmp_insert_iprteidx_tree(1, netif); } netif_default = netif; LWIP_DEBUGF(NETIF_DEBUG, ("netif: setting default interface %c%c\n", netif ? netif->name[0] : '\'', netif ? netif->name[1] : '\'')); } /** * Bring an interface up, available for processing * traffic. * * @note: Enabling DHCP on a down interface will make it come * up once configured. * * @see dhcp_start() */ void netif_set_up(struct netif *netif) { if (!(netif->flags & NETIF_FLAG_UP)) { netif->flags |= NETIF_FLAG_UP; #if LWIP_SNMP snmp_get_sysuptime(&netif->ts); #endif /* LWIP_SNMP */ NETIF_STATUS_CALLBACK(netif); if (netif->flags & NETIF_FLAG_LINK_UP) { #if LWIP_ARP /* For Ethernet network interfaces, we would like to send a "gratuitous ARP" */ if (netif->flags & (NETIF_FLAG_ETHARP)) { etharp_gratuitous(netif); } #endif /* LWIP_ARP */ #if LWIP_IGMP /* resend IGMP memberships */ if (netif->flags & NETIF_FLAG_IGMP) { igmp_report_groups( netif); } #endif /* LWIP_IGMP */ #if LWIP_IPV6 && LWIP_IPV6_MLD /* send mld memberships */ mld6_report_groups( netif); #endif /* LWIP_IPV6 && LWIP_IPV6_MLD */ #if LWIP_IPV6_SEND_ROUTER_SOLICIT /* Send Router Solicitation messages. */ netif->rs_count = LWIP_ND6_MAX_MULTICAST_SOLICIT; #endif /* LWIP_IPV6_SEND_ROUTER_SOLICIT */ } } } /** * Bring an interface down, disabling any traffic processing. * * @note: Enabling DHCP on a down interface will make it come * up once configured. * * @see dhcp_start() */ void netif_set_down(struct netif *netif) { if (netif->flags & NETIF_FLAG_UP) { netif->flags &= ~NETIF_FLAG_UP; #if LWIP_SNMP snmp_get_sysuptime(&netif->ts); #endif #if LWIP_ARP if (netif->flags & NETIF_FLAG_ETHARP) { etharp_cleanup_netif(netif); } #endif /* LWIP_ARP */ NETIF_STATUS_CALLBACK(netif); } } #if LWIP_NETIF_STATUS_CALLBACK /** * Set callback to be called when interface is brought up/down */ void netif_set_status_callback(struct netif *netif, netif_status_callback_fn status_callback) { if (netif) { netif->status_callback = status_callback; } } #endif /* LWIP_NETIF_STATUS_CALLBACK */ #if LWIP_NETIF_REMOVE_CALLBACK /** * Set callback to be called when the interface has been removed */ void netif_set_remove_callback(struct netif *netif, netif_status_callback_fn remove_callback) { if (netif) { netif->remove_callback = remove_callback; } } #endif /* LWIP_NETIF_REMOVE_CALLBACK */ /** * Called by a driver when its link goes up */ void netif_set_link_up(struct netif *netif ) { if (!(netif->flags & NETIF_FLAG_LINK_UP)) { netif->flags |= NETIF_FLAG_LINK_UP; #if LWIP_DHCP if (netif->dhcp) { dhcp_network_changed(netif); } #endif /* LWIP_DHCP */ #if LWIP_AUTOIP if (netif->autoip) { autoip_network_changed(netif); } #endif /* LWIP_AUTOIP */ if (netif->flags & NETIF_FLAG_UP) { #if LWIP_ARP /* For Ethernet network interfaces, we would like to send a "gratuitous ARP" */ if (netif->flags & NETIF_FLAG_ETHARP) { etharp_gratuitous(netif); } #endif /* LWIP_ARP */ #if LWIP_IGMP /* resend IGMP memberships */ if (netif->flags & NETIF_FLAG_IGMP) { igmp_report_groups( netif); } #endif /* LWIP_IGMP */ #if LWIP_IPV6 && LWIP_IPV6_MLD /* send mld memberships */ mld6_report_groups( netif); #endif /* LWIP_IPV6 && LWIP_IPV6_MLD */ } NETIF_LINK_CALLBACK(netif); } } /** * Called by a driver when its link goes down */ void netif_set_link_down(struct netif *netif ) { if (netif->flags & NETIF_FLAG_LINK_UP) { netif->flags &= ~NETIF_FLAG_LINK_UP; NETIF_LINK_CALLBACK(netif); } } #if LWIP_NETIF_LINK_CALLBACK /** * Set callback to be called when link is brought up/down */ void netif_set_link_callback(struct netif *netif, netif_status_callback_fn link_callback) { if (netif) { netif->link_callback = link_callback; } } #endif /* LWIP_NETIF_LINK_CALLBACK */ #if ENABLE_LOOPBACK /** * Send an IP packet to be received on the same netif (loopif-like). * The pbuf is simply copied and handed back to netif->input. * In multithreaded mode, this is done directly since netif->input must put * the packet on a queue. * In callback mode, the packet is put on an internal queue and is fed to * netif->input by netif_poll(). * * @param netif the lwip network interface structure * @param p the (IP) packet to 'send' * @return ERR_OK if the packet has been sent * ERR_MEM if the pbuf used to copy the packet couldn't be allocated */ err_t netif_loop_output(struct netif *netif, struct pbuf *p) { struct pbuf *r; err_t err; struct pbuf *last; #if LWIP_LOOPBACK_MAX_PBUFS u8_t clen = 0; #endif /* LWIP_LOOPBACK_MAX_PBUFS */ /* If we have a loopif, SNMP counters are adjusted for it, * if not they are adjusted for 'netif'. */ #if LWIP_SNMP #if LWIP_HAVE_LOOPIF struct netif *stats_if = &loop_netif; #else /* LWIP_HAVE_LOOPIF */ struct netif *stats_if = netif; #endif /* LWIP_HAVE_LOOPIF */ #endif /* LWIP_SNMP */ SYS_ARCH_DECL_PROTECT(lev); /* Allocate a new pbuf */ r = pbuf_alloc(PBUF_LINK, p->tot_len, PBUF_RAM); if (r == NULL) { LINK_STATS_INC(link.memerr); LINK_STATS_INC(link.drop); snmp_inc_ifoutdiscards(stats_if); return ERR_MEM; } #if LWIP_LOOPBACK_MAX_PBUFS clen = pbuf_clen(r); /* check for overflow or too many pbuf on queue */ if(((netif->loop_cnt_current + clen) < netif->loop_cnt_current) || ((netif->loop_cnt_current + clen) > LWIP_LOOPBACK_MAX_PBUFS)) { pbuf_free(r); LINK_STATS_INC(link.memerr); LINK_STATS_INC(link.drop); snmp_inc_ifoutdiscards(stats_if); return ERR_MEM; } netif->loop_cnt_current += clen; #endif /* LWIP_LOOPBACK_MAX_PBUFS */ /* Copy the whole pbuf queue p into the single pbuf r */ if ((err = pbuf_copy(r, p)) != ERR_OK) { pbuf_free(r); LINK_STATS_INC(link.memerr); LINK_STATS_INC(link.drop); snmp_inc_ifoutdiscards(stats_if); return err; } /* Put the packet on a linked list which gets emptied through calling netif_poll(). */ /* let last point to the last pbuf in chain r */ for (last = r; last->next != NULL; last = last->next); SYS_ARCH_PROTECT(lev); if (netif->loop_first != NULL) { LWIP_ASSERT("if first != NULL, last must also be != NULL", netif->loop_last != NULL); netif->loop_last->next = r; netif->loop_last = last; } else { netif->loop_first = r; netif->loop_last = last; } SYS_ARCH_UNPROTECT(lev); LINK_STATS_INC(link.xmit); snmp_add_ifoutoctets(stats_if, p->tot_len); snmp_inc_ifoutucastpkts(stats_if); #if LWIP_NETIF_LOOPBACK_MULTITHREADING /* For multithreading environment, schedule a call to netif_poll */ tcpip_callback_with_block((tcpip_callback_fn)netif_poll, netif, 0); #endif /* LWIP_NETIF_LOOPBACK_MULTITHREADING */ return ERR_OK; } static err_t netif_loop_output_ipv4(struct netif *netif, struct pbuf *p, ip_addr_t* addr) { LWIP_UNUSED_ARG(addr); return netif_loop_output(netif, p); } #if LWIP_IPV6 static err_t netif_loop_output_ipv6(struct netif *netif, struct pbuf *p, ip6_addr_t* addr) { LWIP_UNUSED_ARG(addr); return netif_loop_output(netif, p); } #endif /** * Call netif_poll() in the main loop of your application. This is to prevent * reentering non-reentrant functions like tcp_input(). Packets passed to * netif_loop_output() are put on a list that is passed to netif->input() by * netif_poll(). */ void netif_poll(struct netif *netif) { struct pbuf *in; /* If we have a loopif, SNMP counters are adjusted for it, * if not they are adjusted for 'netif'. */ #if LWIP_SNMP #if LWIP_HAVE_LOOPIF struct netif *stats_if = &loop_netif; #else /* LWIP_HAVE_LOOPIF */ struct netif *stats_if = netif; #endif /* LWIP_HAVE_LOOPIF */ #endif /* LWIP_SNMP */ SYS_ARCH_DECL_PROTECT(lev); do { /* Get a packet from the list. With SYS_LIGHTWEIGHT_PROT=1, this is protected */ SYS_ARCH_PROTECT(lev); in = netif->loop_first; if (in != NULL) { struct pbuf *in_end = in; #if LWIP_LOOPBACK_MAX_PBUFS u8_t clen = 1; #endif /* LWIP_LOOPBACK_MAX_PBUFS */ while (in_end->len != in_end->tot_len) { LWIP_ASSERT("bogus pbuf: len != tot_len but next == NULL!", in_end->next != NULL); in_end = in_end->next; #if LWIP_LOOPBACK_MAX_PBUFS clen++; #endif /* LWIP_LOOPBACK_MAX_PBUFS */ } #if LWIP_LOOPBACK_MAX_PBUFS /* adjust the number of pbufs on queue */ LWIP_ASSERT("netif->loop_cnt_current underflow", ((netif->loop_cnt_current - clen) < netif->loop_cnt_current)); netif->loop_cnt_current -= clen; #endif /* LWIP_LOOPBACK_MAX_PBUFS */ /* 'in_end' now points to the last pbuf from 'in' */ if (in_end == netif->loop_last) { /* this was the last pbuf in the list */ netif->loop_first = netif->loop_last = NULL; } else { /* pop the pbuf off the list */ netif->loop_first = in_end->next; LWIP_ASSERT("should not be null since first != last!", netif->loop_first != NULL); } /* De-queue the pbuf from its successors on the 'loop_' list. */ in_end->next = NULL; } SYS_ARCH_UNPROTECT(lev); if (in != NULL) { LINK_STATS_INC(link.recv); snmp_add_ifinoctets(stats_if, in->tot_len); snmp_inc_ifinucastpkts(stats_if); /* loopback packets are always IP packets! */ if (ipX_input(in, netif) != ERR_OK) { pbuf_free(in); } /* Don't reference the packet any more! */ in = NULL; } /* go on while there is a packet on the list */ } while (netif->loop_first != NULL); } #if !LWIP_NETIF_LOOPBACK_MULTITHREADING /** * Calls netif_poll() for every netif on the netif_list. */ void netif_poll_all(void) { struct netif *netif = netif_list; /* loop through netifs */ while (netif != NULL) { netif_poll(netif); /* proceed to next network interface */ netif = netif->next; } } #endif /* !LWIP_NETIF_LOOPBACK_MULTITHREADING */ #endif /* ENABLE_LOOPBACK */ #if LWIP_IPV6 s8_t netif_get_ip6_addr_match(struct netif * netif, ip6_addr_t * ip6addr) { s8_t i; for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { if (ip6_addr_cmp(netif_ip6_addr(netif, i), ip6addr)) { return i; } } return -1; } void netif_create_ip6_linklocal_address(struct netif * netif, u8_t from_mac_48bit) { u8_t i, addr_index; /* Link-local prefix. */ netif->ip6_addr[0].addr[0] = PP_HTONL(0xfe800000ul); netif->ip6_addr[0].addr[1] = 0; /* Generate interface ID. */ if (from_mac_48bit) { /* Assume hwaddr is a 48-bit IEEE 802 MAC. Convert to EUI-64 address. Complement Group bit. */ netif->ip6_addr[0].addr[2] = htonl((((u32_t)(netif->hwaddr[0] ^ 0x02)) << 24) | ((u32_t)(netif->hwaddr[1]) << 16) | ((u32_t)(netif->hwaddr[2]) << 8) | (0xff)); netif->ip6_addr[0].addr[3] = htonl((0xfeul << 24) | ((u32_t)(netif->hwaddr[3]) << 16) | ((u32_t)(netif->hwaddr[4]) << 8) | (netif->hwaddr[5])); } else { /* Use hwaddr directly as interface ID. */ netif->ip6_addr[0].addr[2] = 0; netif->ip6_addr[0].addr[3] = 0; addr_index = 3; for (i = 0; i < 8; i++) { if (i == 4) { addr_index--; } netif->ip6_addr[0].addr[addr_index] |= ((u32_t)(netif->hwaddr[netif->hwaddr_len - i - 1])) << (8 * (i & 0x03)); } } /* Set address state. */ #if LWIP_IPV6_DUP_DETECT_ATTEMPTS /* Will perform duplicate address detection (DAD). */ netif->ip6_addr_state[0] = IP6_ADDR_TENTATIVE; #else /* Consider address valid. */ netif->ip6_addr_state[0] = IP6_ADDR_PREFERRED; #endif /* LWIP_IPV6_AUTOCONFIG */ } static err_t netif_null_output_ip6(struct netif *netif, struct pbuf *p, ip6_addr_t *ipaddr) { (void)netif; (void)p; (void)ipaddr; return ERR_IF; } #endif /* LWIP_IPV6 */ ocproxy-1.60/lwip/src/core/pbuf.c000066400000000000000000001173231303453231400167420ustar00rootroot00000000000000/** * @file * Packet buffer management * * Packets are built from the pbuf data structure. It supports dynamic * memory allocation for packet contents or can reference externally * managed packet contents both in RAM and ROM. Quick allocation for * incoming packets is provided through pools with fixed sized pbufs. * * A packet may span over multiple pbufs, chained as a singly linked * list. This is called a "pbuf chain". * * Multiple packets may be queued, also using this singly linked list. * This is called a "packet queue". * * So, a packet queue consists of one or more pbuf chains, each of * which consist of one or more pbufs. CURRENTLY, PACKET QUEUES ARE * NOT SUPPORTED!!! Use helper structs to queue multiple packets. * * The differences between a pbuf chain and a packet queue are very * precise but subtle. * * The last pbuf of a packet has a ->tot_len field that equals the * ->len field. It can be found by traversing the list. If the last * pbuf of a packet has a ->next field other than NULL, more packets * are on the queue. * * Therefore, looping through a pbuf of a single packet, has an * loop end condition (tot_len == p->len), NOT (next == NULL). */ /* * Copyright (c) 2001-2004 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #include "lwip/opt.h" #include "lwip/stats.h" #include "lwip/def.h" #include "lwip/mem.h" #include "lwip/memp.h" #include "lwip/pbuf.h" #include "lwip/sys.h" #include "arch/perf.h" #if LWIP_TCP && TCP_QUEUE_OOSEQ #include "lwip/tcp_impl.h" #endif #if LWIP_CHECKSUM_ON_COPY #include "lwip/inet_chksum.h" #endif #include #define SIZEOF_STRUCT_PBUF LWIP_MEM_ALIGN_SIZE(sizeof(struct pbuf)) /* Since the pool is created in memp, PBUF_POOL_BUFSIZE will be automatically aligned there. Therefore, PBUF_POOL_BUFSIZE_ALIGNED can be used here. */ #define PBUF_POOL_BUFSIZE_ALIGNED LWIP_MEM_ALIGN_SIZE(PBUF_POOL_BUFSIZE) #if !LWIP_TCP || !TCP_QUEUE_OOSEQ || !PBUF_POOL_FREE_OOSEQ #define PBUF_POOL_IS_EMPTY() #else /* !LWIP_TCP || !TCP_QUEUE_OOSEQ || !PBUF_POOL_FREE_OOSEQ */ #if !NO_SYS #ifndef PBUF_POOL_FREE_OOSEQ_QUEUE_CALL #include "lwip/tcpip.h" #define PBUF_POOL_FREE_OOSEQ_QUEUE_CALL() do { \ if(tcpip_callback_with_block(pbuf_free_ooseq_callback, NULL, 0) != ERR_OK) { \ SYS_ARCH_PROTECT(old_level); \ pbuf_free_ooseq_pending = 0; \ SYS_ARCH_UNPROTECT(old_level); \ } } while(0) #endif /* PBUF_POOL_FREE_OOSEQ_QUEUE_CALL */ #endif /* !NO_SYS */ volatile u8_t pbuf_free_ooseq_pending; #define PBUF_POOL_IS_EMPTY() pbuf_pool_is_empty() /** * Attempt to reclaim some memory from queued out-of-sequence TCP segments * if we run out of pool pbufs. It's better to give priority to new packets * if we're running out. * * This must be done in the correct thread context therefore this function * can only be used with NO_SYS=0 and through tcpip_callback. */ #if !NO_SYS static #endif /* !NO_SYS */ void pbuf_free_ooseq(void) { struct tcp_pcb* pcb; SYS_ARCH_DECL_PROTECT(old_level); SYS_ARCH_PROTECT(old_level); pbuf_free_ooseq_pending = 0; SYS_ARCH_UNPROTECT(old_level); for (pcb = tcp_active_pcbs; NULL != pcb; pcb = pcb->next) { if (NULL != pcb->ooseq) { /** Free the ooseq pbufs of one PCB only */ LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_free_ooseq: freeing out-of-sequence pbufs\n")); tcp_segs_free(pcb->ooseq); pcb->ooseq = NULL; return; } } } #if !NO_SYS /** * Just a callback function for tcpip_timeout() that calls pbuf_free_ooseq(). */ static void pbuf_free_ooseq_callback(void *arg) { LWIP_UNUSED_ARG(arg); pbuf_free_ooseq(); } #endif /* !NO_SYS */ /** Queue a call to pbuf_free_ooseq if not already queued. */ static void pbuf_pool_is_empty(void) { #ifndef PBUF_POOL_FREE_OOSEQ_QUEUE_CALL SYS_ARCH_DECL_PROTECT(old_level); SYS_ARCH_PROTECT(old_level); pbuf_free_ooseq_pending = 1; SYS_ARCH_UNPROTECT(old_level); #else /* PBUF_POOL_FREE_OOSEQ_QUEUE_CALL */ u8_t queued; SYS_ARCH_DECL_PROTECT(old_level); SYS_ARCH_PROTECT(old_level); queued = pbuf_free_ooseq_pending; pbuf_free_ooseq_pending = 1; SYS_ARCH_UNPROTECT(old_level); if(!queued) { /* queue a call to pbuf_free_ooseq if not already queued */ PBUF_POOL_FREE_OOSEQ_QUEUE_CALL(); } #endif /* PBUF_POOL_FREE_OOSEQ_QUEUE_CALL */ } #endif /* !LWIP_TCP || !TCP_QUEUE_OOSEQ || !PBUF_POOL_FREE_OOSEQ */ /** * Allocates a pbuf of the given type (possibly a chain for PBUF_POOL type). * * The actual memory allocated for the pbuf is determined by the * layer at which the pbuf is allocated and the requested size * (from the size parameter). * * @param layer flag to define header size * @param length size of the pbuf's payload * @param type this parameter decides how and where the pbuf * should be allocated as follows: * * - PBUF_RAM: buffer memory for pbuf is allocated as one large * chunk. This includes protocol headers as well. * - PBUF_ROM: no buffer memory is allocated for the pbuf, even for * protocol headers. Additional headers must be prepended * by allocating another pbuf and chain in to the front of * the ROM pbuf. It is assumed that the memory used is really * similar to ROM in that it is immutable and will not be * changed. Memory which is dynamic should generally not * be attached to PBUF_ROM pbufs. Use PBUF_REF instead. * - PBUF_REF: no buffer memory is allocated for the pbuf, even for * protocol headers. It is assumed that the pbuf is only * being used in a single thread. If the pbuf gets queued, * then pbuf_take should be called to copy the buffer. * - PBUF_POOL: the pbuf is allocated as a pbuf chain, with pbufs from * the pbuf pool that is allocated during pbuf_init(). * * @return the allocated pbuf. If multiple pbufs where allocated, this * is the first pbuf of a pbuf chain. */ struct pbuf * pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type) { struct pbuf *p, *q, *r; u16_t offset; s32_t rem_len; /* remaining length */ LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloc(length=%"U16_F")\n", length)); /* determine header offset */ switch (layer) { case PBUF_TRANSPORT: /* add room for transport (often TCP) layer header */ offset = PBUF_LINK_HLEN + PBUF_IP_HLEN + PBUF_TRANSPORT_HLEN; break; case PBUF_IP: /* add room for IP layer header */ offset = PBUF_LINK_HLEN + PBUF_IP_HLEN; break; case PBUF_LINK: /* add room for link layer header */ offset = PBUF_LINK_HLEN; break; case PBUF_RAW: offset = 0; break; default: LWIP_ASSERT("pbuf_alloc: bad pbuf layer", 0); return NULL; } switch (type) { case PBUF_POOL: /* allocate head of pbuf chain into p */ p = (struct pbuf *)memp_malloc(MEMP_PBUF_POOL); LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloc: allocated pbuf %p\n", (void *)p)); if (p == NULL) { PBUF_POOL_IS_EMPTY(); return NULL; } p->type = type; p->next = NULL; /* make the payload pointer point 'offset' bytes into pbuf data memory */ p->payload = LWIP_MEM_ALIGN((void *)((u8_t *)p + (SIZEOF_STRUCT_PBUF + offset))); LWIP_ASSERT("pbuf_alloc: pbuf p->payload properly aligned", ((mem_ptr_t)p->payload % MEM_ALIGNMENT) == 0); /* the total length of the pbuf chain is the requested size */ p->tot_len = length; /* set the length of the first pbuf in the chain */ p->len = LWIP_MIN(length, PBUF_POOL_BUFSIZE_ALIGNED - LWIP_MEM_ALIGN_SIZE(offset)); LWIP_ASSERT("check p->payload + p->len does not overflow pbuf", ((u8_t*)p->payload + p->len <= (u8_t*)p + SIZEOF_STRUCT_PBUF + PBUF_POOL_BUFSIZE_ALIGNED)); LWIP_ASSERT("PBUF_POOL_BUFSIZE must be bigger than MEM_ALIGNMENT", (PBUF_POOL_BUFSIZE_ALIGNED - LWIP_MEM_ALIGN_SIZE(offset)) > 0 ); /* set reference count (needed here in case we fail) */ p->ref = 1; /* now allocate the tail of the pbuf chain */ /* remember first pbuf for linkage in next iteration */ r = p; /* remaining length to be allocated */ rem_len = length - p->len; /* any remaining pbufs to be allocated? */ while (rem_len > 0) { q = (struct pbuf *)memp_malloc(MEMP_PBUF_POOL); if (q == NULL) { PBUF_POOL_IS_EMPTY(); /* free chain so far allocated */ pbuf_free(p); /* bail out unsuccesfully */ return NULL; } q->type = type; q->flags = 0; q->next = NULL; /* make previous pbuf point to this pbuf */ r->next = q; /* set total length of this pbuf and next in chain */ LWIP_ASSERT("rem_len < max_u16_t", rem_len < 0xffff); q->tot_len = (u16_t)rem_len; /* this pbuf length is pool size, unless smaller sized tail */ q->len = LWIP_MIN((u16_t)rem_len, PBUF_POOL_BUFSIZE_ALIGNED); q->payload = (void *)((u8_t *)q + SIZEOF_STRUCT_PBUF); LWIP_ASSERT("pbuf_alloc: pbuf q->payload properly aligned", ((mem_ptr_t)q->payload % MEM_ALIGNMENT) == 0); LWIP_ASSERT("check p->payload + p->len does not overflow pbuf", ((u8_t*)p->payload + p->len <= (u8_t*)p + SIZEOF_STRUCT_PBUF + PBUF_POOL_BUFSIZE_ALIGNED)); q->ref = 1; /* calculate remaining length to be allocated */ rem_len -= q->len; /* remember this pbuf for linkage in next iteration */ r = q; } /* end of chain */ /*r->next = NULL;*/ break; case PBUF_RAM: /* If pbuf is to be allocated in RAM, allocate memory for it. */ p = (struct pbuf*)mem_malloc(LWIP_MEM_ALIGN_SIZE(SIZEOF_STRUCT_PBUF + offset) + LWIP_MEM_ALIGN_SIZE(length)); if (p == NULL) { return NULL; } /* Set up internal structure of the pbuf. */ p->payload = LWIP_MEM_ALIGN((void *)((u8_t *)p + SIZEOF_STRUCT_PBUF + offset)); p->len = p->tot_len = length; p->next = NULL; p->type = type; LWIP_ASSERT("pbuf_alloc: pbuf->payload properly aligned", ((mem_ptr_t)p->payload % MEM_ALIGNMENT) == 0); break; /* pbuf references existing (non-volatile static constant) ROM payload? */ case PBUF_ROM: /* pbuf references existing (externally allocated) RAM payload? */ case PBUF_REF: /* only allocate memory for the pbuf structure */ p = (struct pbuf *)memp_malloc(MEMP_PBUF); if (p == NULL) { LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("pbuf_alloc: Could not allocate MEMP_PBUF for PBUF_%s.\n", (type == PBUF_ROM) ? "ROM" : "REF")); return NULL; } /* caller must set this field properly, afterwards */ p->payload = NULL; p->len = p->tot_len = length; p->next = NULL; p->type = type; break; default: LWIP_ASSERT("pbuf_alloc: erroneous type", 0); return NULL; } /* set reference count */ p->ref = 1; /* set flags */ p->flags = 0; LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloc(length=%"U16_F") == %p\n", length, (void *)p)); return p; } #if LWIP_SUPPORT_CUSTOM_PBUF /** Initialize a custom pbuf (already allocated). * * @param layer flag to define header size * @param length size of the pbuf's payload * @param type type of the pbuf (only used to treat the pbuf accordingly, as * this function allocates no memory) * @param p pointer to the custom pbuf to initialize (already allocated) * @param payload_mem pointer to the buffer that is used for payload and headers, * must be at least big enough to hold 'length' plus the header size, * may be NULL if set later. * ATTENTION: The caller is responsible for correct alignment of this buffer!! * @param payload_mem_len the size of the 'payload_mem' buffer, must be at least * big enough to hold 'length' plus the header size */ struct pbuf* pbuf_alloced_custom(pbuf_layer l, u16_t length, pbuf_type type, struct pbuf_custom *p, void *payload_mem, u16_t payload_mem_len) { u16_t offset; LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloced_custom(length=%"U16_F")\n", length)); /* determine header offset */ switch (l) { case PBUF_TRANSPORT: /* add room for transport (often TCP) layer header */ offset = PBUF_LINK_HLEN + PBUF_IP_HLEN + PBUF_TRANSPORT_HLEN; break; case PBUF_IP: /* add room for IP layer header */ offset = PBUF_LINK_HLEN + PBUF_IP_HLEN; break; case PBUF_LINK: /* add room for link layer header */ offset = PBUF_LINK_HLEN; break; case PBUF_RAW: offset = 0; break; default: LWIP_ASSERT("pbuf_alloced_custom: bad pbuf layer", 0); return NULL; } if (LWIP_MEM_ALIGN_SIZE(offset) + length > payload_mem_len) { LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_LEVEL_WARNING, ("pbuf_alloced_custom(length=%"U16_F") buffer too short\n", length)); return NULL; } p->pbuf.next = NULL; if (payload_mem != NULL) { p->pbuf.payload = (u8_t *)payload_mem + LWIP_MEM_ALIGN_SIZE(offset); } else { p->pbuf.payload = NULL; } p->pbuf.flags = PBUF_FLAG_IS_CUSTOM; p->pbuf.len = p->pbuf.tot_len = length; p->pbuf.type = type; p->pbuf.ref = 1; return &p->pbuf; } #endif /* LWIP_SUPPORT_CUSTOM_PBUF */ /** * Shrink a pbuf chain to a desired length. * * @param p pbuf to shrink. * @param new_len desired new length of pbuf chain * * Depending on the desired length, the first few pbufs in a chain might * be skipped and left unchanged. The new last pbuf in the chain will be * resized, and any remaining pbufs will be freed. * * @note If the pbuf is ROM/REF, only the ->tot_len and ->len fields are adjusted. * @note May not be called on a packet queue. * * @note Despite its name, pbuf_realloc cannot grow the size of a pbuf (chain). */ void pbuf_realloc(struct pbuf *p, u16_t new_len) { struct pbuf *q; u16_t rem_len; /* remaining length */ s32_t grow; LWIP_ASSERT("pbuf_realloc: p != NULL", p != NULL); LWIP_ASSERT("pbuf_realloc: sane p->type", p->type == PBUF_POOL || p->type == PBUF_ROM || p->type == PBUF_RAM || p->type == PBUF_REF); /* desired length larger than current length? */ if (new_len >= p->tot_len) { /* enlarging not yet supported */ return; } /* the pbuf chain grows by (new_len - p->tot_len) bytes * (which may be negative in case of shrinking) */ grow = new_len - p->tot_len; /* first, step over any pbufs that should remain in the chain */ rem_len = new_len; q = p; /* should this pbuf be kept? */ while (rem_len > q->len) { /* decrease remaining length by pbuf length */ rem_len -= q->len; /* decrease total length indicator */ LWIP_ASSERT("grow < max_u16_t", grow < 0xffff); q->tot_len += (u16_t)grow; /* proceed to next pbuf in chain */ q = q->next; LWIP_ASSERT("pbuf_realloc: q != NULL", q != NULL); } /* we have now reached the new last pbuf (in q) */ /* rem_len == desired length for pbuf q */ /* shrink allocated memory for PBUF_RAM */ /* (other types merely adjust their length fields */ if ((q->type == PBUF_RAM) && (rem_len != q->len)) { /* reallocate and adjust the length of the pbuf that will be split */ q = (struct pbuf *)mem_trim(q, (u16_t)((u8_t *)q->payload - (u8_t *)q) + rem_len); LWIP_ASSERT("mem_trim returned q == NULL", q != NULL); } /* adjust length fields for new last pbuf */ q->len = rem_len; q->tot_len = q->len; /* any remaining pbufs in chain? */ if (q->next != NULL) { /* free remaining pbufs in chain */ pbuf_free(q->next); } /* q is last packet in chain */ q->next = NULL; } /** * Adjusts the payload pointer to hide or reveal headers in the payload. * * Adjusts the ->payload pointer so that space for a header * (dis)appears in the pbuf payload. * * The ->payload, ->tot_len and ->len fields are adjusted. * * @param p pbuf to change the header size. * @param header_size_increment Number of bytes to increment header size which * increases the size of the pbuf. New space is on the front. * (Using a negative value decreases the header size.) * If hdr_size_inc is 0, this function does nothing and returns succesful. * * PBUF_ROM and PBUF_REF type buffers cannot have their sizes increased, so * the call will fail. A check is made that the increase in header size does * not move the payload pointer in front of the start of the buffer. * @return non-zero on failure, zero on success. * */ u8_t pbuf_header(struct pbuf *p, s16_t header_size_increment) { u16_t type; void *payload; u16_t increment_magnitude; LWIP_ASSERT("p != NULL", p != NULL); if ((header_size_increment == 0) || (p == NULL)) { return 0; } if (header_size_increment < 0){ increment_magnitude = -header_size_increment; /* Check that we aren't going to move off the end of the pbuf */ LWIP_ERROR("increment_magnitude <= p->len", (increment_magnitude <= p->len), return 1;); } else { increment_magnitude = header_size_increment; #if 0 /* Can't assert these as some callers speculatively call pbuf_header() to see if it's OK. Will return 1 below instead. */ /* Check that we've got the correct type of pbuf to work with */ LWIP_ASSERT("p->type == PBUF_RAM || p->type == PBUF_POOL", p->type == PBUF_RAM || p->type == PBUF_POOL); /* Check that we aren't going to move off the beginning of the pbuf */ LWIP_ASSERT("p->payload - increment_magnitude >= p + SIZEOF_STRUCT_PBUF", (u8_t *)p->payload - increment_magnitude >= (u8_t *)p + SIZEOF_STRUCT_PBUF); #endif } type = p->type; /* remember current payload pointer */ payload = p->payload; /* pbuf types containing payloads? */ if (type == PBUF_RAM || type == PBUF_POOL) { /* set new payload pointer */ p->payload = (u8_t *)p->payload - header_size_increment; /* boundary check fails? */ if ((u8_t *)p->payload < (u8_t *)p + SIZEOF_STRUCT_PBUF) { LWIP_DEBUGF( PBUF_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("pbuf_header: failed as %p < %p (not enough space for new header size)\n", (void *)p->payload, (void *)(p + 1))); /* restore old payload pointer */ p->payload = payload; /* bail out unsuccesfully */ return 1; } /* pbuf types refering to external payloads? */ } else if (type == PBUF_REF || type == PBUF_ROM) { /* hide a header in the payload? */ if ((header_size_increment < 0) && (increment_magnitude <= p->len)) { /* increase payload pointer */ p->payload = (u8_t *)p->payload - header_size_increment; } else { /* cannot expand payload to front (yet!) * bail out unsuccesfully */ return 1; } } else { /* Unknown type */ LWIP_ASSERT("bad pbuf type", 0); return 1; } /* modify pbuf length fields */ p->len += header_size_increment; p->tot_len += header_size_increment; LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_header: old %p new %p (%"S16_F")\n", (void *)payload, (void *)p->payload, header_size_increment)); return 0; } /** * Dereference a pbuf chain or queue and deallocate any no-longer-used * pbufs at the head of this chain or queue. * * Decrements the pbuf reference count. If it reaches zero, the pbuf is * deallocated. * * For a pbuf chain, this is repeated for each pbuf in the chain, * up to the first pbuf which has a non-zero reference count after * decrementing. So, when all reference counts are one, the whole * chain is free'd. * * @param p The pbuf (chain) to be dereferenced. * * @return the number of pbufs that were de-allocated * from the head of the chain. * * @note MUST NOT be called on a packet queue (Not verified to work yet). * @note the reference counter of a pbuf equals the number of pointers * that refer to the pbuf (or into the pbuf). * * @internal examples: * * Assuming existing chains a->b->c with the following reference * counts, calling pbuf_free(a) results in: * * 1->2->3 becomes ...1->3 * 3->3->3 becomes 2->3->3 * 1->1->2 becomes ......1 * 2->1->1 becomes 1->1->1 * 1->1->1 becomes ....... * */ u8_t pbuf_free(struct pbuf *p) { u16_t type; struct pbuf *q; u8_t count; if (p == NULL) { LWIP_ASSERT("p != NULL", p != NULL); /* if assertions are disabled, proceed with debug output */ LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("pbuf_free(p == NULL) was called.\n")); return 0; } LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_free(%p)\n", (void *)p)); PERF_START; LWIP_ASSERT("pbuf_free: sane type", p->type == PBUF_RAM || p->type == PBUF_ROM || p->type == PBUF_REF || p->type == PBUF_POOL); count = 0; /* de-allocate all consecutive pbufs from the head of the chain that * obtain a zero reference count after decrementing*/ while (p != NULL) { u16_t ref; SYS_ARCH_DECL_PROTECT(old_level); /* Since decrementing ref cannot be guaranteed to be a single machine operation * we must protect it. We put the new ref into a local variable to prevent * further protection. */ SYS_ARCH_PROTECT(old_level); /* all pbufs in a chain are referenced at least once */ LWIP_ASSERT("pbuf_free: p->ref > 0", p->ref > 0); /* decrease reference count (number of pointers to pbuf) */ ref = --(p->ref); SYS_ARCH_UNPROTECT(old_level); /* this pbuf is no longer referenced to? */ if (ref == 0) { /* remember next pbuf in chain for next iteration */ q = p->next; LWIP_DEBUGF( PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_free: deallocating %p\n", (void *)p)); type = p->type; #if LWIP_SUPPORT_CUSTOM_PBUF /* is this a custom pbuf? */ if ((p->flags & PBUF_FLAG_IS_CUSTOM) != 0) { struct pbuf_custom *pc = (struct pbuf_custom*)p; LWIP_ASSERT("pc->custom_free_function != NULL", pc->custom_free_function != NULL); pc->custom_free_function(p); } else #endif /* LWIP_SUPPORT_CUSTOM_PBUF */ { /* is this a pbuf from the pool? */ if (type == PBUF_POOL) { memp_free(MEMP_PBUF_POOL, p); /* is this a ROM or RAM referencing pbuf? */ } else if (type == PBUF_ROM || type == PBUF_REF) { memp_free(MEMP_PBUF, p); /* type == PBUF_RAM */ } else { mem_free(p); } } count++; /* proceed to next pbuf */ p = q; /* p->ref > 0, this pbuf is still referenced to */ /* (and so the remaining pbufs in chain as well) */ } else { LWIP_DEBUGF( PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_free: %p has ref %"U16_F", ending here.\n", (void *)p, ref)); /* stop walking through the chain */ p = NULL; } } PERF_STOP("pbuf_free"); /* return number of de-allocated pbufs */ return count; } /** * Count number of pbufs in a chain * * @param p first pbuf of chain * @return the number of pbufs in a chain */ u8_t pbuf_clen(struct pbuf *p) { u8_t len; len = 0; while (p != NULL) { ++len; p = p->next; } return len; } /** * Increment the reference count of the pbuf. * * @param p pbuf to increase reference counter of * */ void pbuf_ref(struct pbuf *p) { SYS_ARCH_DECL_PROTECT(old_level); /* pbuf given? */ if (p != NULL) { SYS_ARCH_PROTECT(old_level); ++(p->ref); SYS_ARCH_UNPROTECT(old_level); } } /** * Concatenate two pbufs (each may be a pbuf chain) and take over * the caller's reference of the tail pbuf. * * @note The caller MAY NOT reference the tail pbuf afterwards. * Use pbuf_chain() for that purpose. * * @see pbuf_chain() */ void pbuf_cat(struct pbuf *h, struct pbuf *t) { struct pbuf *p; LWIP_ERROR("(h != NULL) && (t != NULL) (programmer violates API)", ((h != NULL) && (t != NULL)), return;); /* proceed to last pbuf of chain */ for (p = h; p->next != NULL; p = p->next) { /* add total length of second chain to all totals of first chain */ p->tot_len += t->tot_len; } /* { p is last pbuf of first h chain, p->next == NULL } */ LWIP_ASSERT("p->tot_len == p->len (of last pbuf in chain)", p->tot_len == p->len); LWIP_ASSERT("p->next == NULL", p->next == NULL); /* add total length of second chain to last pbuf total of first chain */ p->tot_len += t->tot_len; /* chain last pbuf of head (p) with first of tail (t) */ p->next = t; /* p->next now references t, but the caller will drop its reference to t, * so netto there is no change to the reference count of t. */ } /** * Chain two pbufs (or pbuf chains) together. * * The caller MUST call pbuf_free(t) once it has stopped * using it. Use pbuf_cat() instead if you no longer use t. * * @param h head pbuf (chain) * @param t tail pbuf (chain) * @note The pbufs MUST belong to the same packet. * @note MAY NOT be called on a packet queue. * * The ->tot_len fields of all pbufs of the head chain are adjusted. * The ->next field of the last pbuf of the head chain is adjusted. * The ->ref field of the first pbuf of the tail chain is adjusted. * */ void pbuf_chain(struct pbuf *h, struct pbuf *t) { pbuf_cat(h, t); /* t is now referenced by h */ pbuf_ref(t); LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_chain: %p references %p\n", (void *)h, (void *)t)); } /** * Dechains the first pbuf from its succeeding pbufs in the chain. * * Makes p->tot_len field equal to p->len. * @param p pbuf to dechain * @return remainder of the pbuf chain, or NULL if it was de-allocated. * @note May not be called on a packet queue. */ struct pbuf * pbuf_dechain(struct pbuf *p) { struct pbuf *q; u8_t tail_gone = 1; /* tail */ q = p->next; /* pbuf has successor in chain? */ if (q != NULL) { /* assert tot_len invariant: (p->tot_len == p->len + (p->next? p->next->tot_len: 0) */ LWIP_ASSERT("p->tot_len == p->len + q->tot_len", q->tot_len == p->tot_len - p->len); /* enforce invariant if assertion is disabled */ q->tot_len = p->tot_len - p->len; /* decouple pbuf from remainder */ p->next = NULL; /* total length of pbuf p is its own length only */ p->tot_len = p->len; /* q is no longer referenced by p, free it */ LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_dechain: unreferencing %p\n", (void *)q)); tail_gone = pbuf_free(q); if (tail_gone > 0) { LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_dechain: deallocated %p (as it is no longer referenced)\n", (void *)q)); } /* return remaining tail or NULL if deallocated */ } /* assert tot_len invariant: (p->tot_len == p->len + (p->next? p->next->tot_len: 0) */ LWIP_ASSERT("p->tot_len == p->len", p->tot_len == p->len); return ((tail_gone > 0) ? NULL : q); } /** * * Create PBUF_RAM copies of pbufs. * * Used to queue packets on behalf of the lwIP stack, such as * ARP based queueing. * * @note You MUST explicitly use p = pbuf_take(p); * * @note Only one packet is copied, no packet queue! * * @param p_to pbuf destination of the copy * @param p_from pbuf source of the copy * * @return ERR_OK if pbuf was copied * ERR_ARG if one of the pbufs is NULL or p_to is not big * enough to hold p_from */ err_t pbuf_copy(struct pbuf *p_to, struct pbuf *p_from) { u16_t offset_to=0, offset_from=0, len; LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_copy(%p, %p)\n", (void*)p_to, (void*)p_from)); /* is the target big enough to hold the source? */ LWIP_ERROR("pbuf_copy: target not big enough to hold source", ((p_to != NULL) && (p_from != NULL) && (p_to->tot_len >= p_from->tot_len)), return ERR_ARG;); /* iterate through pbuf chain */ do { /* copy one part of the original chain */ if ((p_to->len - offset_to) >= (p_from->len - offset_from)) { /* complete current p_from fits into current p_to */ len = p_from->len - offset_from; } else { /* current p_from does not fit into current p_to */ len = p_to->len - offset_to; } MEMCPY((u8_t*)p_to->payload + offset_to, (u8_t*)p_from->payload + offset_from, len); offset_to += len; offset_from += len; LWIP_ASSERT("offset_to <= p_to->len", offset_to <= p_to->len); LWIP_ASSERT("offset_from <= p_from->len", offset_from <= p_from->len); if (offset_from >= p_from->len) { /* on to next p_from (if any) */ offset_from = 0; p_from = p_from->next; } if (offset_to == p_to->len) { /* on to next p_to (if any) */ offset_to = 0; p_to = p_to->next; LWIP_ERROR("p_to != NULL", (p_to != NULL) || (p_from == NULL) , return ERR_ARG;); } if((p_from != NULL) && (p_from->len == p_from->tot_len)) { /* don't copy more than one packet! */ LWIP_ERROR("pbuf_copy() does not allow packet queues!", (p_from->next == NULL), return ERR_VAL;); } if((p_to != NULL) && (p_to->len == p_to->tot_len)) { /* don't copy more than one packet! */ LWIP_ERROR("pbuf_copy() does not allow packet queues!", (p_to->next == NULL), return ERR_VAL;); } } while (p_from); LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_copy: end of chain reached.\n")); return ERR_OK; } /** * Copy (part of) the contents of a packet buffer * to an application supplied buffer. * * @param buf the pbuf from which to copy data * @param dataptr the application supplied buffer * @param len length of data to copy (dataptr must be big enough). No more * than buf->tot_len will be copied, irrespective of len * @param offset offset into the packet buffer from where to begin copying len bytes * @return the number of bytes copied, or 0 on failure */ u16_t pbuf_copy_partial(struct pbuf *buf, void *dataptr, u16_t len, u16_t offset) { struct pbuf *p; u16_t left; u16_t buf_copy_len; u16_t copied_total = 0; LWIP_ERROR("pbuf_copy_partial: invalid buf", (buf != NULL), return 0;); LWIP_ERROR("pbuf_copy_partial: invalid dataptr", (dataptr != NULL), return 0;); left = 0; if((buf == NULL) || (dataptr == NULL)) { return 0; } /* Note some systems use byte copy if dataptr or one of the pbuf payload pointers are unaligned. */ for(p = buf; len != 0 && p != NULL; p = p->next) { if ((offset != 0) && (offset >= p->len)) { /* don't copy from this buffer -> on to the next */ offset -= p->len; } else { /* copy from this buffer. maybe only partially. */ buf_copy_len = p->len - offset; if (buf_copy_len > len) buf_copy_len = len; /* copy the necessary parts of the buffer */ MEMCPY(&((char*)dataptr)[left], &((char*)p->payload)[offset], buf_copy_len); copied_total += buf_copy_len; left += buf_copy_len; len -= buf_copy_len; offset = 0; } } return copied_total; } #if LWIP_TCP && TCP_QUEUE_OOSEQ && LWIP_WND_SCALE /** * This method modifies a 'pbuf chain', so that its total length is * smaller than 64K. The remainder of the original pbuf chain is stored * in *rest. * This function never creates new pbufs, but splits an existing chain * in two parts. The tot_len of the modified packet queue will likely be * smaller than 64K. * 'packet queues' are not supported by this function. * * @param p the pbuf queue to be splitted * @param rest pointer to store the remainder (after the first 64K) */ void pbuf_split_64k(struct pbuf *p, struct pbuf **rest) { *rest = NULL; if ((p != NULL) && (p->next != NULL)) { u16_t tot_len_front = p->len; struct pbuf *i = p; struct pbuf *r = p->next; /* continue until the total length (summed up as u16_t) overflows */ while ((r != NULL) && ((u16_t)(tot_len_front + r->len) > tot_len_front)) { tot_len_front += r->len; i = r; r = r->next; } /* i now points to last packet of the first segment. Set next pointer to NULL */ i->next = NULL; if (r != NULL) { /* Update the tot_len field in the first part */ for (i = p; i != NULL; i = i->next) { i->tot_len -= r->tot_len; LWIP_ASSERT("tot_len/len mismatch in last pbuf", (i->next != NULL) || (i->tot_len == i->len)); } if (p->flags & PBUF_FLAG_TCP_FIN) { r->flags |= PBUF_FLAG_TCP_FIN; } /* tot_len field in rest does not need modifications */ /* reference counters do not need modifications */ *rest = r; } } } #endif /* LWIP_TCP && TCP_QUEUE_OOSEQ && LWIP_WND_SCALE */ /** * Copy application supplied data into a pbuf. * This function can only be used to copy the equivalent of buf->tot_len data. * * @param buf pbuf to fill with data * @param dataptr application supplied data buffer * @param len length of the application supplied data buffer * * @return ERR_OK if successful, ERR_MEM if the pbuf is not big enough */ err_t pbuf_take(struct pbuf *buf, const void *dataptr, u16_t len) { struct pbuf *p; u16_t buf_copy_len; u16_t total_copy_len = len; u16_t copied_total = 0; LWIP_ERROR("pbuf_take: invalid buf", (buf != NULL), return 0;); LWIP_ERROR("pbuf_take: invalid dataptr", (dataptr != NULL), return 0;); if ((buf == NULL) || (dataptr == NULL) || (buf->tot_len < len)) { return ERR_ARG; } /* Note some systems use byte copy if dataptr or one of the pbuf payload pointers are unaligned. */ for(p = buf; total_copy_len != 0; p = p->next) { LWIP_ASSERT("pbuf_take: invalid pbuf", p != NULL); buf_copy_len = total_copy_len; if (buf_copy_len > p->len) { /* this pbuf cannot hold all remaining data */ buf_copy_len = p->len; } /* copy the necessary parts of the buffer */ MEMCPY(p->payload, &((char*)dataptr)[copied_total], buf_copy_len); total_copy_len -= buf_copy_len; copied_total += buf_copy_len; } LWIP_ASSERT("did not copy all data", total_copy_len == 0 && copied_total == len); return ERR_OK; } /** * Creates a single pbuf out of a queue of pbufs. * * @remark: Either the source pbuf 'p' is freed by this function or the original * pbuf 'p' is returned, therefore the caller has to check the result! * * @param p the source pbuf * @param layer pbuf_layer of the new pbuf * * @return a new, single pbuf (p->next is NULL) * or the old pbuf if allocation fails */ struct pbuf* pbuf_coalesce(struct pbuf *p, pbuf_layer layer) { struct pbuf *q; err_t err; if (p->next == NULL) { return p; } q = pbuf_alloc(layer, p->tot_len, PBUF_RAM); if (q == NULL) { /* @todo: what do we do now? */ return p; } err = pbuf_copy(q, p); LWIP_ASSERT("pbuf_copy failed", err == ERR_OK); pbuf_free(p); return q; } #if LWIP_CHECKSUM_ON_COPY /** * Copies data into a single pbuf (*not* into a pbuf queue!) and updates * the checksum while copying * * @param p the pbuf to copy data into * @param start_offset offset of p->payload where to copy the data to * @param dataptr data to copy into the pbuf * @param len length of data to copy into the pbuf * @param chksum pointer to the checksum which is updated * @return ERR_OK if successful, another error if the data does not fit * within the (first) pbuf (no pbuf queues!) */ err_t pbuf_fill_chksum(struct pbuf *p, u16_t start_offset, const void *dataptr, u16_t len, u16_t *chksum) { u32_t acc; u16_t copy_chksum; char *dst_ptr; LWIP_ASSERT("p != NULL", p != NULL); LWIP_ASSERT("dataptr != NULL", dataptr != NULL); LWIP_ASSERT("chksum != NULL", chksum != NULL); LWIP_ASSERT("len != 0", len != 0); if ((start_offset >= p->len) || (start_offset + len > p->len)) { return ERR_ARG; } dst_ptr = ((char*)p->payload) + start_offset; copy_chksum = LWIP_CHKSUM_COPY(dst_ptr, dataptr, len); if ((start_offset & 1) != 0) { copy_chksum = SWAP_BYTES_IN_WORD(copy_chksum); } acc = *chksum; acc += copy_chksum; *chksum = FOLD_U32T(acc); return ERR_OK; } #endif /* LWIP_CHECKSUM_ON_COPY */ /** Get one byte from the specified position in a pbuf * WARNING: returns zero for offset >= p->tot_len * * @param p pbuf to parse * @param offset offset into p of the byte to return * @return byte at an offset into p OR ZERO IF 'offset' >= p->tot_len */ u8_t pbuf_get_at(struct pbuf* p, u16_t offset) { u16_t copy_from = offset; struct pbuf* q = p; /* get the correct pbuf */ while ((q != NULL) && (q->len <= copy_from)) { copy_from -= q->len; q = q->next; } /* return requested data if pbuf is OK */ if ((q != NULL) && (q->len > copy_from)) { return ((u8_t*)q->payload)[copy_from]; } return 0; } /** Compare pbuf contents at specified offset with memory s2, both of length n * * @param p pbuf to compare * @param offset offset into p at wich to start comparing * @param s2 buffer to compare * @param n length of buffer to compare * @return zero if equal, nonzero otherwise * (0xffff if p is too short, diffoffset+1 otherwise) */ u16_t pbuf_memcmp(struct pbuf* p, u16_t offset, const void* s2, u16_t n) { u16_t start = offset; struct pbuf* q = p; /* get the correct pbuf */ while ((q != NULL) && (q->len <= start)) { start -= q->len; q = q->next; } /* return requested data if pbuf is OK */ if ((q != NULL) && (q->len > start)) { u16_t i; for(i = 0; i < n; i++) { u8_t a = pbuf_get_at(q, start + i); u8_t b = ((u8_t*)s2)[i]; if (a != b) { return i+1; } } return 0; } return 0xffff; } /** Find occurrence of mem (with length mem_len) in pbuf p, starting at offset * start_offset. * * @param p pbuf to search, maximum length is 0xFFFE since 0xFFFF is used as * return value 'not found' * @param mem search for the contents of this buffer * @param mem_len length of 'mem' * @param start_offset offset into p at which to start searching * @return 0xFFFF if substr was not found in p or the index where it was found */ u16_t pbuf_memfind(struct pbuf* p, const void* mem, u16_t mem_len, u16_t start_offset) { u16_t i; u16_t max = p->tot_len - mem_len; if (p->tot_len >= mem_len + start_offset) { for(i = start_offset; i <= max; i++) { u16_t plus = pbuf_memcmp(p, i, mem, mem_len); if (plus == 0) { return i; } } } return 0xFFFF; } /** Find occurrence of substr with length substr_len in pbuf p, start at offset * start_offset * WARNING: in contrast to strstr(), this one does not stop at the first \0 in * the pbuf/source string! * * @param p pbuf to search, maximum length is 0xFFFE since 0xFFFF is used as * return value 'not found' * @param substr string to search for in p, maximum length is 0xFFFE * @return 0xFFFF if substr was not found in p or the index where it was found */ u16_t pbuf_strstr(struct pbuf* p, const char* substr) { size_t substr_len; if ((substr == NULL) || (substr[0] == 0) || (p->tot_len == 0xFFFF)) { return 0xFFFF; } substr_len = strlen(substr); if (substr_len >= 0xFFFF) { return 0xFFFF; } return pbuf_memfind(p, substr, (u16_t)substr_len, 0); } ocproxy-1.60/lwip/src/core/raw.c000066400000000000000000000315421303453231400165750ustar00rootroot00000000000000/** * @file * Implementation of raw protocol PCBs for low-level handling of * different types of protocols besides (or overriding) those * already available in lwIP. * */ /* * Copyright (c) 2001-2004 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #include "lwip/opt.h" #if LWIP_RAW /* don't build if not configured for use in lwipopts.h */ #include "lwip/def.h" #include "lwip/memp.h" #include "lwip/ip_addr.h" #include "lwip/netif.h" #include "lwip/raw.h" #include "lwip/stats.h" #include "arch/perf.h" #include "lwip/ip6.h" #include "lwip/ip6_addr.h" #include "lwip/inet_chksum.h" #include /** The list of RAW PCBs */ static struct raw_pcb *raw_pcbs; /** * Determine if in incoming IP packet is covered by a RAW PCB * and if so, pass it to a user-provided receive callback function. * * Given an incoming IP datagram (as a chain of pbufs) this function * finds a corresponding RAW PCB and calls the corresponding receive * callback function. * * @param p pbuf to be demultiplexed to a RAW PCB. * @param inp network interface on which the datagram was received. * @return - 1 if the packet has been eaten by a RAW PCB receive * callback function. The caller MAY NOT not reference the * packet any longer, and MAY NOT call pbuf_free(). * @return - 0 if packet is not eaten (pbuf is still referenced by the * caller). * */ u8_t raw_input(struct pbuf *p, struct netif *inp) { struct raw_pcb *pcb, *prev; struct ip_hdr *iphdr; s16_t proto; u8_t eaten = 0; LWIP_UNUSED_ARG(inp); iphdr = (struct ip_hdr *)p->payload; #if LWIP_IPV6 if (IPH_V(iphdr) == 6) { struct ip6_hdr *ip6hdr = (struct ip6_hdr *)p->payload; proto = IP6H_NEXTH(ip6hdr); iphdr = NULL; } else #endif /* LWIP_IPV6 */ { proto = IPH_PROTO(iphdr); } prev = NULL; pcb = raw_pcbs; /* loop through all raw pcbs until the packet is eaten by one */ /* this allows multiple pcbs to match against the packet by design */ while ((eaten == 0) && (pcb != NULL)) { if ((pcb->protocol == proto) && IP_PCB_IPVER_INPUT_MATCH(pcb) && (ipX_addr_isany(PCB_ISIPV6(pcb), &pcb->local_ip) || ipX_addr_cmp(PCB_ISIPV6(pcb), &(pcb->local_ip), ipX_current_dest_addr()))) { #if IP_SOF_BROADCAST_RECV /* broadcast filter? */ if ((ip_get_option(pcb, SOF_BROADCAST) || !ip_addr_isbroadcast(ip_current_dest_addr(), inp)) #if LWIP_IPV6 || PCB_ISIPV6(pcb) #endif /* LWIP_IPV6 */ ) #endif /* IP_SOF_BROADCAST_RECV */ { /* receive callback function available? */ if (pcb->recv.ip4 != NULL) { #ifndef LWIP_NOASSERT void* old_payload = p->payload; #endif /* the receive callback function did not eat the packet? */ #if LWIP_IPV6 if (PCB_ISIPV6(pcb)) { eaten = pcb->recv.ip6(pcb->recv_arg, pcb, p, ip6_current_src_addr()); } else #endif /* LWIP_IPV6 */ { eaten = pcb->recv.ip4(pcb->recv_arg, pcb, p, ip_current_src_addr()); } if (eaten != 0) { /* receive function ate the packet */ p = NULL; eaten = 1; if (prev != NULL) { /* move the pcb to the front of raw_pcbs so that is found faster next time */ prev->next = pcb->next; pcb->next = raw_pcbs; raw_pcbs = pcb; } } else { /* sanity-check that the receive callback did not alter the pbuf */ LWIP_ASSERT("raw pcb recv callback altered pbuf payload pointer without eating packet", p->payload == old_payload); } } /* no receive callback function was set for this raw PCB */ } /* drop the packet */ } prev = pcb; pcb = pcb->next; } return eaten; } /** * Bind a RAW PCB. * * @param pcb RAW PCB to be bound with a local address ipaddr. * @param ipaddr local IP address to bind with. Use IP_ADDR_ANY to * bind to all local interfaces. * * @return lwIP error code. * - ERR_OK. Successful. No error occured. * - ERR_USE. The specified IP address is already bound to by * another RAW PCB. * * @see raw_disconnect() */ err_t raw_bind(struct raw_pcb *pcb, ip_addr_t *ipaddr) { ipX_addr_set_ipaddr(PCB_ISIPV6(pcb), &pcb->local_ip, ipaddr); return ERR_OK; } /** * Connect an RAW PCB. This function is required by upper layers * of lwip. Using the raw api you could use raw_sendto() instead * * This will associate the RAW PCB with the remote address. * * @param pcb RAW PCB to be connected with remote address ipaddr and port. * @param ipaddr remote IP address to connect with. * * @return lwIP error code * * @see raw_disconnect() and raw_sendto() */ err_t raw_connect(struct raw_pcb *pcb, ip_addr_t *ipaddr) { ipX_addr_set_ipaddr(PCB_ISIPV6(pcb), &pcb->remote_ip, ipaddr); return ERR_OK; } /** * Set the callback function for received packets that match the * raw PCB's protocol and binding. * * The callback function MUST either * - eat the packet by calling pbuf_free() and returning non-zero. The * packet will not be passed to other raw PCBs or other protocol layers. * - not free the packet, and return zero. The packet will be matched * against further PCBs and/or forwarded to another protocol layers. * * @return non-zero if the packet was free()d, zero if the packet remains * available for others. */ void raw_recv(struct raw_pcb *pcb, raw_recv_fn recv, void *recv_arg) { /* remember recv() callback and user data */ pcb->recv.ip4 = recv; pcb->recv_arg = recv_arg; } /** * Send the raw IP packet to the given address. Note that actually you cannot * modify the IP headers (this is inconsistent with the receive callback where * you actually get the IP headers), you can only specify the IP payload here. * It requires some more changes in lwIP. (there will be a raw_send() function * then.) * * @param pcb the raw pcb which to send * @param p the IP payload to send * @param ipaddr the destination address of the IP packet * */ err_t raw_sendto(struct raw_pcb *pcb, struct pbuf *p, ip_addr_t *ipaddr) { err_t err; struct netif *netif; ipX_addr_t *src_ip; struct pbuf *q; /* q will be sent down the stack */ s16_t header_size; ipX_addr_t *dst_ip = ip_2_ipX(ipaddr); LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE, ("raw_sendto\n")); header_size = ( #if LWIP_IPV6 PCB_ISIPV6(pcb) ? IP6_HLEN : #endif /* LWIP_IPV6 */ IP_HLEN); /* not enough space to add an IP header to first pbuf in given p chain? */ if (pbuf_header(p, header_size)) { /* allocate header in new pbuf */ q = pbuf_alloc(PBUF_IP, 0, PBUF_RAM); /* new header pbuf could not be allocated? */ if (q == NULL) { LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("raw_sendto: could not allocate header\n")); return ERR_MEM; } if (p->tot_len != 0) { /* chain header q in front of given pbuf p */ pbuf_chain(q, p); } /* { first pbuf q points to header pbuf } */ LWIP_DEBUGF(RAW_DEBUG, ("raw_sendto: added header pbuf %p before given pbuf %p\n", (void *)q, (void *)p)); } else { /* first pbuf q equals given pbuf */ q = p; if(pbuf_header(q, -header_size)) { LWIP_ASSERT("Can't restore header we just removed!", 0); return ERR_MEM; } } netif = ipX_route(PCB_ISIPV6(pcb), &pcb->local_ip, dst_ip); if (netif == NULL) { LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, ("raw_sendto: No route to ")); ipX_addr_debug_print(PCB_ISIPV6(pcb), RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, dst_ip); /* free any temporary header pbuf allocated by pbuf_header() */ if (q != p) { pbuf_free(q); } return ERR_RTE; } #if IP_SOF_BROADCAST #if LWIP_IPV6 if (!PCB_ISIPV6(pcb)) #endif /* LWIP_IPV6 */ { /* broadcast filter? */ if (!ip_get_option(pcb, SOF_BROADCAST) && ip_addr_isbroadcast(ipaddr, netif)) { LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, ("raw_sendto: SOF_BROADCAST not enabled on pcb %p\n", (void *)pcb)); /* free any temporary header pbuf allocated by pbuf_header() */ if (q != p) { pbuf_free(q); } return ERR_VAL; } } #endif /* IP_SOF_BROADCAST */ if (ipX_addr_isany(PCB_ISIPV6(pcb), &pcb->local_ip)) { /* use outgoing network interface IP address as source address */ src_ip = ipX_netif_get_local_ipX(PCB_ISIPV6(pcb), netif, dst_ip); #if LWIP_IPV6 if (src_ip == NULL) { if (q != p) { pbuf_free(q); } return ERR_RTE; } #endif /* LWIP_IPV6 */ } else { /* use RAW PCB local IP address as source address */ src_ip = &pcb->local_ip; } #if LWIP_IPV6 /* If requested, based on the IPV6_CHECKSUM socket option per RFC3542, compute the checksum and update the checksum in the payload. */ if (PCB_ISIPV6(pcb) && pcb->chksum_reqd) { u16_t chksum = ip6_chksum_pseudo(p, pcb->protocol, p->tot_len, ipX_2_ip6(src_ip), ipX_2_ip6(dst_ip)); LWIP_ASSERT("Checksum must fit into first pbuf", p->len >= (pcb->chksum_offset + 2)); SMEMCPY(((u8_t *)p->payload) + pcb->chksum_offset, &chksum, sizeof(u16_t)); } #endif NETIF_SET_HWADDRHINT(netif, &pcb->addr_hint); err = ipX_output_if(PCB_ISIPV6(pcb), q, ipX_2_ip(src_ip), ipX_2_ip(dst_ip), pcb->ttl, pcb->tos, pcb->protocol, netif); NETIF_SET_HWADDRHINT(netif, NULL); /* did we chain a header earlier? */ if (q != p) { /* free the header */ pbuf_free(q); } return err; } /** * Send the raw IP packet to the address given by raw_connect() * * @param pcb the raw pcb which to send * @param p the IP payload to send * */ err_t raw_send(struct raw_pcb *pcb, struct pbuf *p) { return raw_sendto(pcb, p, ipX_2_ip(&pcb->remote_ip)); } /** * Remove an RAW PCB. * * @param pcb RAW PCB to be removed. The PCB is removed from the list of * RAW PCB's and the data structure is freed from memory. * * @see raw_new() */ void raw_remove(struct raw_pcb *pcb) { struct raw_pcb *pcb2; /* pcb to be removed is first in list? */ if (raw_pcbs == pcb) { /* make list start at 2nd pcb */ raw_pcbs = raw_pcbs->next; /* pcb not 1st in list */ } else { for(pcb2 = raw_pcbs; pcb2 != NULL; pcb2 = pcb2->next) { /* find pcb in raw_pcbs list */ if (pcb2->next != NULL && pcb2->next == pcb) { /* remove pcb from list */ pcb2->next = pcb->next; } } } memp_free(MEMP_RAW_PCB, pcb); } /** * Create a RAW PCB. * * @return The RAW PCB which was created. NULL if the PCB data structure * could not be allocated. * * @param proto the protocol number of the IPs payload (e.g. IP_PROTO_ICMP) * * @see raw_remove() */ struct raw_pcb * raw_new(u8_t proto) { struct raw_pcb *pcb; LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE, ("raw_new\n")); pcb = (struct raw_pcb *)memp_malloc(MEMP_RAW_PCB); /* could allocate RAW PCB? */ if (pcb != NULL) { /* initialize PCB to all zeroes */ memset(pcb, 0, sizeof(struct raw_pcb)); pcb->protocol = proto; pcb->ttl = RAW_TTL; pcb->next = raw_pcbs; raw_pcbs = pcb; } return pcb; } #if LWIP_IPV6 /** * Create a RAW PCB for IPv6. * * @return The RAW PCB which was created. NULL if the PCB data structure * could not be allocated. * * @param proto the protocol number (next header) of the IPv6 packet payload * (e.g. IP6_NEXTH_ICMP6) * * @see raw_remove() */ struct raw_pcb * raw_new_ip6(u8_t proto) { struct raw_pcb *pcb; pcb = raw_new(proto); ip_set_v6(pcb, 1); return pcb; } #endif /* LWIP_IPV6 */ #endif /* LWIP_RAW */ ocproxy-1.60/lwip/src/core/snmp/000077500000000000000000000000001303453231400166105ustar00rootroot00000000000000ocproxy-1.60/lwip/src/core/snmp/asn1_dec.c000066400000000000000000000400471303453231400204360ustar00rootroot00000000000000/** * @file * Abstract Syntax Notation One (ISO 8824, 8825) decoding * * @todo not optimised (yet), favor correctness over speed, favor speed over size */ /* * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * Author: Christiaan Simons */ #include "lwip/opt.h" #if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */ #include "lwip/snmp_asn1.h" /** * Retrieves type field from incoming pbuf chain. * * @param p points to a pbuf holding an ASN1 coded type field * @param ofs points to the offset within the pbuf chain of the ASN1 coded type field * @param type return ASN1 type * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) decode */ err_t snmp_asn1_dec_type(struct pbuf *p, u16_t ofs, u8_t *type) { u16_t plen, base; u8_t *msg_ptr; plen = 0; while (p != NULL) { base = plen; plen += p->len; if (ofs < plen) { msg_ptr = (u8_t*)p->payload; msg_ptr += ofs - base; *type = *msg_ptr; return ERR_OK; } p = p->next; } /* p == NULL, ofs >= plen */ return ERR_ARG; } /** * Decodes length field from incoming pbuf chain into host length. * * @param p points to a pbuf holding an ASN1 coded length * @param ofs points to the offset within the pbuf chain of the ASN1 coded length * @param octets_used returns number of octets used by the length code * @param length return host order length, upto 64k * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) decode */ err_t snmp_asn1_dec_length(struct pbuf *p, u16_t ofs, u8_t *octets_used, u16_t *length) { u16_t plen, base; u8_t *msg_ptr; plen = 0; while (p != NULL) { base = plen; plen += p->len; if (ofs < plen) { msg_ptr = (u8_t*)p->payload; msg_ptr += ofs - base; if (*msg_ptr < 0x80) { /* primitive definite length format */ *octets_used = 1; *length = *msg_ptr; return ERR_OK; } else if (*msg_ptr == 0x80) { /* constructed indefinite length format, termination with two zero octets */ u8_t zeros; u8_t i; *length = 0; zeros = 0; while (zeros != 2) { i = 2; while (i > 0) { i--; (*length) += 1; ofs += 1; if (ofs >= plen) { /* next octet in next pbuf */ p = p->next; if (p == NULL) { return ERR_ARG; } msg_ptr = (u8_t*)p->payload; plen += p->len; } else { /* next octet in same pbuf */ msg_ptr++; } if (*msg_ptr == 0) { zeros++; if (zeros == 2) { /* stop while (i > 0) */ i = 0; } } else { zeros = 0; } } } *octets_used = 1; return ERR_OK; } else if (*msg_ptr == 0x81) { /* constructed definite length format, one octet */ ofs += 1; if (ofs >= plen) { /* next octet in next pbuf */ p = p->next; if (p == NULL) { return ERR_ARG; } msg_ptr = (u8_t*)p->payload; } else { /* next octet in same pbuf */ msg_ptr++; } *length = *msg_ptr; *octets_used = 2; return ERR_OK; } else if (*msg_ptr == 0x82) { u8_t i; /* constructed definite length format, two octets */ i = 2; while (i > 0) { i--; ofs += 1; if (ofs >= plen) { /* next octet in next pbuf */ p = p->next; if (p == NULL) { return ERR_ARG; } msg_ptr = (u8_t*)p->payload; plen += p->len; } else { /* next octet in same pbuf */ msg_ptr++; } if (i == 0) { /* least significant length octet */ *length |= *msg_ptr; } else { /* most significant length octet */ *length = (*msg_ptr) << 8; } } *octets_used = 3; return ERR_OK; } else { /* constructed definite length format 3..127 octets, this is too big (>64k) */ /** @todo: do we need to accept inefficient codings with many leading zero's? */ *octets_used = 1 + ((*msg_ptr) & 0x7f); return ERR_ARG; } } p = p->next; } /* p == NULL, ofs >= plen */ return ERR_ARG; } /** * Decodes positive integer (counter, gauge, timeticks) into u32_t. * * @param p points to a pbuf holding an ASN1 coded integer * @param ofs points to the offset within the pbuf chain of the ASN1 coded integer * @param len length of the coded integer field * @param value return host order integer * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) decode * * @note ASN coded integers are _always_ signed. E.g. +0xFFFF is coded * as 0x00,0xFF,0xFF. Note the leading sign octet. A positive value * of 0xFFFFFFFF is preceded with 0x00 and the length is 5 octets!! */ err_t snmp_asn1_dec_u32t(struct pbuf *p, u16_t ofs, u16_t len, u32_t *value) { u16_t plen, base; u8_t *msg_ptr; plen = 0; while (p != NULL) { base = plen; plen += p->len; if (ofs < plen) { msg_ptr = (u8_t*)p->payload; msg_ptr += ofs - base; if ((len > 0) && (len < 6)) { /* start from zero */ *value = 0; if (*msg_ptr & 0x80) { /* negative, expecting zero sign bit! */ return ERR_ARG; } else { /* positive */ if ((len > 1) && (*msg_ptr == 0)) { /* skip leading "sign byte" octet 0x00 */ len--; ofs += 1; if (ofs >= plen) { /* next octet in next pbuf */ p = p->next; if (p == NULL) { return ERR_ARG; } msg_ptr = (u8_t*)p->payload; plen += p->len; } else { /* next octet in same pbuf */ msg_ptr++; } } } /* OR octets with value */ while (len > 1) { len--; *value |= *msg_ptr; *value <<= 8; ofs += 1; if (ofs >= plen) { /* next octet in next pbuf */ p = p->next; if (p == NULL) { return ERR_ARG; } msg_ptr = (u8_t*)p->payload; plen += p->len; } else { /* next octet in same pbuf */ msg_ptr++; } } *value |= *msg_ptr; return ERR_OK; } else { return ERR_ARG; } } p = p->next; } /* p == NULL, ofs >= plen */ return ERR_ARG; } /** * Decodes integer into s32_t. * * @param p points to a pbuf holding an ASN1 coded integer * @param ofs points to the offset within the pbuf chain of the ASN1 coded integer * @param len length of the coded integer field * @param value return host order integer * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) decode * * @note ASN coded integers are _always_ signed! */ err_t snmp_asn1_dec_s32t(struct pbuf *p, u16_t ofs, u16_t len, s32_t *value) { u16_t plen, base; u8_t *msg_ptr; #if BYTE_ORDER == LITTLE_ENDIAN u8_t *lsb_ptr = (u8_t*)value; #endif #if BYTE_ORDER == BIG_ENDIAN u8_t *lsb_ptr = (u8_t*)value + sizeof(s32_t) - 1; #endif u8_t sign; plen = 0; while (p != NULL) { base = plen; plen += p->len; if (ofs < plen) { msg_ptr = (u8_t*)p->payload; msg_ptr += ofs - base; if ((len > 0) && (len < 5)) { if (*msg_ptr & 0x80) { /* negative, start from -1 */ *value = -1; sign = 1; } else { /* positive, start from 0 */ *value = 0; sign = 0; } /* OR/AND octets with value */ while (len > 1) { len--; if (sign) { *lsb_ptr &= *msg_ptr; *value <<= 8; *lsb_ptr |= 255; } else { *lsb_ptr |= *msg_ptr; *value <<= 8; } ofs += 1; if (ofs >= plen) { /* next octet in next pbuf */ p = p->next; if (p == NULL) { return ERR_ARG; } msg_ptr = (u8_t*)p->payload; plen += p->len; } else { /* next octet in same pbuf */ msg_ptr++; } } if (sign) { *lsb_ptr &= *msg_ptr; } else { *lsb_ptr |= *msg_ptr; } return ERR_OK; } else { return ERR_ARG; } } p = p->next; } /* p == NULL, ofs >= plen */ return ERR_ARG; } /** * Decodes object identifier from incoming message into array of s32_t. * * @param p points to a pbuf holding an ASN1 coded object identifier * @param ofs points to the offset within the pbuf chain of the ASN1 coded object identifier * @param len length of the coded object identifier * @param oid return object identifier struct * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) decode */ err_t snmp_asn1_dec_oid(struct pbuf *p, u16_t ofs, u16_t len, struct snmp_obj_id *oid) { u16_t plen, base; u8_t *msg_ptr; s32_t *oid_ptr; plen = 0; while (p != NULL) { base = plen; plen += p->len; if (ofs < plen) { msg_ptr = (u8_t*)p->payload; msg_ptr += ofs - base; oid->len = 0; oid_ptr = &oid->id[0]; if (len > 0) { /* first compressed octet */ if (*msg_ptr == 0x2B) { /* (most) common case 1.3 (iso.org) */ *oid_ptr = 1; oid_ptr++; *oid_ptr = 3; oid_ptr++; } else if (*msg_ptr < 40) { *oid_ptr = 0; oid_ptr++; *oid_ptr = *msg_ptr; oid_ptr++; } else if (*msg_ptr < 80) { *oid_ptr = 1; oid_ptr++; *oid_ptr = (*msg_ptr) - 40; oid_ptr++; } else { *oid_ptr = 2; oid_ptr++; *oid_ptr = (*msg_ptr) - 80; oid_ptr++; } oid->len = 2; } else { /* accepting zero length identifiers e.g. for getnext operation. uncommon but valid */ return ERR_OK; } len--; if (len > 0) { ofs += 1; if (ofs >= plen) { /* next octet in next pbuf */ p = p->next; if (p == NULL) { return ERR_ARG; } msg_ptr = (u8_t*)p->payload; plen += p->len; } else { /* next octet in same pbuf */ msg_ptr++; } } while ((len > 0) && (oid->len < LWIP_SNMP_OBJ_ID_LEN)) { /* sub-identifier uses multiple octets */ if (*msg_ptr & 0x80) { s32_t sub_id = 0; while ((*msg_ptr & 0x80) && (len > 1)) { len--; sub_id = (sub_id << 7) + (*msg_ptr & ~0x80); ofs += 1; if (ofs >= plen) { /* next octet in next pbuf */ p = p->next; if (p == NULL) { return ERR_ARG; } msg_ptr = (u8_t*)p->payload; plen += p->len; } else { /* next octet in same pbuf */ msg_ptr++; } } if (!(*msg_ptr & 0x80) && (len > 0)) { /* last octet sub-identifier */ len--; sub_id = (sub_id << 7) + *msg_ptr; *oid_ptr = sub_id; } } else { /* !(*msg_ptr & 0x80) sub-identifier uses single octet */ len--; *oid_ptr = *msg_ptr; } if (len > 0) { /* remaining oid bytes available ... */ ofs += 1; if (ofs >= plen) { /* next octet in next pbuf */ p = p->next; if (p == NULL) { return ERR_ARG; } msg_ptr = (u8_t*)p->payload; plen += p->len; } else { /* next octet in same pbuf */ msg_ptr++; } } oid_ptr++; oid->len++; } if (len == 0) { /* len == 0, end of oid */ return ERR_OK; } else { /* len > 0, oid->len == LWIP_SNMP_OBJ_ID_LEN or malformed encoding */ return ERR_ARG; } } p = p->next; } /* p == NULL, ofs >= plen */ return ERR_ARG; } /** * Decodes (copies) raw data (ip-addresses, octet strings, opaque encoding) * from incoming message into array. * * @param p points to a pbuf holding an ASN1 coded raw data * @param ofs points to the offset within the pbuf chain of the ASN1 coded raw data * @param len length of the coded raw data (zero is valid, e.g. empty string!) * @param raw_len length of the raw return value * @param raw return raw bytes * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) decode */ err_t snmp_asn1_dec_raw(struct pbuf *p, u16_t ofs, u16_t len, u16_t raw_len, u8_t *raw) { u16_t plen, base; u8_t *msg_ptr; if (len > 0) { plen = 0; while (p != NULL) { base = plen; plen += p->len; if (ofs < plen) { msg_ptr = (u8_t*)p->payload; msg_ptr += ofs - base; if (raw_len >= len) { while (len > 1) { /* copy len - 1 octets */ len--; *raw = *msg_ptr; raw++; ofs += 1; if (ofs >= plen) { /* next octet in next pbuf */ p = p->next; if (p == NULL) { return ERR_ARG; } msg_ptr = (u8_t*)p->payload; plen += p->len; } else { /* next octet in same pbuf */ msg_ptr++; } } /* copy last octet */ *raw = *msg_ptr; return ERR_OK; } else { /* raw_len < len, not enough dst space */ return ERR_ARG; } } p = p->next; } /* p == NULL, ofs >= plen */ return ERR_ARG; } else { /* len == 0, empty string */ return ERR_OK; } } #endif /* LWIP_SNMP */ ocproxy-1.60/lwip/src/core/snmp/asn1_enc.c000066400000000000000000000336071303453231400204540ustar00rootroot00000000000000/** * @file * Abstract Syntax Notation One (ISO 8824, 8825) encoding * * @todo not optimised (yet), favor correctness over speed, favor speed over size */ /* * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * Author: Christiaan Simons */ #include "lwip/opt.h" #if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */ #include "lwip/snmp_asn1.h" /** * Returns octet count for length. * * @param length * @param octets_needed points to the return value */ void snmp_asn1_enc_length_cnt(u16_t length, u8_t *octets_needed) { if (length < 0x80U) { *octets_needed = 1; } else if (length < 0x100U) { *octets_needed = 2; } else { *octets_needed = 3; } } /** * Returns octet count for an u32_t. * * @param value * @param octets_needed points to the return value * * @note ASN coded integers are _always_ signed. E.g. +0xFFFF is coded * as 0x00,0xFF,0xFF. Note the leading sign octet. A positive value * of 0xFFFFFFFF is preceded with 0x00 and the length is 5 octets!! */ void snmp_asn1_enc_u32t_cnt(u32_t value, u16_t *octets_needed) { if (value < 0x80UL) { *octets_needed = 1; } else if (value < 0x8000UL) { *octets_needed = 2; } else if (value < 0x800000UL) { *octets_needed = 3; } else if (value < 0x80000000UL) { *octets_needed = 4; } else { *octets_needed = 5; } } /** * Returns octet count for an s32_t. * * @param value * @param octets_needed points to the return value * * @note ASN coded integers are _always_ signed. */ void snmp_asn1_enc_s32t_cnt(s32_t value, u16_t *octets_needed) { if (value < 0) { value = ~value; } if (value < 0x80L) { *octets_needed = 1; } else if (value < 0x8000L) { *octets_needed = 2; } else if (value < 0x800000L) { *octets_needed = 3; } else { *octets_needed = 4; } } /** * Returns octet count for an object identifier. * * @param ident_len object identifier array length * @param ident points to object identifier array * @param octets_needed points to the return value */ void snmp_asn1_enc_oid_cnt(u8_t ident_len, s32_t *ident, u16_t *octets_needed) { s32_t sub_id; u8_t cnt; cnt = 0; if (ident_len > 1) { /* compressed prefix in one octet */ cnt++; ident_len -= 2; ident += 2; } while(ident_len > 0) { ident_len--; sub_id = *ident; sub_id >>= 7; cnt++; while(sub_id > 0) { sub_id >>= 7; cnt++; } ident++; } *octets_needed = cnt; } /** * Encodes ASN type field into a pbuf chained ASN1 msg. * * @param p points to output pbuf to encode value into * @param ofs points to the offset within the pbuf chain * @param type input ASN1 type * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) encode */ err_t snmp_asn1_enc_type(struct pbuf *p, u16_t ofs, u8_t type) { u16_t plen, base; u8_t *msg_ptr; plen = 0; while (p != NULL) { base = plen; plen += p->len; if (ofs < plen) { msg_ptr = (u8_t*)p->payload; msg_ptr += ofs - base; *msg_ptr = type; return ERR_OK; } p = p->next; } /* p == NULL, ofs >= plen */ return ERR_ARG; } /** * Encodes host order length field into a pbuf chained ASN1 msg. * * @param p points to output pbuf to encode length into * @param ofs points to the offset within the pbuf chain * @param length is the host order length to be encoded * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) encode */ err_t snmp_asn1_enc_length(struct pbuf *p, u16_t ofs, u16_t length) { u16_t plen, base; u8_t *msg_ptr; plen = 0; while (p != NULL) { base = plen; plen += p->len; if (ofs < plen) { msg_ptr = (u8_t*)p->payload; msg_ptr += ofs - base; if (length < 0x80) { *msg_ptr = (u8_t)length; return ERR_OK; } else if (length < 0x100) { *msg_ptr = 0x81; ofs += 1; if (ofs >= plen) { /* next octet in next pbuf */ p = p->next; if (p == NULL) { return ERR_ARG; } msg_ptr = (u8_t*)p->payload; } else { /* next octet in same pbuf */ msg_ptr++; } *msg_ptr = (u8_t)length; return ERR_OK; } else { u8_t i; /* length >= 0x100 && length <= 0xFFFF */ *msg_ptr = 0x82; i = 2; while (i > 0) { i--; ofs += 1; if (ofs >= plen) { /* next octet in next pbuf */ p = p->next; if (p == NULL) { return ERR_ARG; } msg_ptr = (u8_t*)p->payload; plen += p->len; } else { /* next octet in same pbuf */ msg_ptr++; } if (i == 0) { /* least significant length octet */ *msg_ptr = (u8_t)length; } else { /* most significant length octet */ *msg_ptr = (u8_t)(length >> 8); } } return ERR_OK; } } p = p->next; } /* p == NULL, ofs >= plen */ return ERR_ARG; } /** * Encodes u32_t (counter, gauge, timeticks) into a pbuf chained ASN1 msg. * * @param p points to output pbuf to encode value into * @param ofs points to the offset within the pbuf chain * @param octets_needed encoding length (from snmp_asn1_enc_u32t_cnt()) * @param value is the host order u32_t value to be encoded * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) encode * * @see snmp_asn1_enc_u32t_cnt() */ err_t snmp_asn1_enc_u32t(struct pbuf *p, u16_t ofs, u16_t octets_needed, u32_t value) { u16_t plen, base; u8_t *msg_ptr; plen = 0; while (p != NULL) { base = plen; plen += p->len; if (ofs < plen) { msg_ptr = (u8_t*)p->payload; msg_ptr += ofs - base; if (octets_needed == 5) { /* not enough bits in 'value' add leading 0x00 */ octets_needed--; *msg_ptr = 0x00; ofs += 1; if (ofs >= plen) { /* next octet in next pbuf */ p = p->next; if (p == NULL) { return ERR_ARG; } msg_ptr = (u8_t*)p->payload; plen += p->len; } else { /* next octet in same pbuf */ msg_ptr++; } } while (octets_needed > 1) { octets_needed--; *msg_ptr = (u8_t)(value >> (octets_needed << 3)); ofs += 1; if (ofs >= plen) { /* next octet in next pbuf */ p = p->next; if (p == NULL) { return ERR_ARG; } msg_ptr = (u8_t*)p->payload; plen += p->len; } else { /* next octet in same pbuf */ msg_ptr++; } } /* (only) one least significant octet */ *msg_ptr = (u8_t)value; return ERR_OK; } p = p->next; } /* p == NULL, ofs >= plen */ return ERR_ARG; } /** * Encodes s32_t integer into a pbuf chained ASN1 msg. * * @param p points to output pbuf to encode value into * @param ofs points to the offset within the pbuf chain * @param octets_needed encoding length (from snmp_asn1_enc_s32t_cnt()) * @param value is the host order s32_t value to be encoded * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) encode * * @see snmp_asn1_enc_s32t_cnt() */ err_t snmp_asn1_enc_s32t(struct pbuf *p, u16_t ofs, u16_t octets_needed, s32_t value) { u16_t plen, base; u8_t *msg_ptr; plen = 0; while (p != NULL) { base = plen; plen += p->len; if (ofs < plen) { msg_ptr = (u8_t*)p->payload; msg_ptr += ofs - base; while (octets_needed > 1) { octets_needed--; *msg_ptr = (u8_t)(value >> (octets_needed << 3)); ofs += 1; if (ofs >= plen) { /* next octet in next pbuf */ p = p->next; if (p == NULL) { return ERR_ARG; } msg_ptr = (u8_t*)p->payload; plen += p->len; } else { /* next octet in same pbuf */ msg_ptr++; } } /* (only) one least significant octet */ *msg_ptr = (u8_t)value; return ERR_OK; } p = p->next; } /* p == NULL, ofs >= plen */ return ERR_ARG; } /** * Encodes object identifier into a pbuf chained ASN1 msg. * * @param p points to output pbuf to encode oid into * @param ofs points to the offset within the pbuf chain * @param ident_len object identifier array length * @param ident points to object identifier array * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) encode */ err_t snmp_asn1_enc_oid(struct pbuf *p, u16_t ofs, u8_t ident_len, s32_t *ident) { u16_t plen, base; u8_t *msg_ptr; plen = 0; while (p != NULL) { base = plen; plen += p->len; if (ofs < plen) { msg_ptr = (u8_t*)p->payload; msg_ptr += ofs - base; if (ident_len > 1) { if ((ident[0] == 1) && (ident[1] == 3)) { /* compressed (most common) prefix .iso.org */ *msg_ptr = 0x2b; } else { /* calculate prefix */ *msg_ptr = (u8_t)((ident[0] * 40) + ident[1]); } ofs += 1; if (ofs >= plen) { /* next octet in next pbuf */ p = p->next; if (p == NULL) { return ERR_ARG; } msg_ptr = (u8_t*)p->payload; plen += p->len; } else { /* next octet in same pbuf */ msg_ptr++; } ident_len -= 2; ident += 2; } else { /* @bug: allow empty varbinds for symmetry (we must decode them for getnext), allow partial compression?? */ /* ident_len <= 1, at least we need zeroDotZero (0.0) (ident_len == 2) */ return ERR_ARG; } while (ident_len > 0) { s32_t sub_id; u8_t shift, tail; ident_len--; sub_id = *ident; tail = 0; shift = 28; while(shift > 0) { u8_t code; code = (u8_t)(sub_id >> shift); if ((code != 0) || (tail != 0)) { tail = 1; *msg_ptr = code | 0x80; ofs += 1; if (ofs >= plen) { /* next octet in next pbuf */ p = p->next; if (p == NULL) { return ERR_ARG; } msg_ptr = (u8_t*)p->payload; plen += p->len; } else { /* next octet in same pbuf */ msg_ptr++; } } shift -= 7; } *msg_ptr = (u8_t)sub_id & 0x7F; if (ident_len > 0) { ofs += 1; if (ofs >= plen) { /* next octet in next pbuf */ p = p->next; if (p == NULL) { return ERR_ARG; } msg_ptr = (u8_t*)p->payload; plen += p->len; } else { /* next octet in same pbuf */ msg_ptr++; } } /* proceed to next sub-identifier */ ident++; } return ERR_OK; } p = p->next; } /* p == NULL, ofs >= plen */ return ERR_ARG; } /** * Encodes raw data (octet string, opaque) into a pbuf chained ASN1 msg. * * @param p points to output pbuf to encode raw data into * @param ofs points to the offset within the pbuf chain * @param raw_len raw data length * @param raw points raw data * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) encode */ err_t snmp_asn1_enc_raw(struct pbuf *p, u16_t ofs, u16_t raw_len, u8_t *raw) { u16_t plen, base; u8_t *msg_ptr; plen = 0; while (p != NULL) { base = plen; plen += p->len; if (ofs < plen) { msg_ptr = (u8_t*)p->payload; msg_ptr += ofs - base; while (raw_len > 1) { /* copy raw_len - 1 octets */ raw_len--; *msg_ptr = *raw; raw++; ofs += 1; if (ofs >= plen) { /* next octet in next pbuf */ p = p->next; if (p == NULL) { return ERR_ARG; } msg_ptr = (u8_t*)p->payload; plen += p->len; } else { /* next octet in same pbuf */ msg_ptr++; } } if (raw_len > 0) { /* copy last or single octet */ *msg_ptr = *raw; } return ERR_OK; } p = p->next; } /* p == NULL, ofs >= plen */ return ERR_ARG; } #endif /* LWIP_SNMP */ ocproxy-1.60/lwip/src/core/snmp/mib2.c000066400000000000000000003176561303453231400176270ustar00rootroot00000000000000/** * @file * Management Information Base II (RFC1213) objects and functions. * * @note the object identifiers for this MIB-2 and private MIB tree * must be kept in sorted ascending order. This to ensure correct getnext operation. */ /* * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * Author: Christiaan Simons */ #include "lwip/opt.h" #if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */ #include "lwip/snmp.h" #include "lwip/netif.h" #include "lwip/ip.h" #include "lwip/ip_frag.h" #include "lwip/mem.h" #include "lwip/tcp_impl.h" #include "lwip/udp.h" #include "lwip/snmp_asn1.h" #include "lwip/snmp_structs.h" #include "lwip/sys.h" #include "netif/etharp.h" #include /** * IANA assigned enterprise ID for lwIP is 26381 * @see http://www.iana.org/assignments/enterprise-numbers * * @note this enterprise ID is assigned to the lwIP project, * all object identifiers living under this ID are assigned * by the lwIP maintainers (contact Christiaan Simons)! * @note don't change this define, use snmp_set_sysobjid() * * If you need to create your own private MIB you'll need * to apply for your own enterprise ID with IANA: * http://www.iana.org/numbers.html */ #define SNMP_ENTERPRISE_ID 26381 #define SNMP_SYSOBJID_LEN 7 #define SNMP_SYSOBJID {1, 3, 6, 1, 4, 1, SNMP_ENTERPRISE_ID} #ifndef SNMP_SYSSERVICES #define SNMP_SYSSERVICES ((1 << 6) | (1 << 3) | ((IP_FORWARD) << 2)) #endif #ifndef SNMP_GET_SYSUPTIME #define SNMP_GET_SYSUPTIME(sysuptime) (sysuptime = (sys_now() / 10)) #endif static void system_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od); static void system_get_value(struct obj_def *od, u16_t len, void *value); static u8_t system_set_test(struct obj_def *od, u16_t len, void *value); static void system_set_value(struct obj_def *od, u16_t len, void *value); static void interfaces_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od); static void interfaces_get_value(struct obj_def *od, u16_t len, void *value); static void ifentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od); static void ifentry_get_value(struct obj_def *od, u16_t len, void *value); #if !SNMP_SAFE_REQUESTS static u8_t ifentry_set_test (struct obj_def *od, u16_t len, void *value); static void ifentry_set_value (struct obj_def *od, u16_t len, void *value); #endif /* SNMP_SAFE_REQUESTS */ static void atentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od); static void atentry_get_value(struct obj_def *od, u16_t len, void *value); static void ip_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od); static void ip_get_value(struct obj_def *od, u16_t len, void *value); static u8_t ip_set_test(struct obj_def *od, u16_t len, void *value); static void ip_addrentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od); static void ip_addrentry_get_value(struct obj_def *od, u16_t len, void *value); static void ip_rteentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od); static void ip_rteentry_get_value(struct obj_def *od, u16_t len, void *value); static void ip_ntomentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od); static void ip_ntomentry_get_value(struct obj_def *od, u16_t len, void *value); static void icmp_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od); static void icmp_get_value(struct obj_def *od, u16_t len, void *value); #if LWIP_TCP static void tcp_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od); static void tcp_get_value(struct obj_def *od, u16_t len, void *value); #ifdef THIS_SEEMS_UNUSED static void tcpconnentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od); static void tcpconnentry_get_value(struct obj_def *od, u16_t len, void *value); #endif #endif static void udp_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od); static void udp_get_value(struct obj_def *od, u16_t len, void *value); static void udpentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od); static void udpentry_get_value(struct obj_def *od, u16_t len, void *value); static void snmp_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od); static void snmp_get_value(struct obj_def *od, u16_t len, void *value); static u8_t snmp_set_test(struct obj_def *od, u16_t len, void *value); static void snmp_set_value(struct obj_def *od, u16_t len, void *value); /* snmp .1.3.6.1.2.1.11 */ const mib_scalar_node snmp_scalar = { &snmp_get_object_def, &snmp_get_value, &snmp_set_test, &snmp_set_value, MIB_NODE_SC, 0 }; const s32_t snmp_ids[28] = { 1, 2, 3, 4, 5, 6, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 24, 25, 26, 27, 28, 29, 30 }; struct mib_node* const snmp_nodes[28] = { (struct mib_node*)&snmp_scalar, (struct mib_node*)&snmp_scalar, (struct mib_node*)&snmp_scalar, (struct mib_node*)&snmp_scalar, (struct mib_node*)&snmp_scalar, (struct mib_node*)&snmp_scalar, (struct mib_node*)&snmp_scalar, (struct mib_node*)&snmp_scalar, (struct mib_node*)&snmp_scalar, (struct mib_node*)&snmp_scalar, (struct mib_node*)&snmp_scalar, (struct mib_node*)&snmp_scalar, (struct mib_node*)&snmp_scalar, (struct mib_node*)&snmp_scalar, (struct mib_node*)&snmp_scalar, (struct mib_node*)&snmp_scalar, (struct mib_node*)&snmp_scalar, (struct mib_node*)&snmp_scalar, (struct mib_node*)&snmp_scalar, (struct mib_node*)&snmp_scalar, (struct mib_node*)&snmp_scalar, (struct mib_node*)&snmp_scalar, (struct mib_node*)&snmp_scalar, (struct mib_node*)&snmp_scalar, (struct mib_node*)&snmp_scalar, (struct mib_node*)&snmp_scalar, (struct mib_node*)&snmp_scalar, (struct mib_node*)&snmp_scalar }; const struct mib_array_node snmp = { &noleafs_get_object_def, &noleafs_get_value, &noleafs_set_test, &noleafs_set_value, MIB_NODE_AR, 28, snmp_ids, snmp_nodes }; /* dot3 and EtherLike MIB not planned. (transmission .1.3.6.1.2.1.10) */ /* historical (some say hysterical). (cmot .1.3.6.1.2.1.9) */ /* lwIP has no EGP, thus may not implement it. (egp .1.3.6.1.2.1.8) */ /* udp .1.3.6.1.2.1.7 */ /** index root node for udpTable */ struct mib_list_rootnode udp_root = { &noleafs_get_object_def, &noleafs_get_value, &noleafs_set_test, &noleafs_set_value, MIB_NODE_LR, 0, NULL, NULL, 0 }; const s32_t udpentry_ids[2] = { 1, 2 }; struct mib_node* const udpentry_nodes[2] = { (struct mib_node*)&udp_root, (struct mib_node*)&udp_root, }; const struct mib_array_node udpentry = { &noleafs_get_object_def, &noleafs_get_value, &noleafs_set_test, &noleafs_set_value, MIB_NODE_AR, 2, udpentry_ids, udpentry_nodes }; s32_t udptable_id = 1; struct mib_node* udptable_node = (struct mib_node*)&udpentry; struct mib_ram_array_node udptable = { &noleafs_get_object_def, &noleafs_get_value, &noleafs_set_test, &noleafs_set_value, MIB_NODE_RA, 0, &udptable_id, &udptable_node }; const mib_scalar_node udp_scalar = { &udp_get_object_def, &udp_get_value, &noleafs_set_test, &noleafs_set_value, MIB_NODE_SC, 0 }; const s32_t udp_ids[5] = { 1, 2, 3, 4, 5 }; struct mib_node* const udp_nodes[5] = { (struct mib_node*)&udp_scalar, (struct mib_node*)&udp_scalar, (struct mib_node*)&udp_scalar, (struct mib_node*)&udp_scalar, (struct mib_node*)&udptable }; const struct mib_array_node udp = { &noleafs_get_object_def, &noleafs_get_value, &noleafs_set_test, &noleafs_set_value, MIB_NODE_AR, 5, udp_ids, udp_nodes }; /* tcp .1.3.6.1.2.1.6 */ #if LWIP_TCP /* only if the TCP protocol is available may implement this group */ /** index root node for tcpConnTable */ struct mib_list_rootnode tcpconntree_root = { &noleafs_get_object_def, &noleafs_get_value, &noleafs_set_test, &noleafs_set_value, MIB_NODE_LR, 0, NULL, NULL, 0 }; const s32_t tcpconnentry_ids[5] = { 1, 2, 3, 4, 5 }; struct mib_node* const tcpconnentry_nodes[5] = { (struct mib_node*)&tcpconntree_root, (struct mib_node*)&tcpconntree_root, (struct mib_node*)&tcpconntree_root, (struct mib_node*)&tcpconntree_root, (struct mib_node*)&tcpconntree_root }; const struct mib_array_node tcpconnentry = { &noleafs_get_object_def, &noleafs_get_value, &noleafs_set_test, &noleafs_set_value, MIB_NODE_AR, 5, tcpconnentry_ids, tcpconnentry_nodes }; s32_t tcpconntable_id = 1; struct mib_node* tcpconntable_node = (struct mib_node*)&tcpconnentry; struct mib_ram_array_node tcpconntable = { &noleafs_get_object_def, &noleafs_get_value, &noleafs_set_test, &noleafs_set_value, MIB_NODE_RA, /** @todo update maxlength when inserting / deleting from table 0 when table is empty, 1 when more than one entry */ 0, &tcpconntable_id, &tcpconntable_node }; const mib_scalar_node tcp_scalar = { &tcp_get_object_def, &tcp_get_value, &noleafs_set_test, &noleafs_set_value, MIB_NODE_SC, 0 }; const s32_t tcp_ids[15] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }; struct mib_node* const tcp_nodes[15] = { (struct mib_node*)&tcp_scalar, (struct mib_node*)&tcp_scalar, (struct mib_node*)&tcp_scalar, (struct mib_node*)&tcp_scalar, (struct mib_node*)&tcp_scalar, (struct mib_node*)&tcp_scalar, (struct mib_node*)&tcp_scalar, (struct mib_node*)&tcp_scalar, (struct mib_node*)&tcp_scalar, (struct mib_node*)&tcp_scalar, (struct mib_node*)&tcp_scalar, (struct mib_node*)&tcp_scalar, (struct mib_node*)&tcpconntable, (struct mib_node*)&tcp_scalar, (struct mib_node*)&tcp_scalar }; const struct mib_array_node tcp = { &noleafs_get_object_def, &noleafs_get_value, &noleafs_set_test, &noleafs_set_value, MIB_NODE_AR, 15, tcp_ids, tcp_nodes }; #endif /* icmp .1.3.6.1.2.1.5 */ const mib_scalar_node icmp_scalar = { &icmp_get_object_def, &icmp_get_value, &noleafs_set_test, &noleafs_set_value, MIB_NODE_SC, 0 }; const s32_t icmp_ids[26] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26 }; struct mib_node* const icmp_nodes[26] = { (struct mib_node*)&icmp_scalar, (struct mib_node*)&icmp_scalar, (struct mib_node*)&icmp_scalar, (struct mib_node*)&icmp_scalar, (struct mib_node*)&icmp_scalar, (struct mib_node*)&icmp_scalar, (struct mib_node*)&icmp_scalar, (struct mib_node*)&icmp_scalar, (struct mib_node*)&icmp_scalar, (struct mib_node*)&icmp_scalar, (struct mib_node*)&icmp_scalar, (struct mib_node*)&icmp_scalar, (struct mib_node*)&icmp_scalar, (struct mib_node*)&icmp_scalar, (struct mib_node*)&icmp_scalar, (struct mib_node*)&icmp_scalar, (struct mib_node*)&icmp_scalar, (struct mib_node*)&icmp_scalar, (struct mib_node*)&icmp_scalar, (struct mib_node*)&icmp_scalar, (struct mib_node*)&icmp_scalar, (struct mib_node*)&icmp_scalar, (struct mib_node*)&icmp_scalar, (struct mib_node*)&icmp_scalar, (struct mib_node*)&icmp_scalar, (struct mib_node*)&icmp_scalar }; const struct mib_array_node icmp = { &noleafs_get_object_def, &noleafs_get_value, &noleafs_set_test, &noleafs_set_value, MIB_NODE_AR, 26, icmp_ids, icmp_nodes }; /** index root node for ipNetToMediaTable */ struct mib_list_rootnode ipntomtree_root = { &noleafs_get_object_def, &noleafs_get_value, &noleafs_set_test, &noleafs_set_value, MIB_NODE_LR, 0, NULL, NULL, 0 }; const s32_t ipntomentry_ids[4] = { 1, 2, 3, 4 }; struct mib_node* const ipntomentry_nodes[4] = { (struct mib_node*)&ipntomtree_root, (struct mib_node*)&ipntomtree_root, (struct mib_node*)&ipntomtree_root, (struct mib_node*)&ipntomtree_root }; const struct mib_array_node ipntomentry = { &noleafs_get_object_def, &noleafs_get_value, &noleafs_set_test, &noleafs_set_value, MIB_NODE_AR, 4, ipntomentry_ids, ipntomentry_nodes }; s32_t ipntomtable_id = 1; struct mib_node* ipntomtable_node = (struct mib_node*)&ipntomentry; struct mib_ram_array_node ipntomtable = { &noleafs_get_object_def, &noleafs_get_value, &noleafs_set_test, &noleafs_set_value, MIB_NODE_RA, 0, &ipntomtable_id, &ipntomtable_node }; /** index root node for ipRouteTable */ struct mib_list_rootnode iprtetree_root = { &noleafs_get_object_def, &noleafs_get_value, &noleafs_set_test, &noleafs_set_value, MIB_NODE_LR, 0, NULL, NULL, 0 }; const s32_t iprteentry_ids[13] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13 }; struct mib_node* const iprteentry_nodes[13] = { (struct mib_node*)&iprtetree_root, (struct mib_node*)&iprtetree_root, (struct mib_node*)&iprtetree_root, (struct mib_node*)&iprtetree_root, (struct mib_node*)&iprtetree_root, (struct mib_node*)&iprtetree_root, (struct mib_node*)&iprtetree_root, (struct mib_node*)&iprtetree_root, (struct mib_node*)&iprtetree_root, (struct mib_node*)&iprtetree_root, (struct mib_node*)&iprtetree_root, (struct mib_node*)&iprtetree_root, (struct mib_node*)&iprtetree_root }; const struct mib_array_node iprteentry = { &noleafs_get_object_def, &noleafs_get_value, &noleafs_set_test, &noleafs_set_value, MIB_NODE_AR, 13, iprteentry_ids, iprteentry_nodes }; s32_t iprtetable_id = 1; struct mib_node* iprtetable_node = (struct mib_node*)&iprteentry; struct mib_ram_array_node iprtetable = { &noleafs_get_object_def, &noleafs_get_value, &noleafs_set_test, &noleafs_set_value, MIB_NODE_RA, 0, &iprtetable_id, &iprtetable_node }; /** index root node for ipAddrTable */ struct mib_list_rootnode ipaddrtree_root = { &noleafs_get_object_def, &noleafs_get_value, &noleafs_set_test, &noleafs_set_value, MIB_NODE_LR, 0, NULL, NULL, 0 }; const s32_t ipaddrentry_ids[5] = { 1, 2, 3, 4, 5 }; struct mib_node* const ipaddrentry_nodes[5] = { (struct mib_node*)&ipaddrtree_root, (struct mib_node*)&ipaddrtree_root, (struct mib_node*)&ipaddrtree_root, (struct mib_node*)&ipaddrtree_root, (struct mib_node*)&ipaddrtree_root }; const struct mib_array_node ipaddrentry = { &noleafs_get_object_def, &noleafs_get_value, &noleafs_set_test, &noleafs_set_value, MIB_NODE_AR, 5, ipaddrentry_ids, ipaddrentry_nodes }; s32_t ipaddrtable_id = 1; struct mib_node* ipaddrtable_node = (struct mib_node*)&ipaddrentry; struct mib_ram_array_node ipaddrtable = { &noleafs_get_object_def, &noleafs_get_value, &noleafs_set_test, &noleafs_set_value, MIB_NODE_RA, 0, &ipaddrtable_id, &ipaddrtable_node }; /* ip .1.3.6.1.2.1.4 */ const mib_scalar_node ip_scalar = { &ip_get_object_def, &ip_get_value, &ip_set_test, &noleafs_set_value, MIB_NODE_SC, 0 }; const s32_t ip_ids[23] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23 }; struct mib_node* const ip_nodes[23] = { (struct mib_node*)&ip_scalar, (struct mib_node*)&ip_scalar, (struct mib_node*)&ip_scalar, (struct mib_node*)&ip_scalar, (struct mib_node*)&ip_scalar, (struct mib_node*)&ip_scalar, (struct mib_node*)&ip_scalar, (struct mib_node*)&ip_scalar, (struct mib_node*)&ip_scalar, (struct mib_node*)&ip_scalar, (struct mib_node*)&ip_scalar, (struct mib_node*)&ip_scalar, (struct mib_node*)&ip_scalar, (struct mib_node*)&ip_scalar, (struct mib_node*)&ip_scalar, (struct mib_node*)&ip_scalar, (struct mib_node*)&ip_scalar, (struct mib_node*)&ip_scalar, (struct mib_node*)&ip_scalar, (struct mib_node*)&ipaddrtable, (struct mib_node*)&iprtetable, (struct mib_node*)&ipntomtable, (struct mib_node*)&ip_scalar }; const struct mib_array_node mib2_ip = { &noleafs_get_object_def, &noleafs_get_value, &noleafs_set_test, &noleafs_set_value, MIB_NODE_AR, 23, ip_ids, ip_nodes }; /** index root node for atTable */ struct mib_list_rootnode arptree_root = { &noleafs_get_object_def, &noleafs_get_value, &noleafs_set_test, &noleafs_set_value, MIB_NODE_LR, 0, NULL, NULL, 0 }; const s32_t atentry_ids[3] = { 1, 2, 3 }; struct mib_node* const atentry_nodes[3] = { (struct mib_node*)&arptree_root, (struct mib_node*)&arptree_root, (struct mib_node*)&arptree_root }; const struct mib_array_node atentry = { &noleafs_get_object_def, &noleafs_get_value, &noleafs_set_test, &noleafs_set_value, MIB_NODE_AR, 3, atentry_ids, atentry_nodes }; const s32_t attable_id = 1; struct mib_node* const attable_node = (struct mib_node*)&atentry; const struct mib_array_node attable = { &noleafs_get_object_def, &noleafs_get_value, &noleafs_set_test, &noleafs_set_value, MIB_NODE_AR, 1, &attable_id, &attable_node }; /* at .1.3.6.1.2.1.3 */ s32_t at_id = 1; struct mib_node* mib2_at_node = (struct mib_node*)&attable; struct mib_ram_array_node at = { &noleafs_get_object_def, &noleafs_get_value, &noleafs_set_test, &noleafs_set_value, MIB_NODE_RA, 0, &at_id, &mib2_at_node }; /** index root node for ifTable */ struct mib_list_rootnode iflist_root = { &ifentry_get_object_def, &ifentry_get_value, #if SNMP_SAFE_REQUESTS &noleafs_set_test, &noleafs_set_value, #else /* SNMP_SAFE_REQUESTS */ &ifentry_set_test, &ifentry_set_value, #endif /* SNMP_SAFE_REQUESTS */ MIB_NODE_LR, 0, NULL, NULL, 0 }; const s32_t ifentry_ids[22] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22 }; struct mib_node* const ifentry_nodes[22] = { (struct mib_node*)&iflist_root, (struct mib_node*)&iflist_root, (struct mib_node*)&iflist_root, (struct mib_node*)&iflist_root, (struct mib_node*)&iflist_root, (struct mib_node*)&iflist_root, (struct mib_node*)&iflist_root, (struct mib_node*)&iflist_root, (struct mib_node*)&iflist_root, (struct mib_node*)&iflist_root, (struct mib_node*)&iflist_root, (struct mib_node*)&iflist_root, (struct mib_node*)&iflist_root, (struct mib_node*)&iflist_root, (struct mib_node*)&iflist_root, (struct mib_node*)&iflist_root, (struct mib_node*)&iflist_root, (struct mib_node*)&iflist_root, (struct mib_node*)&iflist_root, (struct mib_node*)&iflist_root, (struct mib_node*)&iflist_root, (struct mib_node*)&iflist_root }; const struct mib_array_node ifentry = { &noleafs_get_object_def, &noleafs_get_value, &noleafs_set_test, &noleafs_set_value, MIB_NODE_AR, 22, ifentry_ids, ifentry_nodes }; s32_t iftable_id = 1; struct mib_node* iftable_node = (struct mib_node*)&ifentry; struct mib_ram_array_node iftable = { &noleafs_get_object_def, &noleafs_get_value, &noleafs_set_test, &noleafs_set_value, MIB_NODE_RA, 0, &iftable_id, &iftable_node }; /* interfaces .1.3.6.1.2.1.2 */ const mib_scalar_node interfaces_scalar = { &interfaces_get_object_def, &interfaces_get_value, &noleafs_set_test, &noleafs_set_value, MIB_NODE_SC, 0 }; const s32_t interfaces_ids[2] = { 1, 2 }; struct mib_node* const interfaces_nodes[2] = { (struct mib_node*)&interfaces_scalar, (struct mib_node*)&iftable }; const struct mib_array_node interfaces = { &noleafs_get_object_def, &noleafs_get_value, &noleafs_set_test, &noleafs_set_value, MIB_NODE_AR, 2, interfaces_ids, interfaces_nodes }; /* 0 1 2 3 4 5 6 */ /* system .1.3.6.1.2.1.1 */ const mib_scalar_node sys_tem_scalar = { &system_get_object_def, &system_get_value, &system_set_test, &system_set_value, MIB_NODE_SC, 0 }; const s32_t sys_tem_ids[7] = { 1, 2, 3, 4, 5, 6, 7 }; struct mib_node* const sys_tem_nodes[7] = { (struct mib_node*)&sys_tem_scalar, (struct mib_node*)&sys_tem_scalar, (struct mib_node*)&sys_tem_scalar, (struct mib_node*)&sys_tem_scalar, (struct mib_node*)&sys_tem_scalar, (struct mib_node*)&sys_tem_scalar, (struct mib_node*)&sys_tem_scalar }; /* work around name issue with 'sys_tem', some compiler(s?) seem to reserve 'system' */ const struct mib_array_node sys_tem = { &noleafs_get_object_def, &noleafs_get_value, &noleafs_set_test, &noleafs_set_value, MIB_NODE_AR, 7, sys_tem_ids, sys_tem_nodes }; /* mib-2 .1.3.6.1.2.1 */ #if LWIP_TCP #define MIB2_GROUPS 8 #else #define MIB2_GROUPS 7 #endif const s32_t mib2_ids[MIB2_GROUPS] = { 1, 2, 3, 4, 5, #if LWIP_TCP 6, #endif 7, 11 }; struct mib_node* const mib2_nodes[MIB2_GROUPS] = { (struct mib_node*)&sys_tem, (struct mib_node*)&interfaces, (struct mib_node*)&at, (struct mib_node*)&mib2_ip, (struct mib_node*)&icmp, #if LWIP_TCP (struct mib_node*)&tcp, #endif (struct mib_node*)&udp, (struct mib_node*)&snmp }; const struct mib_array_node mib2 = { &noleafs_get_object_def, &noleafs_get_value, &noleafs_set_test, &noleafs_set_value, MIB_NODE_AR, MIB2_GROUPS, mib2_ids, mib2_nodes }; /* mgmt .1.3.6.1.2 */ const s32_t mgmt_ids[1] = { 1 }; struct mib_node* const mgmt_nodes[1] = { (struct mib_node*)&mib2 }; const struct mib_array_node mgmt = { &noleafs_get_object_def, &noleafs_get_value, &noleafs_set_test, &noleafs_set_value, MIB_NODE_AR, 1, mgmt_ids, mgmt_nodes }; /* internet .1.3.6.1 */ #if SNMP_PRIVATE_MIB /* When using a private MIB, you have to create a file 'private_mib.h' that contains * a 'struct mib_array_node mib_private' which contains your MIB. */ s32_t internet_ids[2] = { 2, 4 }; struct mib_node* const internet_nodes[2] = { (struct mib_node*)&mgmt, (struct mib_node*)&mib_private }; const struct mib_array_node internet = { &noleafs_get_object_def, &noleafs_get_value, &noleafs_set_test, &noleafs_set_value, MIB_NODE_AR, 2, internet_ids, internet_nodes }; #else const s32_t internet_ids[1] = { 2 }; struct mib_node* const internet_nodes[1] = { (struct mib_node*)&mgmt }; const struct mib_array_node internet = { &noleafs_get_object_def, &noleafs_get_value, &noleafs_set_test, &noleafs_set_value, MIB_NODE_AR, 1, internet_ids, internet_nodes }; #endif /** mib-2.system.sysObjectID */ static const struct snmp_obj_id sysobjid_default = {SNMP_SYSOBJID_LEN, SNMP_SYSOBJID}; static const struct snmp_obj_id* sysobjid_ptr = &sysobjid_default; /** enterprise ID for generic TRAPs, .iso.org.dod.internet.mgmt.mib-2.snmp */ static struct snmp_obj_id snmpgrp_id = {7,{1,3,6,1,2,1,11}}; /** mib-2.system.sysServices */ static const s32_t sysservices = SNMP_SYSSERVICES; /** mib-2.system.sysDescr */ static const u8_t sysdescr_len_default = 4; static const u8_t sysdescr_default[] = "lwIP"; static const u8_t* sysdescr_len_ptr = &sysdescr_len_default; static const u8_t* sysdescr_ptr = &sysdescr_default[0]; /** mib-2.system.sysContact */ static const u8_t syscontact_len_default = 0; static const u8_t syscontact_default[] = ""; static u8_t* syscontact_len_ptr = (u8_t*)&syscontact_len_default; static u8_t* syscontact_ptr = (u8_t*)&syscontact_default[0]; /** mib-2.system.sysName */ static const u8_t sysname_len_default = 8; static const u8_t sysname_default[] = "FQDN-unk"; static u8_t* sysname_len_ptr = (u8_t*)&sysname_len_default; static u8_t* sysname_ptr = (u8_t*)&sysname_default[0]; /** mib-2.system.sysLocation */ static const u8_t syslocation_len_default = 0; static const u8_t syslocation_default[] = ""; static u8_t* syslocation_len_ptr = (u8_t*)&syslocation_len_default; static u8_t* syslocation_ptr = (u8_t*)&syslocation_default[0]; /** mib-2.snmp.snmpEnableAuthenTraps */ static const u8_t snmpenableauthentraps_default = 2; /* disabled */ static u8_t* snmpenableauthentraps_ptr = (u8_t*)&snmpenableauthentraps_default; /** mib-2.interfaces.ifTable.ifEntry.ifSpecific (zeroDotZero) */ static const struct snmp_obj_id ifspecific = {2, {0, 0}}; /** mib-2.ip.ipRouteTable.ipRouteEntry.ipRouteInfo (zeroDotZero) */ static const struct snmp_obj_id iprouteinfo = {2, {0, 0}}; /* mib-2.system counter(s) */ static u32_t sysuptime = 0; /* mib-2.ip counter(s) */ static u32_t ipinreceives = 0, ipinhdrerrors = 0, ipinaddrerrors = 0, ipforwdatagrams = 0, ipinunknownprotos = 0, ipindiscards = 0, ipindelivers = 0, ipoutrequests = 0, ipoutdiscards = 0, ipoutnoroutes = 0, ipreasmreqds = 0, ipreasmoks = 0, ipreasmfails = 0, ipfragoks = 0, ipfragfails = 0, ipfragcreates = 0, iproutingdiscards = 0; /* mib-2.icmp counter(s) */ static u32_t icmpinmsgs = 0, icmpinerrors = 0, icmpindestunreachs = 0, icmpintimeexcds = 0, icmpinparmprobs = 0, icmpinsrcquenchs = 0, icmpinredirects = 0, icmpinechos = 0, icmpinechoreps = 0, icmpintimestamps = 0, icmpintimestampreps = 0, icmpinaddrmasks = 0, icmpinaddrmaskreps = 0, icmpoutmsgs = 0, icmpouterrors = 0, icmpoutdestunreachs = 0, icmpouttimeexcds = 0, icmpoutparmprobs = 0, icmpoutsrcquenchs = 0, icmpoutredirects = 0, icmpoutechos = 0, icmpoutechoreps = 0, icmpouttimestamps = 0, icmpouttimestampreps = 0, icmpoutaddrmasks = 0, icmpoutaddrmaskreps = 0; /* mib-2.tcp counter(s) */ static u32_t tcpactiveopens = 0, tcppassiveopens = 0, tcpattemptfails = 0, tcpestabresets = 0, tcpinsegs = 0, tcpoutsegs = 0, tcpretranssegs = 0, tcpinerrs = 0, tcpoutrsts = 0; /* mib-2.udp counter(s) */ static u32_t udpindatagrams = 0, udpnoports = 0, udpinerrors = 0, udpoutdatagrams = 0; /* mib-2.snmp counter(s) */ static u32_t snmpinpkts = 0, snmpoutpkts = 0, snmpinbadversions = 0, snmpinbadcommunitynames = 0, snmpinbadcommunityuses = 0, snmpinasnparseerrs = 0, snmpintoobigs = 0, snmpinnosuchnames = 0, snmpinbadvalues = 0, snmpinreadonlys = 0, snmpingenerrs = 0, snmpintotalreqvars = 0, snmpintotalsetvars = 0, snmpingetrequests = 0, snmpingetnexts = 0, snmpinsetrequests = 0, snmpingetresponses = 0, snmpintraps = 0, snmpouttoobigs = 0, snmpoutnosuchnames = 0, snmpoutbadvalues = 0, snmpoutgenerrs = 0, snmpoutgetrequests = 0, snmpoutgetnexts = 0, snmpoutsetrequests = 0, snmpoutgetresponses = 0, snmpouttraps = 0; /** * Initializes sysDescr pointers. * * @param str if non-NULL then copy str pointer * @param len points to string length, excluding zero terminator */ void snmp_set_sysdescr(const u8_t *str, const u8_t *len) { if (str != NULL) { sysdescr_ptr = str; sysdescr_len_ptr = len; } } void snmp_get_sysobjid_ptr(const struct snmp_obj_id **oid) { *oid = sysobjid_ptr; } /** * Initializes sysObjectID value. * * @param oid points to stuct snmp_obj_id to copy */ void snmp_set_sysobjid(const struct snmp_obj_id *oid) { sysobjid_ptr = oid; } /** * Must be called at regular 10 msec interval from a timer interrupt * or signal handler depending on your runtime environment. */ void snmp_inc_sysuptime(void) { sysuptime++; } void snmp_add_sysuptime(u32_t value) { sysuptime+=value; } void snmp_get_sysuptime(u32_t *value) { SNMP_GET_SYSUPTIME(sysuptime); *value = sysuptime; } /** * Initializes sysContact pointers, * e.g. ptrs to non-volatile memory external to lwIP. * * @param ocstr if non-NULL then copy str pointer * @param ocstrlen points to string length, excluding zero terminator */ void snmp_set_syscontact(u8_t *ocstr, u8_t *ocstrlen) { if (ocstr != NULL) { syscontact_ptr = ocstr; syscontact_len_ptr = ocstrlen; } } /** * Initializes sysName pointers, * e.g. ptrs to non-volatile memory external to lwIP. * * @param ocstr if non-NULL then copy str pointer * @param ocstrlen points to string length, excluding zero terminator */ void snmp_set_sysname(u8_t *ocstr, u8_t *ocstrlen) { if (ocstr != NULL) { sysname_ptr = ocstr; sysname_len_ptr = ocstrlen; } } /** * Initializes sysLocation pointers, * e.g. ptrs to non-volatile memory external to lwIP. * * @param ocstr if non-NULL then copy str pointer * @param ocstrlen points to string length, excluding zero terminator */ void snmp_set_syslocation(u8_t *ocstr, u8_t *ocstrlen) { if (ocstr != NULL) { syslocation_ptr = ocstr; syslocation_len_ptr = ocstrlen; } } void snmp_add_ifinoctets(struct netif *ni, u32_t value) { ni->ifinoctets += value; } void snmp_inc_ifinucastpkts(struct netif *ni) { (ni->ifinucastpkts)++; } void snmp_inc_ifinnucastpkts(struct netif *ni) { (ni->ifinnucastpkts)++; } void snmp_inc_ifindiscards(struct netif *ni) { (ni->ifindiscards)++; } void snmp_add_ifoutoctets(struct netif *ni, u32_t value) { ni->ifoutoctets += value; } void snmp_inc_ifoutucastpkts(struct netif *ni) { (ni->ifoutucastpkts)++; } void snmp_inc_ifoutnucastpkts(struct netif *ni) { (ni->ifoutnucastpkts)++; } void snmp_inc_ifoutdiscards(struct netif *ni) { (ni->ifoutdiscards)++; } void snmp_inc_iflist(void) { struct mib_list_node *if_node = NULL; snmp_mib_node_insert(&iflist_root, iflist_root.count + 1, &if_node); /* enable getnext traversal on filled table */ iftable.maxlength = 1; } void snmp_dec_iflist(void) { snmp_mib_node_delete(&iflist_root, iflist_root.tail); /* disable getnext traversal on empty table */ if(iflist_root.count == 0) iftable.maxlength = 0; } /** * Inserts ARP table indexes (.xIfIndex.xNetAddress) * into arp table index trees (both atTable and ipNetToMediaTable). */ void snmp_insert_arpidx_tree(struct netif *ni, ip_addr_t *ip) { struct mib_list_rootnode *at_rn; struct mib_list_node *at_node; s32_t arpidx[5]; u8_t level, tree; LWIP_ASSERT("ni != NULL", ni != NULL); snmp_netiftoifindex(ni, &arpidx[0]); snmp_iptooid(ip, &arpidx[1]); for (tree = 0; tree < 2; tree++) { if (tree == 0) { at_rn = &arptree_root; } else { at_rn = &ipntomtree_root; } for (level = 0; level < 5; level++) { at_node = NULL; snmp_mib_node_insert(at_rn, arpidx[level], &at_node); if ((level != 4) && (at_node != NULL)) { if (at_node->nptr == NULL) { at_rn = snmp_mib_lrn_alloc(); at_node->nptr = (struct mib_node*)at_rn; if (at_rn != NULL) { if (level == 3) { if (tree == 0) { at_rn->get_object_def = atentry_get_object_def; at_rn->get_value = atentry_get_value; } else { at_rn->get_object_def = ip_ntomentry_get_object_def; at_rn->get_value = ip_ntomentry_get_value; } at_rn->set_test = noleafs_set_test; at_rn->set_value = noleafs_set_value; } } else { /* at_rn == NULL, malloc failure */ LWIP_DEBUGF(SNMP_MIB_DEBUG,("snmp_insert_arpidx_tree() insert failed, mem full")); break; } } else { at_rn = (struct mib_list_rootnode*)at_node->nptr; } } } } /* enable getnext traversal on filled tables */ at.maxlength = 1; ipntomtable.maxlength = 1; } /** * Removes ARP table indexes (.xIfIndex.xNetAddress) * from arp table index trees. */ void snmp_delete_arpidx_tree(struct netif *ni, ip_addr_t *ip) { struct mib_list_rootnode *at_rn, *next, *del_rn[5]; struct mib_list_node *at_n, *del_n[5]; s32_t arpidx[5]; u8_t fc, tree, level, del_cnt; snmp_netiftoifindex(ni, &arpidx[0]); snmp_iptooid(ip, &arpidx[1]); for (tree = 0; tree < 2; tree++) { /* mark nodes for deletion */ if (tree == 0) { at_rn = &arptree_root; } else { at_rn = &ipntomtree_root; } level = 0; del_cnt = 0; while ((level < 5) && (at_rn != NULL)) { fc = snmp_mib_node_find(at_rn, arpidx[level], &at_n); if (fc == 0) { /* arpidx[level] does not exist */ del_cnt = 0; at_rn = NULL; } else if (fc == 1) { del_rn[del_cnt] = at_rn; del_n[del_cnt] = at_n; del_cnt++; at_rn = (struct mib_list_rootnode*)(at_n->nptr); } else if (fc == 2) { /* reset delete (2 or more childs) */ del_cnt = 0; at_rn = (struct mib_list_rootnode*)(at_n->nptr); } level++; } /* delete marked index nodes */ while (del_cnt > 0) { del_cnt--; at_rn = del_rn[del_cnt]; at_n = del_n[del_cnt]; next = snmp_mib_node_delete(at_rn, at_n); if (next != NULL) { LWIP_ASSERT("next_count == 0",next->count == 0); snmp_mib_lrn_free(next); } } } /* disable getnext traversal on empty tables */ if(arptree_root.count == 0) at.maxlength = 0; if(ipntomtree_root.count == 0) ipntomtable.maxlength = 0; } void snmp_inc_ipinreceives(void) { ipinreceives++; } void snmp_inc_ipinhdrerrors(void) { ipinhdrerrors++; } void snmp_inc_ipinaddrerrors(void) { ipinaddrerrors++; } void snmp_inc_ipforwdatagrams(void) { ipforwdatagrams++; } void snmp_inc_ipinunknownprotos(void) { ipinunknownprotos++; } void snmp_inc_ipindiscards(void) { ipindiscards++; } void snmp_inc_ipindelivers(void) { ipindelivers++; } void snmp_inc_ipoutrequests(void) { ipoutrequests++; } void snmp_inc_ipoutdiscards(void) { ipoutdiscards++; } void snmp_inc_ipoutnoroutes(void) { ipoutnoroutes++; } void snmp_inc_ipreasmreqds(void) { ipreasmreqds++; } void snmp_inc_ipreasmoks(void) { ipreasmoks++; } void snmp_inc_ipreasmfails(void) { ipreasmfails++; } void snmp_inc_ipfragoks(void) { ipfragoks++; } void snmp_inc_ipfragfails(void) { ipfragfails++; } void snmp_inc_ipfragcreates(void) { ipfragcreates++; } void snmp_inc_iproutingdiscards(void) { iproutingdiscards++; } /** * Inserts ipAddrTable indexes (.ipAdEntAddr) * into index tree. */ void snmp_insert_ipaddridx_tree(struct netif *ni) { struct mib_list_rootnode *ipa_rn; struct mib_list_node *ipa_node; s32_t ipaddridx[4]; u8_t level; LWIP_ASSERT("ni != NULL", ni != NULL); snmp_iptooid(&ni->ip_addr, &ipaddridx[0]); level = 0; ipa_rn = &ipaddrtree_root; while (level < 4) { ipa_node = NULL; snmp_mib_node_insert(ipa_rn, ipaddridx[level], &ipa_node); if ((level != 3) && (ipa_node != NULL)) { if (ipa_node->nptr == NULL) { ipa_rn = snmp_mib_lrn_alloc(); ipa_node->nptr = (struct mib_node*)ipa_rn; if (ipa_rn != NULL) { if (level == 2) { ipa_rn->get_object_def = ip_addrentry_get_object_def; ipa_rn->get_value = ip_addrentry_get_value; ipa_rn->set_test = noleafs_set_test; ipa_rn->set_value = noleafs_set_value; } } else { /* ipa_rn == NULL, malloc failure */ LWIP_DEBUGF(SNMP_MIB_DEBUG,("snmp_insert_ipaddridx_tree() insert failed, mem full")); break; } } else { ipa_rn = (struct mib_list_rootnode*)ipa_node->nptr; } } level++; } /* enable getnext traversal on filled table */ ipaddrtable.maxlength = 1; } /** * Removes ipAddrTable indexes (.ipAdEntAddr) * from index tree. */ void snmp_delete_ipaddridx_tree(struct netif *ni) { struct mib_list_rootnode *ipa_rn, *next, *del_rn[4]; struct mib_list_node *ipa_n, *del_n[4]; s32_t ipaddridx[4]; u8_t fc, level, del_cnt; LWIP_ASSERT("ni != NULL", ni != NULL); snmp_iptooid(&ni->ip_addr, &ipaddridx[0]); /* mark nodes for deletion */ level = 0; del_cnt = 0; ipa_rn = &ipaddrtree_root; while ((level < 4) && (ipa_rn != NULL)) { fc = snmp_mib_node_find(ipa_rn, ipaddridx[level], &ipa_n); if (fc == 0) { /* ipaddridx[level] does not exist */ del_cnt = 0; ipa_rn = NULL; } else if (fc == 1) { del_rn[del_cnt] = ipa_rn; del_n[del_cnt] = ipa_n; del_cnt++; ipa_rn = (struct mib_list_rootnode*)(ipa_n->nptr); } else if (fc == 2) { /* reset delete (2 or more childs) */ del_cnt = 0; ipa_rn = (struct mib_list_rootnode*)(ipa_n->nptr); } level++; } /* delete marked index nodes */ while (del_cnt > 0) { del_cnt--; ipa_rn = del_rn[del_cnt]; ipa_n = del_n[del_cnt]; next = snmp_mib_node_delete(ipa_rn, ipa_n); if (next != NULL) { LWIP_ASSERT("next_count == 0",next->count == 0); snmp_mib_lrn_free(next); } } /* disable getnext traversal on empty table */ if (ipaddrtree_root.count == 0) ipaddrtable.maxlength = 0; } /** * Inserts ipRouteTable indexes (.ipRouteDest) * into index tree. * * @param dflt non-zero for the default rte, zero for network rte * @param ni points to network interface for this rte * * @todo record sysuptime for _this_ route when it is installed * (needed for ipRouteAge) in the netif. */ void snmp_insert_iprteidx_tree(u8_t dflt, struct netif *ni) { u8_t insert = 0; ip_addr_t dst; if (dflt != 0) { /* the default route 0.0.0.0 */ ip_addr_set_any(&dst); insert = 1; } else { /* route to the network address */ ip_addr_get_network(&dst, &ni->ip_addr, &ni->netmask); /* exclude 0.0.0.0 network (reserved for default rte) */ if (!ip_addr_isany(&dst)) { insert = 1; } } if (insert) { struct mib_list_rootnode *iprte_rn; struct mib_list_node *iprte_node; s32_t iprteidx[4]; u8_t level; snmp_iptooid(&dst, &iprteidx[0]); level = 0; iprte_rn = &iprtetree_root; while (level < 4) { iprte_node = NULL; snmp_mib_node_insert(iprte_rn, iprteidx[level], &iprte_node); if ((level != 3) && (iprte_node != NULL)) { if (iprte_node->nptr == NULL) { iprte_rn = snmp_mib_lrn_alloc(); iprte_node->nptr = (struct mib_node*)iprte_rn; if (iprte_rn != NULL) { if (level == 2) { iprte_rn->get_object_def = ip_rteentry_get_object_def; iprte_rn->get_value = ip_rteentry_get_value; iprte_rn->set_test = noleafs_set_test; iprte_rn->set_value = noleafs_set_value; } } else { /* iprte_rn == NULL, malloc failure */ LWIP_DEBUGF(SNMP_MIB_DEBUG,("snmp_insert_iprteidx_tree() insert failed, mem full")); break; } } else { iprte_rn = (struct mib_list_rootnode*)iprte_node->nptr; } } level++; } } /* enable getnext traversal on filled table */ iprtetable.maxlength = 1; } /** * Removes ipRouteTable indexes (.ipRouteDest) * from index tree. * * @param dflt non-zero for the default rte, zero for network rte * @param ni points to network interface for this rte or NULL * for default route to be removed. */ void snmp_delete_iprteidx_tree(u8_t dflt, struct netif *ni) { u8_t del = 0; ip_addr_t dst; if (dflt != 0) { /* the default route 0.0.0.0 */ ip_addr_set_any(&dst); del = 1; } else { /* route to the network address */ ip_addr_get_network(&dst, &ni->ip_addr, &ni->netmask); /* exclude 0.0.0.0 network (reserved for default rte) */ if (!ip_addr_isany(&dst)) { del = 1; } } if (del) { struct mib_list_rootnode *iprte_rn, *next, *del_rn[4]; struct mib_list_node *iprte_n, *del_n[4]; s32_t iprteidx[4]; u8_t fc, level, del_cnt; snmp_iptooid(&dst, &iprteidx[0]); /* mark nodes for deletion */ level = 0; del_cnt = 0; iprte_rn = &iprtetree_root; while ((level < 4) && (iprte_rn != NULL)) { fc = snmp_mib_node_find(iprte_rn, iprteidx[level], &iprte_n); if (fc == 0) { /* iprteidx[level] does not exist */ del_cnt = 0; iprte_rn = NULL; } else if (fc == 1) { del_rn[del_cnt] = iprte_rn; del_n[del_cnt] = iprte_n; del_cnt++; iprte_rn = (struct mib_list_rootnode*)(iprte_n->nptr); } else if (fc == 2) { /* reset delete (2 or more childs) */ del_cnt = 0; iprte_rn = (struct mib_list_rootnode*)(iprte_n->nptr); } level++; } /* delete marked index nodes */ while (del_cnt > 0) { del_cnt--; iprte_rn = del_rn[del_cnt]; iprte_n = del_n[del_cnt]; next = snmp_mib_node_delete(iprte_rn, iprte_n); if (next != NULL) { LWIP_ASSERT("next_count == 0",next->count == 0); snmp_mib_lrn_free(next); } } } /* disable getnext traversal on empty table */ if (iprtetree_root.count == 0) iprtetable.maxlength = 0; } void snmp_inc_icmpinmsgs(void) { icmpinmsgs++; } void snmp_inc_icmpinerrors(void) { icmpinerrors++; } void snmp_inc_icmpindestunreachs(void) { icmpindestunreachs++; } void snmp_inc_icmpintimeexcds(void) { icmpintimeexcds++; } void snmp_inc_icmpinparmprobs(void) { icmpinparmprobs++; } void snmp_inc_icmpinsrcquenchs(void) { icmpinsrcquenchs++; } void snmp_inc_icmpinredirects(void) { icmpinredirects++; } void snmp_inc_icmpinechos(void) { icmpinechos++; } void snmp_inc_icmpinechoreps(void) { icmpinechoreps++; } void snmp_inc_icmpintimestamps(void) { icmpintimestamps++; } void snmp_inc_icmpintimestampreps(void) { icmpintimestampreps++; } void snmp_inc_icmpinaddrmasks(void) { icmpinaddrmasks++; } void snmp_inc_icmpinaddrmaskreps(void) { icmpinaddrmaskreps++; } void snmp_inc_icmpoutmsgs(void) { icmpoutmsgs++; } void snmp_inc_icmpouterrors(void) { icmpouterrors++; } void snmp_inc_icmpoutdestunreachs(void) { icmpoutdestunreachs++; } void snmp_inc_icmpouttimeexcds(void) { icmpouttimeexcds++; } void snmp_inc_icmpoutparmprobs(void) { icmpoutparmprobs++; } void snmp_inc_icmpoutsrcquenchs(void) { icmpoutsrcquenchs++; } void snmp_inc_icmpoutredirects(void) { icmpoutredirects++; } void snmp_inc_icmpoutechos(void) { icmpoutechos++; } void snmp_inc_icmpoutechoreps(void) { icmpoutechoreps++; } void snmp_inc_icmpouttimestamps(void) { icmpouttimestamps++; } void snmp_inc_icmpouttimestampreps(void) { icmpouttimestampreps++; } void snmp_inc_icmpoutaddrmasks(void) { icmpoutaddrmasks++; } void snmp_inc_icmpoutaddrmaskreps(void) { icmpoutaddrmaskreps++; } void snmp_inc_tcpactiveopens(void) { tcpactiveopens++; } void snmp_inc_tcppassiveopens(void) { tcppassiveopens++; } void snmp_inc_tcpattemptfails(void) { tcpattemptfails++; } void snmp_inc_tcpestabresets(void) { tcpestabresets++; } void snmp_inc_tcpinsegs(void) { tcpinsegs++; } void snmp_inc_tcpoutsegs(void) { tcpoutsegs++; } void snmp_inc_tcpretranssegs(void) { tcpretranssegs++; } void snmp_inc_tcpinerrs(void) { tcpinerrs++; } void snmp_inc_tcpoutrsts(void) { tcpoutrsts++; } void snmp_inc_udpindatagrams(void) { udpindatagrams++; } void snmp_inc_udpnoports(void) { udpnoports++; } void snmp_inc_udpinerrors(void) { udpinerrors++; } void snmp_inc_udpoutdatagrams(void) { udpoutdatagrams++; } /** * Inserts udpTable indexes (.udpLocalAddress.udpLocalPort) * into index tree. */ void snmp_insert_udpidx_tree(struct udp_pcb *pcb) { struct mib_list_rootnode *udp_rn; struct mib_list_node *udp_node; s32_t udpidx[5]; u8_t level; LWIP_ASSERT("pcb != NULL", pcb != NULL); snmp_iptooid(ipX_2_ip(&pcb->local_ip), &udpidx[0]); udpidx[4] = pcb->local_port; udp_rn = &udp_root; for (level = 0; level < 5; level++) { udp_node = NULL; snmp_mib_node_insert(udp_rn, udpidx[level], &udp_node); if ((level != 4) && (udp_node != NULL)) { if (udp_node->nptr == NULL) { udp_rn = snmp_mib_lrn_alloc(); udp_node->nptr = (struct mib_node*)udp_rn; if (udp_rn != NULL) { if (level == 3) { udp_rn->get_object_def = udpentry_get_object_def; udp_rn->get_value = udpentry_get_value; udp_rn->set_test = noleafs_set_test; udp_rn->set_value = noleafs_set_value; } } else { /* udp_rn == NULL, malloc failure */ LWIP_DEBUGF(SNMP_MIB_DEBUG,("snmp_insert_udpidx_tree() insert failed, mem full")); break; } } else { udp_rn = (struct mib_list_rootnode*)udp_node->nptr; } } } udptable.maxlength = 1; } /** * Removes udpTable indexes (.udpLocalAddress.udpLocalPort) * from index tree. */ void snmp_delete_udpidx_tree(struct udp_pcb *pcb) { struct udp_pcb *npcb; struct mib_list_rootnode *udp_rn, *next, *del_rn[5]; struct mib_list_node *udp_n, *del_n[5]; s32_t udpidx[5]; u8_t bindings, fc, level, del_cnt; LWIP_ASSERT("pcb != NULL", pcb != NULL); snmp_iptooid(ipX_2_ip(&pcb->local_ip), &udpidx[0]); udpidx[4] = pcb->local_port; /* count PCBs for a given binding (e.g. when reusing ports or for temp output PCBs) */ bindings = 0; npcb = udp_pcbs; while ((npcb != NULL)) { if (ipX_addr_cmp(0, &npcb->local_ip, &pcb->local_ip) && (npcb->local_port == udpidx[4])) { bindings++; } npcb = npcb->next; } if (bindings == 1) { /* selectively remove */ /* mark nodes for deletion */ level = 0; del_cnt = 0; udp_rn = &udp_root; while ((level < 5) && (udp_rn != NULL)) { fc = snmp_mib_node_find(udp_rn, udpidx[level], &udp_n); if (fc == 0) { /* udpidx[level] does not exist */ del_cnt = 0; udp_rn = NULL; } else if (fc == 1) { del_rn[del_cnt] = udp_rn; del_n[del_cnt] = udp_n; del_cnt++; udp_rn = (struct mib_list_rootnode*)(udp_n->nptr); } else if (fc == 2) { /* reset delete (2 or more childs) */ del_cnt = 0; udp_rn = (struct mib_list_rootnode*)(udp_n->nptr); } level++; } /* delete marked index nodes */ while (del_cnt > 0) { del_cnt--; udp_rn = del_rn[del_cnt]; udp_n = del_n[del_cnt]; next = snmp_mib_node_delete(udp_rn, udp_n); if (next != NULL) { LWIP_ASSERT("next_count == 0",next->count == 0); snmp_mib_lrn_free(next); } } } /* disable getnext traversal on empty table */ if (udp_root.count == 0) udptable.maxlength = 0; } void snmp_inc_snmpinpkts(void) { snmpinpkts++; } void snmp_inc_snmpoutpkts(void) { snmpoutpkts++; } void snmp_inc_snmpinbadversions(void) { snmpinbadversions++; } void snmp_inc_snmpinbadcommunitynames(void) { snmpinbadcommunitynames++; } void snmp_inc_snmpinbadcommunityuses(void) { snmpinbadcommunityuses++; } void snmp_inc_snmpinasnparseerrs(void) { snmpinasnparseerrs++; } void snmp_inc_snmpintoobigs(void) { snmpintoobigs++; } void snmp_inc_snmpinnosuchnames(void) { snmpinnosuchnames++; } void snmp_inc_snmpinbadvalues(void) { snmpinbadvalues++; } void snmp_inc_snmpinreadonlys(void) { snmpinreadonlys++; } void snmp_inc_snmpingenerrs(void) { snmpingenerrs++; } void snmp_add_snmpintotalreqvars(u8_t value) { snmpintotalreqvars += value; } void snmp_add_snmpintotalsetvars(u8_t value) { snmpintotalsetvars += value; } void snmp_inc_snmpingetrequests(void) { snmpingetrequests++; } void snmp_inc_snmpingetnexts(void) { snmpingetnexts++; } void snmp_inc_snmpinsetrequests(void) { snmpinsetrequests++; } void snmp_inc_snmpingetresponses(void) { snmpingetresponses++; } void snmp_inc_snmpintraps(void) { snmpintraps++; } void snmp_inc_snmpouttoobigs(void) { snmpouttoobigs++; } void snmp_inc_snmpoutnosuchnames(void) { snmpoutnosuchnames++; } void snmp_inc_snmpoutbadvalues(void) { snmpoutbadvalues++; } void snmp_inc_snmpoutgenerrs(void) { snmpoutgenerrs++; } void snmp_inc_snmpoutgetrequests(void) { snmpoutgetrequests++; } void snmp_inc_snmpoutgetnexts(void) { snmpoutgetnexts++; } void snmp_inc_snmpoutsetrequests(void) { snmpoutsetrequests++; } void snmp_inc_snmpoutgetresponses(void) { snmpoutgetresponses++; } void snmp_inc_snmpouttraps(void) { snmpouttraps++; } void snmp_get_snmpgrpid_ptr(struct snmp_obj_id **oid) { *oid = &snmpgrp_id; } void snmp_set_snmpenableauthentraps(u8_t *value) { if (value != NULL) { snmpenableauthentraps_ptr = value; } } void snmp_get_snmpenableauthentraps(u8_t *value) { *value = *snmpenableauthentraps_ptr; } void noleafs_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od) { LWIP_UNUSED_ARG(ident_len); LWIP_UNUSED_ARG(ident); od->instance = MIB_OBJECT_NONE; } void noleafs_get_value(struct obj_def *od, u16_t len, void *value) { LWIP_UNUSED_ARG(od); LWIP_UNUSED_ARG(len); LWIP_UNUSED_ARG(value); } u8_t noleafs_set_test(struct obj_def *od, u16_t len, void *value) { LWIP_UNUSED_ARG(od); LWIP_UNUSED_ARG(len); LWIP_UNUSED_ARG(value); /* can't set */ return 0; } void noleafs_set_value(struct obj_def *od, u16_t len, void *value) { LWIP_UNUSED_ARG(od); LWIP_UNUSED_ARG(len); LWIP_UNUSED_ARG(value); } /** * Returns systems object definitions. * * @param ident_len the address length (2) * @param ident points to objectname.0 (object id trailer) * @param od points to object definition. */ static void system_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od) { u8_t id; /* return to object name, adding index depth (1) */ ident_len += 1; ident -= 1; if (ident_len == 2) { od->id_inst_len = ident_len; od->id_inst_ptr = ident; LWIP_ASSERT("invalid id", (ident[0] >= 0) && (ident[0] <= 0xff)); id = (u8_t)ident[0]; LWIP_DEBUGF(SNMP_MIB_DEBUG,("get_object_def system.%"U16_F".0\n",(u16_t)id)); switch (id) { case 1: /* sysDescr */ od->instance = MIB_OBJECT_SCALAR; od->access = MIB_OBJECT_READ_ONLY; od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR); od->v_len = *sysdescr_len_ptr; break; case 2: /* sysObjectID */ od->instance = MIB_OBJECT_SCALAR; od->access = MIB_OBJECT_READ_ONLY; od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID); od->v_len = sysobjid_ptr->len * sizeof(s32_t); break; case 3: /* sysUpTime */ od->instance = MIB_OBJECT_SCALAR; od->access = MIB_OBJECT_READ_ONLY; od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_TIMETICKS); od->v_len = sizeof(u32_t); break; case 4: /* sysContact */ od->instance = MIB_OBJECT_SCALAR; od->access = MIB_OBJECT_READ_WRITE; od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR); od->v_len = *syscontact_len_ptr; break; case 5: /* sysName */ od->instance = MIB_OBJECT_SCALAR; od->access = MIB_OBJECT_READ_WRITE; od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR); od->v_len = *sysname_len_ptr; break; case 6: /* sysLocation */ od->instance = MIB_OBJECT_SCALAR; od->access = MIB_OBJECT_READ_WRITE; od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR); od->v_len = *syslocation_len_ptr; break; case 7: /* sysServices */ od->instance = MIB_OBJECT_SCALAR; od->access = MIB_OBJECT_READ_ONLY; od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG); od->v_len = sizeof(s32_t); break; default: LWIP_DEBUGF(SNMP_MIB_DEBUG,("system_get_object_def: no such object\n")); od->instance = MIB_OBJECT_NONE; break; }; } else { LWIP_DEBUGF(SNMP_MIB_DEBUG,("system_get_object_def: no scalar\n")); od->instance = MIB_OBJECT_NONE; } } /** * Returns system object value. * * @param ident_len the address length (2) * @param ident points to objectname.0 (object id trailer) * @param len return value space (in bytes) * @param value points to (varbind) space to copy value into. */ static void system_get_value(struct obj_def *od, u16_t len, void *value) { u8_t id; LWIP_ASSERT("invalid id", (od->id_inst_ptr[0] >= 0) && (od->id_inst_ptr[0] <= 0xff)); id = (u8_t)od->id_inst_ptr[0]; switch (id) { case 1: /* sysDescr */ MEMCPY(value, sysdescr_ptr, len); break; case 2: /* sysObjectID */ MEMCPY(value, sysobjid_ptr->id, len); break; case 3: /* sysUpTime */ { snmp_get_sysuptime((u32_t*)value); } break; case 4: /* sysContact */ MEMCPY(value, syscontact_ptr, len); break; case 5: /* sysName */ MEMCPY(value, sysname_ptr, len); break; case 6: /* sysLocation */ MEMCPY(value, syslocation_ptr, len); break; case 7: /* sysServices */ { s32_t *sint_ptr = (s32_t*)value; *sint_ptr = sysservices; } break; default: LWIP_DEBUGF(SNMP_MIB_DEBUG,("system_get_value(): unknown id: %d\n", id)); break; }; } static u8_t system_set_test(struct obj_def *od, u16_t len, void *value) { u8_t id, set_ok; LWIP_UNUSED_ARG(value); set_ok = 0; LWIP_ASSERT("invalid id", (od->id_inst_ptr[0] >= 0) && (od->id_inst_ptr[0] <= 0xff)); id = (u8_t)od->id_inst_ptr[0]; switch (id) { case 4: /* sysContact */ if ((syscontact_ptr != syscontact_default) && (len <= 255)) { set_ok = 1; } break; case 5: /* sysName */ if ((sysname_ptr != sysname_default) && (len <= 255)) { set_ok = 1; } break; case 6: /* sysLocation */ if ((syslocation_ptr != syslocation_default) && (len <= 255)) { set_ok = 1; } break; default: LWIP_DEBUGF(SNMP_MIB_DEBUG,("system_set_test(): unknown id: %d\n", id)); break; }; return set_ok; } static void system_set_value(struct obj_def *od, u16_t len, void *value) { u8_t id; LWIP_ASSERT("invalid len", len <= 0xff); LWIP_ASSERT("invalid id", (od->id_inst_ptr[0] >= 0) && (od->id_inst_ptr[0] <= 0xff)); id = (u8_t)od->id_inst_ptr[0]; switch (id) { case 4: /* sysContact */ MEMCPY(syscontact_ptr, value, len); *syscontact_len_ptr = (u8_t)len; break; case 5: /* sysName */ MEMCPY(sysname_ptr, value, len); *sysname_len_ptr = (u8_t)len; break; case 6: /* sysLocation */ MEMCPY(syslocation_ptr, value, len); *syslocation_len_ptr = (u8_t)len; break; default: LWIP_DEBUGF(SNMP_MIB_DEBUG,("system_set_value(): unknown id: %d\n", id)); break; }; } /** * Returns interfaces.ifnumber object definition. * * @param ident_len the address length (2) * @param ident points to objectname.index * @param od points to object definition. */ static void interfaces_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od) { /* return to object name, adding index depth (1) */ ident_len += 1; ident -= 1; if (ident_len == 2) { od->id_inst_len = ident_len; od->id_inst_ptr = ident; od->instance = MIB_OBJECT_SCALAR; od->access = MIB_OBJECT_READ_ONLY; od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG); od->v_len = sizeof(s32_t); } else { LWIP_DEBUGF(SNMP_MIB_DEBUG,("interfaces_get_object_def: no scalar\n")); od->instance = MIB_OBJECT_NONE; } } /** * Returns interfaces.ifnumber object value. * * @param ident_len the address length (2) * @param ident points to objectname.0 (object id trailer) * @param len return value space (in bytes) * @param value points to (varbind) space to copy value into. */ static void interfaces_get_value(struct obj_def *od, u16_t len, void *value) { LWIP_UNUSED_ARG(len); if (od->id_inst_ptr[0] == 1) { s32_t *sint_ptr = (s32_t*)value; *sint_ptr = iflist_root.count; } } /** * Returns ifentry object definitions. * * @param ident_len the address length (2) * @param ident points to objectname.index * @param od points to object definition. */ static void ifentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od) { u8_t id; /* return to object name, adding index depth (1) */ ident_len += 1; ident -= 1; if (ident_len == 2) { od->id_inst_len = ident_len; od->id_inst_ptr = ident; LWIP_ASSERT("invalid id", (ident[0] >= 0) && (ident[0] <= 0xff)); id = (u8_t)ident[0]; LWIP_DEBUGF(SNMP_MIB_DEBUG,("get_object_def ifentry.%"U16_F"\n",(u16_t)id)); switch (id) { case 1: /* ifIndex */ case 3: /* ifType */ case 4: /* ifMtu */ case 8: /* ifOperStatus */ od->instance = MIB_OBJECT_TAB; od->access = MIB_OBJECT_READ_ONLY; od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG); od->v_len = sizeof(s32_t); break; case 2: /* ifDescr */ od->instance = MIB_OBJECT_TAB; od->access = MIB_OBJECT_READ_ONLY; od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR); /** @todo this should be some sort of sizeof(struct netif.name) */ od->v_len = 2; break; case 5: /* ifSpeed */ case 21: /* ifOutQLen */ od->instance = MIB_OBJECT_TAB; od->access = MIB_OBJECT_READ_ONLY; od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_GAUGE); od->v_len = sizeof(u32_t); break; case 6: /* ifPhysAddress */ { struct netif *netif; snmp_ifindextonetif(ident[1], &netif); od->instance = MIB_OBJECT_TAB; od->access = MIB_OBJECT_READ_ONLY; od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR); od->v_len = netif->hwaddr_len; } break; case 7: /* ifAdminStatus */ od->instance = MIB_OBJECT_TAB; od->access = MIB_OBJECT_READ_WRITE; od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG); od->v_len = sizeof(s32_t); break; case 9: /* ifLastChange */ od->instance = MIB_OBJECT_TAB; od->access = MIB_OBJECT_READ_ONLY; od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_TIMETICKS); od->v_len = sizeof(u32_t); break; case 10: /* ifInOctets */ case 11: /* ifInUcastPkts */ case 12: /* ifInNUcastPkts */ case 13: /* ifInDiscarts */ case 14: /* ifInErrors */ case 15: /* ifInUnkownProtos */ case 16: /* ifOutOctets */ case 17: /* ifOutUcastPkts */ case 18: /* ifOutNUcastPkts */ case 19: /* ifOutDiscarts */ case 20: /* ifOutErrors */ od->instance = MIB_OBJECT_TAB; od->access = MIB_OBJECT_READ_ONLY; od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER); od->v_len = sizeof(u32_t); break; case 22: /* ifSpecific */ /** @note returning zeroDotZero (0.0) no media specific MIB support */ od->instance = MIB_OBJECT_TAB; od->access = MIB_OBJECT_READ_ONLY; od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID); od->v_len = ifspecific.len * sizeof(s32_t); break; default: LWIP_DEBUGF(SNMP_MIB_DEBUG,("ifentry_get_object_def: no such object\n")); od->instance = MIB_OBJECT_NONE; break; }; } else { LWIP_DEBUGF(SNMP_MIB_DEBUG,("ifentry_get_object_def: no scalar\n")); od->instance = MIB_OBJECT_NONE; } } /** * Returns ifentry object value. * * @param ident_len the address length (2) * @param ident points to objectname.0 (object id trailer) * @param len return value space (in bytes) * @param value points to (varbind) space to copy value into. */ static void ifentry_get_value(struct obj_def *od, u16_t len, void *value) { struct netif *netif; u8_t id; snmp_ifindextonetif(od->id_inst_ptr[1], &netif); LWIP_ASSERT("invalid id", (od->id_inst_ptr[0] >= 0) && (od->id_inst_ptr[0] <= 0xff)); id = (u8_t)od->id_inst_ptr[0]; switch (id) { case 1: /* ifIndex */ { s32_t *sint_ptr = (s32_t*)value; *sint_ptr = od->id_inst_ptr[1]; } break; case 2: /* ifDescr */ MEMCPY(value, netif->name, len); break; case 3: /* ifType */ { s32_t *sint_ptr = (s32_t*)value; *sint_ptr = netif->link_type; } break; case 4: /* ifMtu */ { s32_t *sint_ptr = (s32_t*)value; *sint_ptr = netif->mtu; } break; case 5: /* ifSpeed */ { u32_t *uint_ptr = (u32_t*)value; *uint_ptr = netif->link_speed; } break; case 6: /* ifPhysAddress */ MEMCPY(value, netif->hwaddr, len); break; case 7: /* ifAdminStatus */ { s32_t *sint_ptr = (s32_t*)value; if (netif_is_up(netif)) { if (netif_is_link_up(netif)) { *sint_ptr = 1; /* up */ } else { *sint_ptr = 7; /* lowerLayerDown */ } } else { *sint_ptr = 2; /* down */ } } break; case 8: /* ifOperStatus */ { s32_t *sint_ptr = (s32_t*)value; if (netif_is_up(netif)) { *sint_ptr = 1; } else { *sint_ptr = 2; } } break; case 9: /* ifLastChange */ { u32_t *uint_ptr = (u32_t*)value; *uint_ptr = netif->ts; } break; case 10: /* ifInOctets */ { u32_t *uint_ptr = (u32_t*)value; *uint_ptr = netif->ifinoctets; } break; case 11: /* ifInUcastPkts */ { u32_t *uint_ptr = (u32_t*)value; *uint_ptr = netif->ifinucastpkts; } break; case 12: /* ifInNUcastPkts */ { u32_t *uint_ptr = (u32_t*)value; *uint_ptr = netif->ifinnucastpkts; } break; case 13: /* ifInDiscarts */ { u32_t *uint_ptr = (u32_t*)value; *uint_ptr = netif->ifindiscards; } break; case 14: /* ifInErrors */ case 15: /* ifInUnkownProtos */ /** @todo add these counters! */ { u32_t *uint_ptr = (u32_t*)value; *uint_ptr = 0; } break; case 16: /* ifOutOctets */ { u32_t *uint_ptr = (u32_t*)value; *uint_ptr = netif->ifoutoctets; } break; case 17: /* ifOutUcastPkts */ { u32_t *uint_ptr = (u32_t*)value; *uint_ptr = netif->ifoutucastpkts; } break; case 18: /* ifOutNUcastPkts */ { u32_t *uint_ptr = (u32_t*)value; *uint_ptr = netif->ifoutnucastpkts; } break; case 19: /* ifOutDiscarts */ { u32_t *uint_ptr = (u32_t*)value; *uint_ptr = netif->ifoutdiscards; } break; case 20: /* ifOutErrors */ /** @todo add this counter! */ { u32_t *uint_ptr = (u32_t*)value; *uint_ptr = 0; } break; case 21: /* ifOutQLen */ /** @todo figure out if this must be 0 (no queue) or 1? */ { u32_t *uint_ptr = (u32_t*)value; *uint_ptr = 0; } break; case 22: /* ifSpecific */ MEMCPY(value, ifspecific.id, len); break; default: LWIP_DEBUGF(SNMP_MIB_DEBUG,("ifentry_get_value(): unknown id: %d\n", id)); break; }; } #if !SNMP_SAFE_REQUESTS static u8_t ifentry_set_test(struct obj_def *od, u16_t len, void *value) { struct netif *netif; u8_t id, set_ok; LWIP_UNUSED_ARG(len); set_ok = 0; snmp_ifindextonetif(od->id_inst_ptr[1], &netif); id = (u8_t)od->id_inst_ptr[0]; switch (id) { case 7: /* ifAdminStatus */ { s32_t *sint_ptr = (s32_t*)value; if (*sint_ptr == 1 || *sint_ptr == 2) set_ok = 1; } break; } return set_ok; } static void ifentry_set_value(struct obj_def *od, u16_t len, void *value) { struct netif *netif; u8_t id; LWIP_UNUSED_ARG(len); snmp_ifindextonetif(od->id_inst_ptr[1], &netif); id = (u8_t)od->id_inst_ptr[0]; switch (id) { case 7: /* ifAdminStatus */ { s32_t *sint_ptr = (s32_t*)value; if (*sint_ptr == 1) { netif_set_up(netif); } else if (*sint_ptr == 2) { netif_set_down(netif); } } break; } } #endif /* SNMP_SAFE_REQUESTS */ /** * Returns atentry object definitions. * * @param ident_len the address length (6) * @param ident points to objectname.atifindex.atnetaddress * @param od points to object definition. */ static void atentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od) { /* return to object name, adding index depth (5) */ ident_len += 5; ident -= 5; if (ident_len == 6) { od->id_inst_len = ident_len; od->id_inst_ptr = ident; switch (ident[0]) { case 1: /* atIfIndex */ od->instance = MIB_OBJECT_TAB; od->access = MIB_OBJECT_READ_WRITE; od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG); od->v_len = sizeof(s32_t); break; case 2: /* atPhysAddress */ od->instance = MIB_OBJECT_TAB; od->access = MIB_OBJECT_READ_WRITE; od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR); od->v_len = 6; /** @todo try to use netif::hwaddr_len */ break; case 3: /* atNetAddress */ od->instance = MIB_OBJECT_TAB; od->access = MIB_OBJECT_READ_WRITE; od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR); od->v_len = 4; break; default: LWIP_DEBUGF(SNMP_MIB_DEBUG,("atentry_get_object_def: no such object\n")); od->instance = MIB_OBJECT_NONE; break; } } else { LWIP_DEBUGF(SNMP_MIB_DEBUG,("atentry_get_object_def: no scalar\n")); od->instance = MIB_OBJECT_NONE; } } static void atentry_get_value(struct obj_def *od, u16_t len, void *value) { #if LWIP_ARP u8_t id; struct eth_addr* ethaddr_ret; ip_addr_t* ipaddr_ret; #endif /* LWIP_ARP */ ip_addr_t ip; struct netif *netif; LWIP_UNUSED_ARG(len); LWIP_UNUSED_ARG(value);/* if !LWIP_ARP */ snmp_ifindextonetif(od->id_inst_ptr[1], &netif); snmp_oidtoip(&od->id_inst_ptr[2], &ip); #if LWIP_ARP /** @todo implement a netif_find_addr */ if (etharp_find_addr(netif, &ip, ðaddr_ret, &ipaddr_ret) > -1) { LWIP_ASSERT("invalid id", (od->id_inst_ptr[0] >= 0) && (od->id_inst_ptr[0] <= 0xff)); id = (u8_t)od->id_inst_ptr[0]; switch (id) { case 1: /* atIfIndex */ { s32_t *sint_ptr = (s32_t*)value; *sint_ptr = od->id_inst_ptr[1]; } break; case 2: /* atPhysAddress */ { struct eth_addr *dst = (struct eth_addr*)value; *dst = *ethaddr_ret; } break; case 3: /* atNetAddress */ { ip_addr_t *dst = (ip_addr_t*)value; *dst = *ipaddr_ret; } break; default: LWIP_DEBUGF(SNMP_MIB_DEBUG,("atentry_get_value(): unknown id: %d\n", id)); break; } } #endif /* LWIP_ARP */ } static void ip_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od) { u8_t id; /* return to object name, adding index depth (1) */ ident_len += 1; ident -= 1; if (ident_len == 2) { od->id_inst_len = ident_len; od->id_inst_ptr = ident; LWIP_ASSERT("invalid id", (ident[0] >= 0) && (ident[0] <= 0xff)); id = (u8_t)ident[0]; LWIP_DEBUGF(SNMP_MIB_DEBUG,("get_object_def ip.%"U16_F".0\n",(u16_t)id)); switch (id) { case 1: /* ipForwarding */ case 2: /* ipDefaultTTL */ od->instance = MIB_OBJECT_SCALAR; od->access = MIB_OBJECT_READ_WRITE; od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG); od->v_len = sizeof(s32_t); break; case 3: /* ipInReceives */ case 4: /* ipInHdrErrors */ case 5: /* ipInAddrErrors */ case 6: /* ipForwDatagrams */ case 7: /* ipInUnknownProtos */ case 8: /* ipInDiscards */ case 9: /* ipInDelivers */ case 10: /* ipOutRequests */ case 11: /* ipOutDiscards */ case 12: /* ipOutNoRoutes */ case 14: /* ipReasmReqds */ case 15: /* ipReasmOKs */ case 16: /* ipReasmFails */ case 17: /* ipFragOKs */ case 18: /* ipFragFails */ case 19: /* ipFragCreates */ case 23: /* ipRoutingDiscards */ od->instance = MIB_OBJECT_SCALAR; od->access = MIB_OBJECT_READ_ONLY; od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER); od->v_len = sizeof(u32_t); break; case 13: /* ipReasmTimeout */ od->instance = MIB_OBJECT_SCALAR; od->access = MIB_OBJECT_READ_ONLY; od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG); od->v_len = sizeof(s32_t); break; default: LWIP_DEBUGF(SNMP_MIB_DEBUG,("ip_get_object_def: no such object\n")); od->instance = MIB_OBJECT_NONE; break; }; } else { LWIP_DEBUGF(SNMP_MIB_DEBUG,("ip_get_object_def: no scalar\n")); od->instance = MIB_OBJECT_NONE; } } static void ip_get_value(struct obj_def *od, u16_t len, void *value) { u8_t id; LWIP_UNUSED_ARG(len); LWIP_ASSERT("invalid id", (od->id_inst_ptr[0] >= 0) && (od->id_inst_ptr[0] <= 0xff)); id = (u8_t)od->id_inst_ptr[0]; switch (id) { case 1: /* ipForwarding */ { s32_t *sint_ptr = (s32_t*)value; #if IP_FORWARD /* forwarding */ *sint_ptr = 1; #else /* not-forwarding */ *sint_ptr = 2; #endif } break; case 2: /* ipDefaultTTL */ { s32_t *sint_ptr = (s32_t*)value; *sint_ptr = IP_DEFAULT_TTL; } break; case 3: /* ipInReceives */ { u32_t *uint_ptr = (u32_t*)value; *uint_ptr = ipinreceives; } break; case 4: /* ipInHdrErrors */ { u32_t *uint_ptr = (u32_t*)value; *uint_ptr = ipinhdrerrors; } break; case 5: /* ipInAddrErrors */ { u32_t *uint_ptr = (u32_t*)value; *uint_ptr = ipinaddrerrors; } break; case 6: /* ipForwDatagrams */ { u32_t *uint_ptr = (u32_t*)value; *uint_ptr = ipforwdatagrams; } break; case 7: /* ipInUnknownProtos */ { u32_t *uint_ptr = (u32_t*)value; *uint_ptr = ipinunknownprotos; } break; case 8: /* ipInDiscards */ { u32_t *uint_ptr = (u32_t*)value; *uint_ptr = ipindiscards; } break; case 9: /* ipInDelivers */ { u32_t *uint_ptr = (u32_t*)value; *uint_ptr = ipindelivers; } break; case 10: /* ipOutRequests */ { u32_t *uint_ptr = (u32_t*)value; *uint_ptr = ipoutrequests; } break; case 11: /* ipOutDiscards */ { u32_t *uint_ptr = (u32_t*)value; *uint_ptr = ipoutdiscards; } break; case 12: /* ipOutNoRoutes */ { u32_t *uint_ptr = (u32_t*)value; *uint_ptr = ipoutnoroutes; } break; case 13: /* ipReasmTimeout */ { s32_t *sint_ptr = (s32_t*)value; #if IP_REASSEMBLY *sint_ptr = IP_REASS_MAXAGE; #else *sint_ptr = 0; #endif } break; case 14: /* ipReasmReqds */ { u32_t *uint_ptr = (u32_t*)value; *uint_ptr = ipreasmreqds; } break; case 15: /* ipReasmOKs */ { u32_t *uint_ptr = (u32_t*)value; *uint_ptr = ipreasmoks; } break; case 16: /* ipReasmFails */ { u32_t *uint_ptr = (u32_t*)value; *uint_ptr = ipreasmfails; } break; case 17: /* ipFragOKs */ { u32_t *uint_ptr = (u32_t*)value; *uint_ptr = ipfragoks; } break; case 18: /* ipFragFails */ { u32_t *uint_ptr = (u32_t*)value; *uint_ptr = ipfragfails; } break; case 19: /* ipFragCreates */ { u32_t *uint_ptr = (u32_t*)value; *uint_ptr = ipfragcreates; } break; case 23: /* ipRoutingDiscards */ /** @todo can lwIP discard routes at all?? hardwire this to 0?? */ { u32_t *uint_ptr = (u32_t*)value; *uint_ptr = iproutingdiscards; } break; default: LWIP_DEBUGF(SNMP_MIB_DEBUG,("ip_get_value(): unknown id: %d\n", id)); break; }; } /** * Test ip object value before setting. * * @param od is the object definition * @param len return value space (in bytes) * @param value points to (varbind) space to copy value from. * * @note we allow set if the value matches the hardwired value, * otherwise return badvalue. */ static u8_t ip_set_test(struct obj_def *od, u16_t len, void *value) { u8_t id, set_ok; s32_t *sint_ptr = (s32_t*)value; LWIP_UNUSED_ARG(len); set_ok = 0; LWIP_ASSERT("invalid id", (od->id_inst_ptr[0] >= 0) && (od->id_inst_ptr[0] <= 0xff)); id = (u8_t)od->id_inst_ptr[0]; switch (id) { case 1: /* ipForwarding */ #if IP_FORWARD /* forwarding */ if (*sint_ptr == 1) #else /* not-forwarding */ if (*sint_ptr == 2) #endif { set_ok = 1; } break; case 2: /* ipDefaultTTL */ if (*sint_ptr == IP_DEFAULT_TTL) { set_ok = 1; } break; default: LWIP_DEBUGF(SNMP_MIB_DEBUG,("ip_set_test(): unknown id: %d\n", id)); break; }; return set_ok; } static void ip_addrentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od) { /* return to object name, adding index depth (4) */ ident_len += 4; ident -= 4; if (ident_len == 5) { u8_t id; od->id_inst_len = ident_len; od->id_inst_ptr = ident; LWIP_ASSERT("invalid id", (ident[0] >= 0) && (ident[0] <= 0xff)); id = (u8_t)ident[0]; switch (id) { case 1: /* ipAdEntAddr */ case 3: /* ipAdEntNetMask */ od->instance = MIB_OBJECT_TAB; od->access = MIB_OBJECT_READ_ONLY; od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR); od->v_len = 4; break; case 2: /* ipAdEntIfIndex */ case 4: /* ipAdEntBcastAddr */ case 5: /* ipAdEntReasmMaxSize */ od->instance = MIB_OBJECT_TAB; od->access = MIB_OBJECT_READ_ONLY; od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG); od->v_len = sizeof(s32_t); break; default: LWIP_DEBUGF(SNMP_MIB_DEBUG,("ip_addrentry_get_object_def: no such object\n")); od->instance = MIB_OBJECT_NONE; break; } } else { LWIP_DEBUGF(SNMP_MIB_DEBUG,("ip_addrentry_get_object_def: no scalar\n")); od->instance = MIB_OBJECT_NONE; } } static void ip_addrentry_get_value(struct obj_def *od, u16_t len, void *value) { u8_t id; u16_t ifidx; ip_addr_t ip; struct netif *netif = netif_list; LWIP_UNUSED_ARG(len); snmp_oidtoip(&od->id_inst_ptr[1], &ip); ifidx = 0; while ((netif != NULL) && !ip_addr_cmp(&ip, &netif->ip_addr)) { netif = netif->next; ifidx++; } if (netif != NULL) { LWIP_ASSERT("invalid id", (od->id_inst_ptr[0] >= 0) && (od->id_inst_ptr[0] <= 0xff)); id = (u8_t)od->id_inst_ptr[0]; switch (id) { case 1: /* ipAdEntAddr */ { ip_addr_t *dst = (ip_addr_t*)value; *dst = netif->ip_addr; } break; case 2: /* ipAdEntIfIndex */ { s32_t *sint_ptr = (s32_t*)value; *sint_ptr = ifidx + 1; } break; case 3: /* ipAdEntNetMask */ { ip_addr_t *dst = (ip_addr_t*)value; *dst = netif->netmask; } break; case 4: /* ipAdEntBcastAddr */ { s32_t *sint_ptr = (s32_t*)value; /* lwIP oddity, there's no broadcast address in the netif we can rely on */ *sint_ptr = IPADDR_BROADCAST & 1; } break; case 5: /* ipAdEntReasmMaxSize */ { s32_t *sint_ptr = (s32_t*)value; #if IP_REASSEMBLY /* @todo The theoretical maximum is IP_REASS_MAX_PBUFS * size of the pbufs, * but only if receiving one fragmented packet at a time. * The current solution is to calculate for 2 simultaneous packets... */ *sint_ptr = (IP_HLEN + ((IP_REASS_MAX_PBUFS/2) * (PBUF_POOL_BUFSIZE - PBUF_LINK_HLEN - IP_HLEN))); #else /** @todo returning MTU would be a bad thing and returning a wild guess like '576' isn't good either */ *sint_ptr = 0; #endif } break; default: LWIP_DEBUGF(SNMP_MIB_DEBUG,("ip_addrentry_get_value(): unknown id: %d\n", id)); break; } } } /** * @note * lwIP IP routing is currently using the network addresses in netif_list. * if no suitable network IP is found in netif_list, the default_netif is used. */ static void ip_rteentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od) { u8_t id; /* return to object name, adding index depth (4) */ ident_len += 4; ident -= 4; if (ident_len == 5) { od->id_inst_len = ident_len; od->id_inst_ptr = ident; LWIP_ASSERT("invalid id", (ident[0] >= 0) && (ident[0] <= 0xff)); id = (u8_t)ident[0]; switch (id) { case 1: /* ipRouteDest */ case 7: /* ipRouteNextHop */ case 11: /* ipRouteMask */ od->instance = MIB_OBJECT_TAB; od->access = MIB_OBJECT_READ_WRITE; od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR); od->v_len = 4; break; case 2: /* ipRouteIfIndex */ case 3: /* ipRouteMetric1 */ case 4: /* ipRouteMetric2 */ case 5: /* ipRouteMetric3 */ case 6: /* ipRouteMetric4 */ case 8: /* ipRouteType */ case 10: /* ipRouteAge */ case 12: /* ipRouteMetric5 */ od->instance = MIB_OBJECT_TAB; od->access = MIB_OBJECT_READ_WRITE; od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG); od->v_len = sizeof(s32_t); break; case 9: /* ipRouteProto */ od->instance = MIB_OBJECT_TAB; od->access = MIB_OBJECT_READ_ONLY; od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG); od->v_len = sizeof(s32_t); break; case 13: /* ipRouteInfo */ /** @note returning zeroDotZero (0.0) no routing protocol specific MIB */ od->instance = MIB_OBJECT_TAB; od->access = MIB_OBJECT_READ_ONLY; od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID); od->v_len = iprouteinfo.len * sizeof(s32_t); break; default: LWIP_DEBUGF(SNMP_MIB_DEBUG,("ip_rteentry_get_object_def: no such object\n")); od->instance = MIB_OBJECT_NONE; break; } } else { LWIP_DEBUGF(SNMP_MIB_DEBUG,("ip_rteentry_get_object_def: no scalar\n")); od->instance = MIB_OBJECT_NONE; } } static void ip_rteentry_get_value(struct obj_def *od, u16_t len, void *value) { struct netif *netif; ip_addr_t dest; s32_t *ident; u8_t id; ident = od->id_inst_ptr; snmp_oidtoip(&ident[1], &dest); if (ip_addr_isany(&dest)) { /* ip_route() uses default netif for default route */ netif = netif_default; } else { /* not using ip_route(), need exact match! */ netif = netif_list; while ((netif != NULL) && !ip_addr_netcmp(&dest, &(netif->ip_addr), &(netif->netmask)) ) { netif = netif->next; } } if (netif != NULL) { LWIP_ASSERT("invalid id", (ident[0] >= 0) && (ident[0] <= 0xff)); id = (u8_t)ident[0]; switch (id) { case 1: /* ipRouteDest */ { ip_addr_t *dst = (ip_addr_t*)value; if (ip_addr_isany(&dest)) { /* default rte has 0.0.0.0 dest */ ip_addr_set_zero(dst); } else { /* netifs have netaddress dest */ ip_addr_get_network(dst, &netif->ip_addr, &netif->netmask); } } break; case 2: /* ipRouteIfIndex */ { s32_t *sint_ptr = (s32_t*)value; snmp_netiftoifindex(netif, sint_ptr); } break; case 3: /* ipRouteMetric1 */ { s32_t *sint_ptr = (s32_t*)value; if (ip_addr_isany(&dest)) { /* default rte has metric 1 */ *sint_ptr = 1; } else { /* other rtes have metric 0 */ *sint_ptr = 0; } } break; case 4: /* ipRouteMetric2 */ case 5: /* ipRouteMetric3 */ case 6: /* ipRouteMetric4 */ case 12: /* ipRouteMetric5 */ { s32_t *sint_ptr = (s32_t*)value; /* not used */ *sint_ptr = -1; } break; case 7: /* ipRouteNextHop */ { ip_addr_t *dst = (ip_addr_t*)value; if (ip_addr_isany(&dest)) { /* default rte: gateway */ *dst = netif->gw; } else { /* other rtes: netif ip_addr */ *dst = netif->ip_addr; } } break; case 8: /* ipRouteType */ { s32_t *sint_ptr = (s32_t*)value; if (ip_addr_isany(&dest)) { /* default rte is indirect */ *sint_ptr = 4; } else { /* other rtes are direct */ *sint_ptr = 3; } } break; case 9: /* ipRouteProto */ { s32_t *sint_ptr = (s32_t*)value; /* locally defined routes */ *sint_ptr = 2; } break; case 10: /* ipRouteAge */ { s32_t *sint_ptr = (s32_t*)value; /** @todo (sysuptime - timestamp last change) / 100 @see snmp_insert_iprteidx_tree() */ *sint_ptr = 0; } break; case 11: /* ipRouteMask */ { ip_addr_t *dst = (ip_addr_t*)value; if (ip_addr_isany(&dest)) { /* default rte use 0.0.0.0 mask */ ip_addr_set_zero(dst); } else { /* other rtes use netmask */ *dst = netif->netmask; } } break; case 13: /* ipRouteInfo */ MEMCPY(value, iprouteinfo.id, len); break; default: LWIP_DEBUGF(SNMP_MIB_DEBUG,("ip_rteentry_get_value(): unknown id: %d\n", id)); break; } } } static void ip_ntomentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od) { /* return to object name, adding index depth (5) */ ident_len += 5; ident -= 5; if (ident_len == 6) { u8_t id; od->id_inst_len = ident_len; od->id_inst_ptr = ident; LWIP_ASSERT("invalid id", (ident[0] >= 0) && (ident[0] <= 0xff)); id = (u8_t)ident[0]; switch (id) { case 1: /* ipNetToMediaIfIndex */ case 4: /* ipNetToMediaType */ od->instance = MIB_OBJECT_TAB; od->access = MIB_OBJECT_READ_WRITE; od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG); od->v_len = sizeof(s32_t); break; case 2: /* ipNetToMediaPhysAddress */ od->instance = MIB_OBJECT_TAB; od->access = MIB_OBJECT_READ_WRITE; od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR); od->v_len = 6; /** @todo try to use netif::hwaddr_len */ break; case 3: /* ipNetToMediaNetAddress */ od->instance = MIB_OBJECT_TAB; od->access = MIB_OBJECT_READ_WRITE; od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR); od->v_len = 4; break; default: LWIP_DEBUGF(SNMP_MIB_DEBUG,("ip_ntomentry_get_object_def: no such object\n")); od->instance = MIB_OBJECT_NONE; break; } } else { LWIP_DEBUGF(SNMP_MIB_DEBUG,("ip_ntomentry_get_object_def: no scalar\n")); od->instance = MIB_OBJECT_NONE; } } static void ip_ntomentry_get_value(struct obj_def *od, u16_t len, void *value) { #if LWIP_ARP u8_t id; struct eth_addr* ethaddr_ret; ip_addr_t* ipaddr_ret; #endif /* LWIP_ARP */ ip_addr_t ip; struct netif *netif; LWIP_UNUSED_ARG(len); LWIP_UNUSED_ARG(value);/* if !LWIP_ARP */ snmp_ifindextonetif(od->id_inst_ptr[1], &netif); snmp_oidtoip(&od->id_inst_ptr[2], &ip); #if LWIP_ARP /** @todo implement a netif_find_addr */ if (etharp_find_addr(netif, &ip, ðaddr_ret, &ipaddr_ret) > -1) { LWIP_ASSERT("invalid id", (od->id_inst_ptr[0] >= 0) && (od->id_inst_ptr[0] <= 0xff)); id = (u8_t)od->id_inst_ptr[0]; switch (id) { case 1: /* ipNetToMediaIfIndex */ { s32_t *sint_ptr = (s32_t*)value; *sint_ptr = od->id_inst_ptr[1]; } break; case 2: /* ipNetToMediaPhysAddress */ { struct eth_addr *dst = (struct eth_addr*)value; *dst = *ethaddr_ret; } break; case 3: /* ipNetToMediaNetAddress */ { ip_addr_t *dst = (ip_addr_t*)value; *dst = *ipaddr_ret; } break; case 4: /* ipNetToMediaType */ { s32_t *sint_ptr = (s32_t*)value; /* dynamic (?) */ *sint_ptr = 3; } break; default: LWIP_DEBUGF(SNMP_MIB_DEBUG,("ip_ntomentry_get_value(): unknown id: %d\n", id)); break; } } #endif /* LWIP_ARP */ } static void icmp_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od) { /* return to object name, adding index depth (1) */ ident_len += 1; ident -= 1; if ((ident_len == 2) && (ident[0] > 0) && (ident[0] < 27)) { od->id_inst_len = ident_len; od->id_inst_ptr = ident; od->instance = MIB_OBJECT_SCALAR; od->access = MIB_OBJECT_READ_ONLY; od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER); od->v_len = sizeof(u32_t); } else { LWIP_DEBUGF(SNMP_MIB_DEBUG,("icmp_get_object_def: no scalar\n")); od->instance = MIB_OBJECT_NONE; } } static void icmp_get_value(struct obj_def *od, u16_t len, void *value) { u32_t *uint_ptr = (u32_t*)value; u8_t id; LWIP_UNUSED_ARG(len); LWIP_ASSERT("invalid id", (od->id_inst_ptr[0] >= 0) && (od->id_inst_ptr[0] <= 0xff)); id = (u8_t)od->id_inst_ptr[0]; switch (id) { case 1: /* icmpInMsgs */ *uint_ptr = icmpinmsgs; break; case 2: /* icmpInErrors */ *uint_ptr = icmpinerrors; break; case 3: /* icmpInDestUnreachs */ *uint_ptr = icmpindestunreachs; break; case 4: /* icmpInTimeExcds */ *uint_ptr = icmpintimeexcds; break; case 5: /* icmpInParmProbs */ *uint_ptr = icmpinparmprobs; break; case 6: /* icmpInSrcQuenchs */ *uint_ptr = icmpinsrcquenchs; break; case 7: /* icmpInRedirects */ *uint_ptr = icmpinredirects; break; case 8: /* icmpInEchos */ *uint_ptr = icmpinechos; break; case 9: /* icmpInEchoReps */ *uint_ptr = icmpinechoreps; break; case 10: /* icmpInTimestamps */ *uint_ptr = icmpintimestamps; break; case 11: /* icmpInTimestampReps */ *uint_ptr = icmpintimestampreps; break; case 12: /* icmpInAddrMasks */ *uint_ptr = icmpinaddrmasks; break; case 13: /* icmpInAddrMaskReps */ *uint_ptr = icmpinaddrmaskreps; break; case 14: /* icmpOutMsgs */ *uint_ptr = icmpoutmsgs; break; case 15: /* icmpOutErrors */ *uint_ptr = icmpouterrors; break; case 16: /* icmpOutDestUnreachs */ *uint_ptr = icmpoutdestunreachs; break; case 17: /* icmpOutTimeExcds */ *uint_ptr = icmpouttimeexcds; break; case 18: /* icmpOutParmProbs */ *uint_ptr = icmpoutparmprobs; break; case 19: /* icmpOutSrcQuenchs */ *uint_ptr = icmpoutsrcquenchs; break; case 20: /* icmpOutRedirects */ *uint_ptr = icmpoutredirects; break; case 21: /* icmpOutEchos */ *uint_ptr = icmpoutechos; break; case 22: /* icmpOutEchoReps */ *uint_ptr = icmpoutechoreps; break; case 23: /* icmpOutTimestamps */ *uint_ptr = icmpouttimestamps; break; case 24: /* icmpOutTimestampReps */ *uint_ptr = icmpouttimestampreps; break; case 25: /* icmpOutAddrMasks */ *uint_ptr = icmpoutaddrmasks; break; case 26: /* icmpOutAddrMaskReps */ *uint_ptr = icmpoutaddrmaskreps; break; default: LWIP_DEBUGF(SNMP_MIB_DEBUG,("icmp_get_value(): unknown id: %d\n", id)); break; } } #if LWIP_TCP /** @todo tcp grp */ static void tcp_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od) { u8_t id; /* return to object name, adding index depth (1) */ ident_len += 1; ident -= 1; if (ident_len == 2) { od->id_inst_len = ident_len; od->id_inst_ptr = ident; LWIP_ASSERT("invalid id", (ident[0] >= 0) && (ident[0] <= 0xff)); id = (u8_t)ident[0]; LWIP_DEBUGF(SNMP_MIB_DEBUG,("get_object_def tcp.%"U16_F".0\n",(u16_t)id)); switch (id) { case 1: /* tcpRtoAlgorithm */ case 2: /* tcpRtoMin */ case 3: /* tcpRtoMax */ case 4: /* tcpMaxConn */ od->instance = MIB_OBJECT_SCALAR; od->access = MIB_OBJECT_READ_ONLY; od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG); od->v_len = sizeof(s32_t); break; case 5: /* tcpActiveOpens */ case 6: /* tcpPassiveOpens */ case 7: /* tcpAttemptFails */ case 8: /* tcpEstabResets */ case 10: /* tcpInSegs */ case 11: /* tcpOutSegs */ case 12: /* tcpRetransSegs */ case 14: /* tcpInErrs */ case 15: /* tcpOutRsts */ od->instance = MIB_OBJECT_SCALAR; od->access = MIB_OBJECT_READ_ONLY; od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER); od->v_len = sizeof(u32_t); break; case 9: /* tcpCurrEstab */ od->instance = MIB_OBJECT_TAB; od->access = MIB_OBJECT_READ_ONLY; od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_GAUGE); od->v_len = sizeof(u32_t); break; default: LWIP_DEBUGF(SNMP_MIB_DEBUG,("tcp_get_object_def: no such object\n")); od->instance = MIB_OBJECT_NONE; break; }; } else { LWIP_DEBUGF(SNMP_MIB_DEBUG,("tcp_get_object_def: no scalar\n")); od->instance = MIB_OBJECT_NONE; } } static void tcp_get_value(struct obj_def *od, u16_t len, void *value) { u32_t *uint_ptr = (u32_t*)value; s32_t *sint_ptr = (s32_t*)value; u8_t id; LWIP_UNUSED_ARG(len); LWIP_ASSERT("invalid id", (od->id_inst_ptr[0] >= 0) && (od->id_inst_ptr[0] <= 0xff)); id = (u8_t)od->id_inst_ptr[0]; switch (id) { case 1: /* tcpRtoAlgorithm, vanj(4) */ *sint_ptr = 4; break; case 2: /* tcpRtoMin */ /* @todo not the actual value, a guess, needs to be calculated */ *sint_ptr = 1000; break; case 3: /* tcpRtoMax */ /* @todo not the actual value, a guess, needs to be calculated */ *sint_ptr = 60000; break; case 4: /* tcpMaxConn */ *sint_ptr = MEMP_NUM_TCP_PCB; break; case 5: /* tcpActiveOpens */ *uint_ptr = tcpactiveopens; break; case 6: /* tcpPassiveOpens */ *uint_ptr = tcppassiveopens; break; case 7: /* tcpAttemptFails */ *uint_ptr = tcpattemptfails; break; case 8: /* tcpEstabResets */ *uint_ptr = tcpestabresets; break; case 9: /* tcpCurrEstab */ { u16_t tcpcurrestab = 0; struct tcp_pcb *pcb = tcp_active_pcbs; while (pcb != NULL) { if ((pcb->state == ESTABLISHED) || (pcb->state == CLOSE_WAIT)) { tcpcurrestab++; } pcb = pcb->next; } *uint_ptr = tcpcurrestab; } break; case 10: /* tcpInSegs */ *uint_ptr = tcpinsegs; break; case 11: /* tcpOutSegs */ *uint_ptr = tcpoutsegs; break; case 12: /* tcpRetransSegs */ *uint_ptr = tcpretranssegs; break; case 14: /* tcpInErrs */ *uint_ptr = tcpinerrs; break; case 15: /* tcpOutRsts */ *uint_ptr = tcpoutrsts; break; default: LWIP_DEBUGF(SNMP_MIB_DEBUG,("tcp_get_value(): unknown id: %d\n", id)); break; } } #ifdef THIS_SEEMS_UNUSED static void tcpconnentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od) { /* return to object name, adding index depth (10) */ ident_len += 10; ident -= 10; if (ident_len == 11) { u8_t id; od->id_inst_len = ident_len; od->id_inst_ptr = ident; id = ident[0]; LWIP_DEBUGF(SNMP_MIB_DEBUG,("get_object_def tcp.%"U16_F".0\n",(u16_t)id)); switch (id) { case 1: /* tcpConnState */ od->instance = MIB_OBJECT_TAB; od->access = MIB_OBJECT_READ_WRITE; od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG); od->v_len = sizeof(s32_t); break; case 2: /* tcpConnLocalAddress */ case 4: /* tcpConnRemAddress */ od->instance = MIB_OBJECT_TAB; od->access = MIB_OBJECT_READ_ONLY; od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR); od->v_len = 4; break; case 3: /* tcpConnLocalPort */ case 5: /* tcpConnRemPort */ od->instance = MIB_OBJECT_TAB; od->access = MIB_OBJECT_READ_ONLY; od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG); od->v_len = sizeof(s32_t); break; default: LWIP_DEBUGF(SNMP_MIB_DEBUG,("tcpconnentry_get_object_def: no such object\n")); od->instance = MIB_OBJECT_NONE; break; }; } else { LWIP_DEBUGF(SNMP_MIB_DEBUG,("tcpconnentry_get_object_def: no such object\n")); od->instance = MIB_OBJECT_NONE; } } static void tcpconnentry_get_value(struct obj_def *od, u16_t len, void *value) { ip_addr_t lip, rip; u16_t lport, rport; s32_t *ident; ident = od->id_inst_ptr; snmp_oidtoip(&ident[1], &lip); lport = ident[5]; snmp_oidtoip(&ident[6], &rip); rport = ident[10]; /** @todo find matching PCB */ } #endif /* if 0 */ #endif static void udp_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od) { /* return to object name, adding index depth (1) */ ident_len += 1; ident -= 1; if ((ident_len == 2) && (ident[0] > 0) && (ident[0] < 6)) { od->id_inst_len = ident_len; od->id_inst_ptr = ident; od->instance = MIB_OBJECT_SCALAR; od->access = MIB_OBJECT_READ_ONLY; od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER); od->v_len = sizeof(u32_t); } else { LWIP_DEBUGF(SNMP_MIB_DEBUG,("udp_get_object_def: no scalar\n")); od->instance = MIB_OBJECT_NONE; } } static void udp_get_value(struct obj_def *od, u16_t len, void *value) { u32_t *uint_ptr = (u32_t*)value; u8_t id; LWIP_UNUSED_ARG(len); LWIP_ASSERT("invalid id", (od->id_inst_ptr[0] >= 0) && (od->id_inst_ptr[0] <= 0xff)); id = (u8_t)od->id_inst_ptr[0]; switch (id) { case 1: /* udpInDatagrams */ *uint_ptr = udpindatagrams; break; case 2: /* udpNoPorts */ *uint_ptr = udpnoports; break; case 3: /* udpInErrors */ *uint_ptr = udpinerrors; break; case 4: /* udpOutDatagrams */ *uint_ptr = udpoutdatagrams; break; default: LWIP_DEBUGF(SNMP_MIB_DEBUG,("udp_get_value(): unknown id: %d\n", id)); break; } } static void udpentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od) { /* return to object name, adding index depth (5) */ ident_len += 5; ident -= 5; if (ident_len == 6) { od->id_inst_len = ident_len; od->id_inst_ptr = ident; switch (ident[0]) { case 1: /* udpLocalAddress */ od->instance = MIB_OBJECT_TAB; od->access = MIB_OBJECT_READ_ONLY; od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR); od->v_len = 4; break; case 2: /* udpLocalPort */ od->instance = MIB_OBJECT_TAB; od->access = MIB_OBJECT_READ_ONLY; od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG); od->v_len = sizeof(s32_t); break; default: LWIP_DEBUGF(SNMP_MIB_DEBUG,("udpentry_get_object_def: no such object\n")); od->instance = MIB_OBJECT_NONE; break; } } else { LWIP_DEBUGF(SNMP_MIB_DEBUG,("udpentry_get_object_def: no scalar\n")); od->instance = MIB_OBJECT_NONE; } } static void udpentry_get_value(struct obj_def *od, u16_t len, void *value) { u8_t id; struct udp_pcb *pcb; ipX_addr_t ip; u16_t port; LWIP_UNUSED_ARG(len); snmp_oidtoip(&od->id_inst_ptr[1], (ip_addr_t*)&ip); LWIP_ASSERT("invalid port", (od->id_inst_ptr[5] >= 0) && (od->id_inst_ptr[5] <= 0xffff)); port = (u16_t)od->id_inst_ptr[5]; pcb = udp_pcbs; while ((pcb != NULL) && !(ipX_addr_cmp(0, &pcb->local_ip, &ip) && (pcb->local_port == port))) { pcb = pcb->next; } if (pcb != NULL) { LWIP_ASSERT("invalid id", (od->id_inst_ptr[0] >= 0) && (od->id_inst_ptr[0] <= 0xff)); id = (u8_t)od->id_inst_ptr[0]; switch (id) { case 1: /* udpLocalAddress */ { ipX_addr_t *dst = (ipX_addr_t*)value; ipX_addr_copy(0, *dst, pcb->local_ip); } break; case 2: /* udpLocalPort */ { s32_t *sint_ptr = (s32_t*)value; *sint_ptr = pcb->local_port; } break; default: LWIP_DEBUGF(SNMP_MIB_DEBUG,("udpentry_get_value(): unknown id: %d\n", id)); break; } } } static void snmp_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od) { /* return to object name, adding index depth (1) */ ident_len += 1; ident -= 1; if (ident_len == 2) { u8_t id; od->id_inst_len = ident_len; od->id_inst_ptr = ident; LWIP_ASSERT("invalid id", (ident[0] >= 0) && (ident[0] <= 0xff)); id = (u8_t)ident[0]; switch (id) { case 1: /* snmpInPkts */ case 2: /* snmpOutPkts */ case 3: /* snmpInBadVersions */ case 4: /* snmpInBadCommunityNames */ case 5: /* snmpInBadCommunityUses */ case 6: /* snmpInASNParseErrs */ case 8: /* snmpInTooBigs */ case 9: /* snmpInNoSuchNames */ case 10: /* snmpInBadValues */ case 11: /* snmpInReadOnlys */ case 12: /* snmpInGenErrs */ case 13: /* snmpInTotalReqVars */ case 14: /* snmpInTotalSetVars */ case 15: /* snmpInGetRequests */ case 16: /* snmpInGetNexts */ case 17: /* snmpInSetRequests */ case 18: /* snmpInGetResponses */ case 19: /* snmpInTraps */ case 20: /* snmpOutTooBigs */ case 21: /* snmpOutNoSuchNames */ case 22: /* snmpOutBadValues */ case 24: /* snmpOutGenErrs */ case 25: /* snmpOutGetRequests */ case 26: /* snmpOutGetNexts */ case 27: /* snmpOutSetRequests */ case 28: /* snmpOutGetResponses */ case 29: /* snmpOutTraps */ od->instance = MIB_OBJECT_SCALAR; od->access = MIB_OBJECT_READ_ONLY; od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER); od->v_len = sizeof(u32_t); break; case 30: /* snmpEnableAuthenTraps */ od->instance = MIB_OBJECT_SCALAR; od->access = MIB_OBJECT_READ_WRITE; od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG); od->v_len = sizeof(s32_t); break; default: LWIP_DEBUGF(SNMP_MIB_DEBUG,("snmp_get_object_def: no such object\n")); od->instance = MIB_OBJECT_NONE; break; }; } else { LWIP_DEBUGF(SNMP_MIB_DEBUG,("snmp_get_object_def: no scalar\n")); od->instance = MIB_OBJECT_NONE; } } static void snmp_get_value(struct obj_def *od, u16_t len, void *value) { u32_t *uint_ptr = (u32_t*)value; u8_t id; LWIP_UNUSED_ARG(len); LWIP_ASSERT("invalid id", (od->id_inst_ptr[0] >= 0) && (od->id_inst_ptr[0] <= 0xff)); id = (u8_t)od->id_inst_ptr[0]; switch (id) { case 1: /* snmpInPkts */ *uint_ptr = snmpinpkts; break; case 2: /* snmpOutPkts */ *uint_ptr = snmpoutpkts; break; case 3: /* snmpInBadVersions */ *uint_ptr = snmpinbadversions; break; case 4: /* snmpInBadCommunityNames */ *uint_ptr = snmpinbadcommunitynames; break; case 5: /* snmpInBadCommunityUses */ *uint_ptr = snmpinbadcommunityuses; break; case 6: /* snmpInASNParseErrs */ *uint_ptr = snmpinasnparseerrs; break; case 8: /* snmpInTooBigs */ *uint_ptr = snmpintoobigs; break; case 9: /* snmpInNoSuchNames */ *uint_ptr = snmpinnosuchnames; break; case 10: /* snmpInBadValues */ *uint_ptr = snmpinbadvalues; break; case 11: /* snmpInReadOnlys */ *uint_ptr = snmpinreadonlys; break; case 12: /* snmpInGenErrs */ *uint_ptr = snmpingenerrs; break; case 13: /* snmpInTotalReqVars */ *uint_ptr = snmpintotalreqvars; break; case 14: /* snmpInTotalSetVars */ *uint_ptr = snmpintotalsetvars; break; case 15: /* snmpInGetRequests */ *uint_ptr = snmpingetrequests; break; case 16: /* snmpInGetNexts */ *uint_ptr = snmpingetnexts; break; case 17: /* snmpInSetRequests */ *uint_ptr = snmpinsetrequests; break; case 18: /* snmpInGetResponses */ *uint_ptr = snmpingetresponses; break; case 19: /* snmpInTraps */ *uint_ptr = snmpintraps; break; case 20: /* snmpOutTooBigs */ *uint_ptr = snmpouttoobigs; break; case 21: /* snmpOutNoSuchNames */ *uint_ptr = snmpoutnosuchnames; break; case 22: /* snmpOutBadValues */ *uint_ptr = snmpoutbadvalues; break; case 24: /* snmpOutGenErrs */ *uint_ptr = snmpoutgenerrs; break; case 25: /* snmpOutGetRequests */ *uint_ptr = snmpoutgetrequests; break; case 26: /* snmpOutGetNexts */ *uint_ptr = snmpoutgetnexts; break; case 27: /* snmpOutSetRequests */ *uint_ptr = snmpoutsetrequests; break; case 28: /* snmpOutGetResponses */ *uint_ptr = snmpoutgetresponses; break; case 29: /* snmpOutTraps */ *uint_ptr = snmpouttraps; break; case 30: /* snmpEnableAuthenTraps */ *uint_ptr = *snmpenableauthentraps_ptr; break; default: LWIP_DEBUGF(SNMP_MIB_DEBUG,("snmp_get_value(): unknown id: %d\n", id)); break; }; } /** * Test snmp object value before setting. * * @param od is the object definition * @param len return value space (in bytes) * @param value points to (varbind) space to copy value from. */ static u8_t snmp_set_test(struct obj_def *od, u16_t len, void *value) { u8_t id, set_ok; LWIP_UNUSED_ARG(len); set_ok = 0; LWIP_ASSERT("invalid id", (od->id_inst_ptr[0] >= 0) && (od->id_inst_ptr[0] <= 0xff)); id = (u8_t)od->id_inst_ptr[0]; if (id == 30) { /* snmpEnableAuthenTraps */ s32_t *sint_ptr = (s32_t*)value; if (snmpenableauthentraps_ptr != &snmpenableauthentraps_default) { /* we should have writable non-volatile mem here */ if ((*sint_ptr == 1) || (*sint_ptr == 2)) { set_ok = 1; } } else { /* const or hardwired value */ if (*sint_ptr == snmpenableauthentraps_default) { set_ok = 1; } } } return set_ok; } static void snmp_set_value(struct obj_def *od, u16_t len, void *value) { u8_t id; LWIP_UNUSED_ARG(len); LWIP_ASSERT("invalid id", (od->id_inst_ptr[0] >= 0) && (od->id_inst_ptr[0] <= 0xff)); id = (u8_t)od->id_inst_ptr[0]; if (id == 30) { /* snmpEnableAuthenTraps */ /* @todo @fixme: which kind of pointer is 'value'? s32_t or u8_t??? */ u8_t *ptr = (u8_t*)value; *snmpenableauthentraps_ptr = *ptr; } } #endif /* LWIP_SNMP */ ocproxy-1.60/lwip/src/core/snmp/mib_structs.c000066400000000000000000000721051303453231400213170ustar00rootroot00000000000000/** * @file * MIB tree access/construction functions. */ /* * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * Author: Christiaan Simons */ #include "lwip/opt.h" #if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */ #include "lwip/snmp_structs.h" #include "lwip/memp.h" #include "lwip/netif.h" /** .iso.org.dod.internet address prefix, @see snmp_iso_*() */ const s32_t prefix[4] = {1, 3, 6, 1}; #define NODE_STACK_SIZE (LWIP_SNMP_OBJ_ID_LEN) /** node stack entry (old news?) */ struct nse { /** right child */ struct mib_node* r_ptr; /** right child identifier */ s32_t r_id; /** right child next level */ u8_t r_nl; }; static u8_t node_stack_cnt; static struct nse node_stack[NODE_STACK_SIZE]; const struct nse node_null = {NULL, 0, 0}; /** * Pushes nse struct onto stack. */ static void push_node(const struct nse* node) { LWIP_ASSERT("node_stack_cnt < NODE_STACK_SIZE",node_stack_cnt < NODE_STACK_SIZE); LWIP_DEBUGF(SNMP_MIB_DEBUG,("push_node() node=%p id=%"S32_F"\n",(void*)(node->r_ptr),node->r_id)); if (node_stack_cnt < NODE_STACK_SIZE) { node_stack[node_stack_cnt] = *node; node_stack_cnt++; } } /** * Pops nse struct from stack. */ static void pop_node(struct nse* node) { if (node_stack_cnt > 0) { node_stack_cnt--; *node = node_stack[node_stack_cnt]; } LWIP_DEBUGF(SNMP_MIB_DEBUG,("pop_node() node=%p id=%"S32_F"\n",(void *)(node->r_ptr),node->r_id)); } /** * Conversion from ifIndex to lwIP netif * @param ifindex is a s32_t object sub-identifier * @param netif points to returned netif struct pointer */ void snmp_ifindextonetif(s32_t ifindex, struct netif **netif) { struct netif *nif = netif_list; s32_t i, ifidx; ifidx = ifindex - 1; i = 0; while ((nif != NULL) && (i < ifidx)) { nif = nif->next; i++; } *netif = nif; } /** * Conversion from lwIP netif to ifIndex * @param netif points to a netif struct * @param ifidx points to s32_t object sub-identifier */ void snmp_netiftoifindex(struct netif *netif, s32_t *ifidx) { struct netif *nif = netif_list; u16_t i; i = 0; while ((nif != NULL) && (nif != netif)) { nif = nif->next; i++; } *ifidx = i+1; } /** * Conversion from oid to lwIP ip_addr * @param ident points to s32_t ident[4] input * @param ip points to output struct */ void snmp_oidtoip(s32_t *ident, ip_addr_t *ip) { IP4_ADDR(ip, ident[0], ident[1], ident[2], ident[3]); } /** * Conversion from lwIP ip_addr to oid * @param ip points to input struct * @param ident points to s32_t ident[4] output */ void snmp_iptooid(ip_addr_t *ip, s32_t *ident) { ident[0] = ip4_addr1(ip); ident[1] = ip4_addr2(ip); ident[2] = ip4_addr3(ip); ident[3] = ip4_addr4(ip); } struct mib_list_node * snmp_mib_ln_alloc(s32_t id) { struct mib_list_node *ln; ln = (struct mib_list_node *)memp_malloc(MEMP_SNMP_NODE); if (ln != NULL) { ln->prev = NULL; ln->next = NULL; ln->objid = id; ln->nptr = NULL; } return ln; } void snmp_mib_ln_free(struct mib_list_node *ln) { memp_free(MEMP_SNMP_NODE, ln); } struct mib_list_rootnode * snmp_mib_lrn_alloc(void) { struct mib_list_rootnode *lrn; lrn = (struct mib_list_rootnode*)memp_malloc(MEMP_SNMP_ROOTNODE); if (lrn != NULL) { lrn->get_object_def = noleafs_get_object_def; lrn->get_value = noleafs_get_value; lrn->set_test = noleafs_set_test; lrn->set_value = noleafs_set_value; lrn->node_type = MIB_NODE_LR; lrn->maxlength = 0; lrn->head = NULL; lrn->tail = NULL; lrn->count = 0; } return lrn; } void snmp_mib_lrn_free(struct mib_list_rootnode *lrn) { memp_free(MEMP_SNMP_ROOTNODE, lrn); } /** * Inserts node in idx list in a sorted * (ascending order) fashion and * allocates the node if needed. * * @param rn points to the root node * @param objid is the object sub identifier * @param insn points to a pointer to the inserted node * used for constructing the tree. * @return -1 if failed, 1 if inserted, 2 if present. */ s8_t snmp_mib_node_insert(struct mib_list_rootnode *rn, s32_t objid, struct mib_list_node **insn) { struct mib_list_node *nn; s8_t insert; LWIP_ASSERT("rn != NULL",rn != NULL); /* -1 = malloc failure, 0 = not inserted, 1 = inserted, 2 = was present */ insert = 0; if (rn->head == NULL) { /* empty list, add first node */ LWIP_DEBUGF(SNMP_MIB_DEBUG,("alloc empty list objid==%"S32_F"\n",objid)); nn = snmp_mib_ln_alloc(objid); if (nn != NULL) { rn->head = nn; rn->tail = nn; *insn = nn; insert = 1; } else { insert = -1; } } else { struct mib_list_node *n; /* at least one node is present */ n = rn->head; while ((n != NULL) && (insert == 0)) { if (n->objid == objid) { /* node is already there */ LWIP_DEBUGF(SNMP_MIB_DEBUG,("node already there objid==%"S32_F"\n",objid)); *insn = n; insert = 2; } else if (n->objid < objid) { if (n->next == NULL) { /* alloc and insert at the tail */ LWIP_DEBUGF(SNMP_MIB_DEBUG,("alloc ins tail objid==%"S32_F"\n",objid)); nn = snmp_mib_ln_alloc(objid); if (nn != NULL) { nn->next = NULL; nn->prev = n; n->next = nn; rn->tail = nn; *insn = nn; insert = 1; } else { /* insertion failure */ insert = -1; } } else { /* there's more to explore: traverse list */ LWIP_DEBUGF(SNMP_MIB_DEBUG,("traverse list\n")); n = n->next; } } else { /* n->objid > objid */ /* alloc and insert between n->prev and n */ LWIP_DEBUGF(SNMP_MIB_DEBUG,("alloc ins n->prev, objid==%"S32_F", n\n",objid)); nn = snmp_mib_ln_alloc(objid); if (nn != NULL) { if (n->prev == NULL) { /* insert at the head */ nn->next = n; nn->prev = NULL; rn->head = nn; n->prev = nn; } else { /* insert in the middle */ nn->next = n; nn->prev = n->prev; n->prev->next = nn; n->prev = nn; } *insn = nn; insert = 1; } else { /* insertion failure */ insert = -1; } } } } if (insert == 1) { rn->count += 1; } LWIP_ASSERT("insert != 0",insert != 0); return insert; } /** * Finds node in idx list and returns deletion mark. * * @param rn points to the root node * @param objid is the object sub identifier * @param fn returns pointer to found node * @return 0 if not found, 1 if deletable, * 2 can't delete (2 or more children), 3 not a list_node */ s8_t snmp_mib_node_find(struct mib_list_rootnode *rn, s32_t objid, struct mib_list_node **fn) { s8_t fc; struct mib_list_node *n; LWIP_ASSERT("rn != NULL",rn != NULL); n = rn->head; while ((n != NULL) && (n->objid != objid)) { n = n->next; } if (n == NULL) { fc = 0; } else if (n->nptr == NULL) { /* leaf, can delete node */ fc = 1; } else { struct mib_list_rootnode *r; if (n->nptr->node_type == MIB_NODE_LR) { r = (struct mib_list_rootnode *)n->nptr; if (r->count > 1) { /* can't delete node */ fc = 2; } else { /* count <= 1, can delete node */ fc = 1; } } else { /* other node type */ fc = 3; } } *fn = n; return fc; } /** * Removes node from idx list * if it has a single child left. * * @param rn points to the root node * @param n points to the node to delete * @return the nptr to be freed by caller */ struct mib_list_rootnode * snmp_mib_node_delete(struct mib_list_rootnode *rn, struct mib_list_node *n) { struct mib_list_rootnode *next; LWIP_ASSERT("rn != NULL",rn != NULL); LWIP_ASSERT("n != NULL",n != NULL); /* caller must remove this sub-tree */ next = (struct mib_list_rootnode*)(n->nptr); rn->count -= 1; if (n == rn->head) { rn->head = n->next; if (n->next != NULL) { /* not last node, new list begin */ n->next->prev = NULL; } } else if (n == rn->tail) { rn->tail = n->prev; if (n->prev != NULL) { /* not last node, new list end */ n->prev->next = NULL; } } else { /* node must be in the middle */ n->prev->next = n->next; n->next->prev = n->prev; } LWIP_DEBUGF(SNMP_MIB_DEBUG,("free list objid==%"S32_F"\n",n->objid)); snmp_mib_ln_free(n); if (rn->count == 0) { rn->head = NULL; rn->tail = NULL; } return next; } /** * Searches tree for the supplied (scalar?) object identifier. * * @param node points to the root of the tree ('.internet') * @param ident_len the length of the supplied object identifier * @param ident points to the array of sub identifiers * @param np points to the found object instance (return) * @return pointer to the requested parent (!) node if success, NULL otherwise */ struct mib_node * snmp_search_tree(struct mib_node *node, u8_t ident_len, s32_t *ident, struct snmp_name_ptr *np) { u8_t node_type, ext_level; ext_level = 0; LWIP_DEBUGF(SNMP_MIB_DEBUG,("node==%p *ident==%"S32_F"\n",(void*)node,*ident)); while (node != NULL) { node_type = node->node_type; if ((node_type == MIB_NODE_AR) || (node_type == MIB_NODE_RA)) { struct mib_array_node *an; u16_t i; if (ident_len > 0) { /* array node (internal ROM or RAM, fixed length) */ an = (struct mib_array_node *)node; i = 0; while ((i < an->maxlength) && (an->objid[i] != *ident)) { i++; } if (i < an->maxlength) { /* found it, if available proceed to child, otherwise inspect leaf */ LWIP_DEBUGF(SNMP_MIB_DEBUG,("an->objid[%"U16_F"]==%"S32_F" *ident==%"S32_F"\n",i,an->objid[i],*ident)); if (an->nptr[i] == NULL) { /* a scalar leaf OR table, inspect remaining instance number / table index */ np->ident_len = ident_len; np->ident = ident; return (struct mib_node*)an; } else { /* follow next child pointer */ ident++; ident_len--; node = an->nptr[i]; } } else { /* search failed, identifier mismatch (nosuchname) */ LWIP_DEBUGF(SNMP_MIB_DEBUG,("an search failed *ident==%"S32_F"\n",*ident)); return NULL; } } else { /* search failed, short object identifier (nosuchname) */ LWIP_DEBUGF(SNMP_MIB_DEBUG,("an search failed, short object identifier\n")); return NULL; } } else if(node_type == MIB_NODE_LR) { struct mib_list_rootnode *lrn; struct mib_list_node *ln; if (ident_len > 0) { /* list root node (internal 'RAM', variable length) */ lrn = (struct mib_list_rootnode *)node; ln = lrn->head; /* iterate over list, head to tail */ while ((ln != NULL) && (ln->objid != *ident)) { ln = ln->next; } if (ln != NULL) { /* found it, proceed to child */; LWIP_DEBUGF(SNMP_MIB_DEBUG,("ln->objid==%"S32_F" *ident==%"S32_F"\n",ln->objid,*ident)); if (ln->nptr == NULL) { np->ident_len = ident_len; np->ident = ident; return (struct mib_node*)lrn; } else { /* follow next child pointer */ ident_len--; ident++; node = ln->nptr; } } else { /* search failed */ LWIP_DEBUGF(SNMP_MIB_DEBUG,("ln search failed *ident==%"S32_F"\n",*ident)); return NULL; } } else { /* search failed, short object identifier (nosuchname) */ LWIP_DEBUGF(SNMP_MIB_DEBUG,("ln search failed, short object identifier\n")); return NULL; } } else if(node_type == MIB_NODE_EX) { struct mib_external_node *en; u16_t i, len; if (ident_len > 0) { /* external node (addressing and access via functions) */ en = (struct mib_external_node *)node; i = 0; len = en->level_length(en->addr_inf,ext_level); while ((i < len) && (en->ident_cmp(en->addr_inf,ext_level,i,*ident) != 0)) { i++; } if (i < len) { s32_t debug_id; en->get_objid(en->addr_inf,ext_level,i,&debug_id); LWIP_DEBUGF(SNMP_MIB_DEBUG,("en->objid==%"S32_F" *ident==%"S32_F"\n",debug_id,*ident)); if ((ext_level + 1) == en->tree_levels) { np->ident_len = ident_len; np->ident = ident; return (struct mib_node*)en; } else { /* found it, proceed to child */ ident_len--; ident++; ext_level++; } } else { /* search failed */ LWIP_DEBUGF(SNMP_MIB_DEBUG,("en search failed *ident==%"S32_F"\n",*ident)); return NULL; } } else { /* search failed, short object identifier (nosuchname) */ LWIP_DEBUGF(SNMP_MIB_DEBUG,("en search failed, short object identifier\n")); return NULL; } } else if (node_type == MIB_NODE_SC) { mib_scalar_node *sn; sn = (mib_scalar_node *)node; if ((ident_len == 1) && (*ident == 0)) { np->ident_len = ident_len; np->ident = ident; return (struct mib_node*)sn; } else { /* search failed, short object identifier (nosuchname) */ LWIP_DEBUGF(SNMP_MIB_DEBUG,("search failed, invalid object identifier length\n")); return NULL; } } else { /* unknown node_type */ LWIP_DEBUGF(SNMP_MIB_DEBUG,("search failed node_type %"U16_F" unkown\n",(u16_t)node_type)); return NULL; } } /* done, found nothing */ LWIP_DEBUGF(SNMP_MIB_DEBUG,("search failed node==%p\n",(void*)node)); return NULL; } /** * Test table for presence of at least one table entry. */ static u8_t empty_table(struct mib_node *node) { u8_t node_type; u8_t empty = 0; if (node != NULL) { node_type = node->node_type; if (node_type == MIB_NODE_LR) { struct mib_list_rootnode *lrn; lrn = (struct mib_list_rootnode *)node; if ((lrn->count == 0) || (lrn->head == NULL)) { empty = 1; } } else if ((node_type == MIB_NODE_AR) || (node_type == MIB_NODE_RA)) { struct mib_array_node *an; an = (struct mib_array_node *)node; if ((an->maxlength == 0) || (an->nptr == NULL)) { empty = 1; } } else if (node_type == MIB_NODE_EX) { struct mib_external_node *en; en = (struct mib_external_node *)node; if (en->tree_levels == 0) { empty = 1; } } } return empty; } /** * Tree expansion. */ struct mib_node * snmp_expand_tree(struct mib_node *node, u8_t ident_len, s32_t *ident, struct snmp_obj_id *oidret) { u8_t node_type, ext_level, climb_tree; ext_level = 0; /* reset node stack */ node_stack_cnt = 0; while (node != NULL) { climb_tree = 0; node_type = node->node_type; if ((node_type == MIB_NODE_AR) || (node_type == MIB_NODE_RA)) { struct mib_array_node *an; u16_t i; /* array node (internal ROM or RAM, fixed length) */ an = (struct mib_array_node *)node; if (ident_len > 0) { i = 0; while ((i < an->maxlength) && (an->objid[i] < *ident)) { i++; } if (i < an->maxlength) { LWIP_DEBUGF(SNMP_MIB_DEBUG,("an->objid[%"U16_F"]==%"S32_F" *ident==%"S32_F"\n",i,an->objid[i],*ident)); /* add identifier to oidret */ oidret->id[oidret->len] = an->objid[i]; (oidret->len)++; if (an->nptr[i] == NULL) { LWIP_DEBUGF(SNMP_MIB_DEBUG,("leaf node\n")); /* leaf node (e.g. in a fixed size table) */ if (an->objid[i] > *ident) { return (struct mib_node*)an; } else if ((i + 1) < an->maxlength) { /* an->objid[i] == *ident */ (oidret->len)--; oidret->id[oidret->len] = an->objid[i + 1]; (oidret->len)++; return (struct mib_node*)an; } else { /* (i + 1) == an->maxlength */ (oidret->len)--; climb_tree = 1; } } else { u16_t j; LWIP_DEBUGF(SNMP_MIB_DEBUG,("non-leaf node\n")); /* non-leaf, store right child ptr and id */ LWIP_ASSERT("i < 0xff", i < 0xff); j = i + 1; while ((j < an->maxlength) && (empty_table(an->nptr[j]))) { j++; } if (j < an->maxlength) { struct nse cur_node; cur_node.r_ptr = an->nptr[j]; cur_node.r_id = an->objid[j]; cur_node.r_nl = 0; push_node(&cur_node); } else { push_node(&node_null); } if (an->objid[i] == *ident) { ident_len--; ident++; } else { /* an->objid[i] < *ident */ ident_len = 0; } /* follow next child pointer */ node = an->nptr[i]; } } else { /* i == an->maxlength */ climb_tree = 1; } } else { u16_t j; /* ident_len == 0, complete with leftmost '.thing' */ j = 0; while ((j < an->maxlength) && empty_table(an->nptr[j])) { j++; } if (j < an->maxlength) { LWIP_DEBUGF(SNMP_MIB_DEBUG,("left an->objid[j]==%"S32_F"\n",an->objid[j])); oidret->id[oidret->len] = an->objid[j]; (oidret->len)++; if (an->nptr[j] == NULL) { /* leaf node */ return (struct mib_node*)an; } else { /* no leaf, continue */ node = an->nptr[j]; } } else { /* j == an->maxlength */ climb_tree = 1; } } } else if(node_type == MIB_NODE_LR) { struct mib_list_rootnode *lrn; struct mib_list_node *ln; /* list root node (internal 'RAM', variable length) */ lrn = (struct mib_list_rootnode *)node; if (ident_len > 0) { ln = lrn->head; /* iterate over list, head to tail */ while ((ln != NULL) && (ln->objid < *ident)) { ln = ln->next; } if (ln != NULL) { LWIP_DEBUGF(SNMP_MIB_DEBUG,("ln->objid==%"S32_F" *ident==%"S32_F"\n",ln->objid,*ident)); oidret->id[oidret->len] = ln->objid; (oidret->len)++; if (ln->nptr == NULL) { /* leaf node */ if (ln->objid > *ident) { return (struct mib_node*)lrn; } else if (ln->next != NULL) { /* ln->objid == *ident */ (oidret->len)--; oidret->id[oidret->len] = ln->next->objid; (oidret->len)++; return (struct mib_node*)lrn; } else { /* ln->next == NULL */ (oidret->len)--; climb_tree = 1; } } else { struct mib_list_node *jn; /* non-leaf, store right child ptr and id */ jn = ln->next; while ((jn != NULL) && empty_table(jn->nptr)) { jn = jn->next; } if (jn != NULL) { struct nse cur_node; cur_node.r_ptr = jn->nptr; cur_node.r_id = jn->objid; cur_node.r_nl = 0; push_node(&cur_node); } else { push_node(&node_null); } if (ln->objid == *ident) { ident_len--; ident++; } else { /* ln->objid < *ident */ ident_len = 0; } /* follow next child pointer */ node = ln->nptr; } } else { /* ln == NULL */ climb_tree = 1; } } else { struct mib_list_node *jn; /* ident_len == 0, complete with leftmost '.thing' */ jn = lrn->head; while ((jn != NULL) && empty_table(jn->nptr)) { jn = jn->next; } if (jn != NULL) { LWIP_DEBUGF(SNMP_MIB_DEBUG,("left jn->objid==%"S32_F"\n",jn->objid)); oidret->id[oidret->len] = jn->objid; (oidret->len)++; if (jn->nptr == NULL) { /* leaf node */ LWIP_DEBUGF(SNMP_MIB_DEBUG,("jn->nptr == NULL\n")); return (struct mib_node*)lrn; } else { /* no leaf, continue */ node = jn->nptr; } } else { /* jn == NULL */ climb_tree = 1; } } } else if(node_type == MIB_NODE_EX) { struct mib_external_node *en; s32_t ex_id; /* external node (addressing and access via functions) */ en = (struct mib_external_node *)node; if (ident_len > 0) { u16_t i, len; i = 0; len = en->level_length(en->addr_inf,ext_level); while ((i < len) && (en->ident_cmp(en->addr_inf,ext_level,i,*ident) < 0)) { i++; } if (i < len) { /* add identifier to oidret */ en->get_objid(en->addr_inf,ext_level,i,&ex_id); LWIP_DEBUGF(SNMP_MIB_DEBUG,("en->objid[%"U16_F"]==%"S32_F" *ident==%"S32_F"\n",i,ex_id,*ident)); oidret->id[oidret->len] = ex_id; (oidret->len)++; if ((ext_level + 1) == en->tree_levels) { LWIP_DEBUGF(SNMP_MIB_DEBUG,("leaf node\n")); /* leaf node */ if (ex_id > *ident) { return (struct mib_node*)en; } else if ((i + 1) < len) { /* ex_id == *ident */ en->get_objid(en->addr_inf,ext_level,i + 1,&ex_id); (oidret->len)--; oidret->id[oidret->len] = ex_id; (oidret->len)++; return (struct mib_node*)en; } else { /* (i + 1) == len */ (oidret->len)--; climb_tree = 1; } } else { u16_t j; LWIP_DEBUGF(SNMP_MIB_DEBUG,("non-leaf node\n")); /* non-leaf, store right child ptr and id */ LWIP_ASSERT("i < 0xff", i < 0xff); j = i + 1; if (j < len) { struct nse cur_node; /* right node is the current external node */ cur_node.r_ptr = node; en->get_objid(en->addr_inf,ext_level,j,&cur_node.r_id); cur_node.r_nl = ext_level + 1; push_node(&cur_node); } else { push_node(&node_null); } if (en->ident_cmp(en->addr_inf,ext_level,i,*ident) == 0) { ident_len--; ident++; } else { /* external id < *ident */ ident_len = 0; } /* proceed to child */ ext_level++; } } else { /* i == len (en->level_len()) */ climb_tree = 1; } } else { /* ident_len == 0, complete with leftmost '.thing' */ en->get_objid(en->addr_inf,ext_level,0,&ex_id); LWIP_DEBUGF(SNMP_MIB_DEBUG,("left en->objid==%"S32_F"\n",ex_id)); oidret->id[oidret->len] = ex_id; (oidret->len)++; if ((ext_level + 1) == en->tree_levels) { /* leaf node */ LWIP_DEBUGF(SNMP_MIB_DEBUG,("(ext_level + 1) == en->tree_levels\n")); return (struct mib_node*)en; } else { /* no leaf, proceed to child */ ext_level++; } } } else if(node_type == MIB_NODE_SC) { mib_scalar_node *sn; /* scalar node */ sn = (mib_scalar_node *)node; if (ident_len > 0) { /* at .0 */ climb_tree = 1; } else { /* ident_len == 0, complete object identifier */ oidret->id[oidret->len] = 0; (oidret->len)++; /* leaf node */ LWIP_DEBUGF(SNMP_MIB_DEBUG,("completed scalar leaf\n")); return (struct mib_node*)sn; } } else { /* unknown/unhandled node_type */ LWIP_DEBUGF(SNMP_MIB_DEBUG,("expand failed node_type %"U16_F" unkown\n",(u16_t)node_type)); return NULL; } if (climb_tree) { struct nse child; /* find right child ptr */ child.r_ptr = NULL; child.r_id = 0; child.r_nl = 0; while ((node_stack_cnt > 0) && (child.r_ptr == NULL)) { pop_node(&child); /* trim returned oid */ (oidret->len)--; } if (child.r_ptr != NULL) { /* incoming ident is useless beyond this point */ ident_len = 0; oidret->id[oidret->len] = child.r_id; oidret->len++; node = child.r_ptr; ext_level = child.r_nl; } else { /* tree ends here ... */ LWIP_DEBUGF(SNMP_MIB_DEBUG,("expand failed, tree ends here\n")); return NULL; } } } /* done, found nothing */ LWIP_DEBUGF(SNMP_MIB_DEBUG,("expand failed node==%p\n",(void*)node)); return NULL; } /** * Test object identifier for the iso.org.dod.internet prefix. * * @param ident_len the length of the supplied object identifier * @param ident points to the array of sub identifiers * @return 1 if it matches, 0 otherwise */ u8_t snmp_iso_prefix_tst(u8_t ident_len, s32_t *ident) { if ((ident_len > 3) && (ident[0] == 1) && (ident[1] == 3) && (ident[2] == 6) && (ident[3] == 1)) { return 1; } else { return 0; } } /** * Expands object identifier to the iso.org.dod.internet * prefix for use in getnext operation. * * @param ident_len the length of the supplied object identifier * @param ident points to the array of sub identifiers * @param oidret points to returned expanded object identifier * @return 1 if it matches, 0 otherwise * * @note ident_len 0 is allowed, expanding to the first known object id!! */ u8_t snmp_iso_prefix_expand(u8_t ident_len, s32_t *ident, struct snmp_obj_id *oidret) { const s32_t *prefix_ptr; s32_t *ret_ptr; u8_t i; i = 0; prefix_ptr = &prefix[0]; ret_ptr = &oidret->id[0]; ident_len = ((ident_len < 4)?ident_len:4); while ((i < ident_len) && ((*ident) <= (*prefix_ptr))) { *ret_ptr++ = *prefix_ptr++; ident++; i++; } if (i == ident_len) { /* match, complete missing bits */ while (i < 4) { *ret_ptr++ = *prefix_ptr++; i++; } oidret->len = i; return 1; } else { /* i != ident_len */ return 0; } } #endif /* LWIP_SNMP */ ocproxy-1.60/lwip/src/core/snmp/msg_in.c000066400000000000000000001261051303453231400202350ustar00rootroot00000000000000/** * @file * SNMP input message processing (RFC1157). */ /* * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * Author: Christiaan Simons */ #include "lwip/opt.h" #if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */ #include "lwip/snmp.h" #include "lwip/snmp_asn1.h" #include "lwip/snmp_msg.h" #include "lwip/snmp_structs.h" #include "lwip/ip_addr.h" #include "lwip/memp.h" #include "lwip/udp.h" #include "lwip/stats.h" #include /* public (non-static) constants */ /** SNMP v1 == 0 */ const s32_t snmp_version = 0; /** default SNMP community string */ const char snmp_publiccommunity[7] = "public"; /* statically allocated buffers for SNMP_CONCURRENT_REQUESTS */ struct snmp_msg_pstat msg_input_list[SNMP_CONCURRENT_REQUESTS]; /* UDP Protocol Control Block */ struct udp_pcb *snmp1_pcb; static void snmp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port); static err_t snmp_pdu_header_check(struct pbuf *p, u16_t ofs, u16_t pdu_len, u16_t *ofs_ret, struct snmp_msg_pstat *m_stat); static err_t snmp_pdu_dec_varbindlist(struct pbuf *p, u16_t ofs, u16_t *ofs_ret, struct snmp_msg_pstat *m_stat); /** * Starts SNMP Agent. * Allocates UDP pcb and binds it to IP_ADDR_ANY port 161. */ void snmp_init(void) { struct snmp_msg_pstat *msg_ps; u8_t i; snmp1_pcb = udp_new(); if (snmp1_pcb != NULL) { udp_recv(snmp1_pcb, snmp_recv, (void *)SNMP_IN_PORT); udp_bind(snmp1_pcb, IP_ADDR_ANY, SNMP_IN_PORT); } msg_ps = &msg_input_list[0]; for (i=0; istate = SNMP_MSG_EMPTY; msg_ps->error_index = 0; msg_ps->error_status = SNMP_ES_NOERROR; msg_ps++; } trap_msg.pcb = snmp1_pcb; #ifdef SNMP_PRIVATE_MIB_INIT /* If defined, this must be a function-like define to initialize the * private MIB after the stack has been initialized. * The private MIB can also be initialized in tcpip_callback (or after * the stack is initialized), this define is only for convenience. */ SNMP_PRIVATE_MIB_INIT(); #endif /* SNMP_PRIVATE_MIB_INIT */ /* The coldstart trap will only be output if our outgoing interface is up & configured */ snmp_coldstart_trap(); } static void snmp_error_response(struct snmp_msg_pstat *msg_ps, u8_t error) { /* move names back from outvb to invb */ int v; struct snmp_varbind *vbi = msg_ps->invb.head; struct snmp_varbind *vbo = msg_ps->outvb.head; for (v=0; vvb_idx; v++) { vbi->ident_len = vbo->ident_len; vbo->ident_len = 0; vbi->ident = vbo->ident; vbo->ident = NULL; vbi = vbi->next; vbo = vbo->next; } /* free outvb */ snmp_varbind_list_free(&msg_ps->outvb); /* we send invb back */ msg_ps->outvb = msg_ps->invb; msg_ps->invb.head = NULL; msg_ps->invb.tail = NULL; msg_ps->invb.count = 0; msg_ps->error_status = error; /* error index must be 0 for error too big */ msg_ps->error_index = (error != SNMP_ES_TOOBIG) ? (1 + msg_ps->vb_idx) : 0; snmp_send_response(msg_ps); snmp_varbind_list_free(&msg_ps->outvb); msg_ps->state = SNMP_MSG_EMPTY; } static void snmp_ok_response(struct snmp_msg_pstat *msg_ps) { err_t err_ret; err_ret = snmp_send_response(msg_ps); if (err_ret == ERR_MEM) { /* serious memory problem, can't return tooBig */ } else { LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_event = %"S32_F"\n",msg_ps->error_status)); } /* free varbinds (if available) */ snmp_varbind_list_free(&msg_ps->invb); snmp_varbind_list_free(&msg_ps->outvb); msg_ps->state = SNMP_MSG_EMPTY; } /** * Service an internal or external event for SNMP GET. * * @param request_id identifies requests from 0 to (SNMP_CONCURRENT_REQUESTS-1) * @param msg_ps points to the assosicated message process state */ static void snmp_msg_get_event(u8_t request_id, struct snmp_msg_pstat *msg_ps) { LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_get_event: msg_ps->state==%"U16_F"\n",(u16_t)msg_ps->state)); if (msg_ps->state == SNMP_MSG_EXTERNAL_GET_OBJDEF) { struct mib_external_node *en; struct snmp_name_ptr np; /* get_object_def() answer*/ en = msg_ps->ext_mib_node; np = msg_ps->ext_name_ptr; /* translate answer into a known lifeform */ en->get_object_def_a(request_id, np.ident_len, np.ident, &msg_ps->ext_object_def); if ((msg_ps->ext_object_def.instance != MIB_OBJECT_NONE) && (msg_ps->ext_object_def.access & MIB_ACCESS_READ)) { msg_ps->state = SNMP_MSG_EXTERNAL_GET_VALUE; en->get_value_q(request_id, &msg_ps->ext_object_def); } else { en->get_object_def_pc(request_id, np.ident_len, np.ident); /* search failed, object id points to unknown object (nosuchname) */ snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME); } } else if (msg_ps->state == SNMP_MSG_EXTERNAL_GET_VALUE) { struct mib_external_node *en; struct snmp_varbind *vb; /* get_value() answer */ en = msg_ps->ext_mib_node; /* allocate output varbind */ vb = (struct snmp_varbind *)memp_malloc(MEMP_SNMP_VARBIND); if (vb != NULL) { vb->next = NULL; vb->prev = NULL; /* move name from invb to outvb */ vb->ident = msg_ps->vb_ptr->ident; vb->ident_len = msg_ps->vb_ptr->ident_len; /* ensure this memory is refereced once only */ msg_ps->vb_ptr->ident = NULL; msg_ps->vb_ptr->ident_len = 0; vb->value_type = msg_ps->ext_object_def.asn_type; LWIP_ASSERT("invalid length", msg_ps->ext_object_def.v_len <= 0xff); vb->value_len = (u8_t)msg_ps->ext_object_def.v_len; if (vb->value_len > 0) { LWIP_ASSERT("SNMP_MAX_OCTET_STRING_LEN is configured too low", vb->value_len <= SNMP_MAX_VALUE_SIZE); vb->value = memp_malloc(MEMP_SNMP_VALUE); if (vb->value != NULL) { en->get_value_a(request_id, &msg_ps->ext_object_def, vb->value_len, vb->value); snmp_varbind_tail_add(&msg_ps->outvb, vb); /* search again (if vb_idx < msg_ps->invb.count) */ msg_ps->state = SNMP_MSG_SEARCH_OBJ; msg_ps->vb_idx += 1; } else { en->get_value_pc(request_id, &msg_ps->ext_object_def); LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_event: no variable space\n")); msg_ps->vb_ptr->ident = vb->ident; msg_ps->vb_ptr->ident_len = vb->ident_len; memp_free(MEMP_SNMP_VARBIND, vb); snmp_error_response(msg_ps,SNMP_ES_TOOBIG); } } else { /* vb->value_len == 0, empty value (e.g. empty string) */ en->get_value_a(request_id, &msg_ps->ext_object_def, 0, NULL); vb->value = NULL; snmp_varbind_tail_add(&msg_ps->outvb, vb); /* search again (if vb_idx < msg_ps->invb.count) */ msg_ps->state = SNMP_MSG_SEARCH_OBJ; msg_ps->vb_idx += 1; } } else { en->get_value_pc(request_id, &msg_ps->ext_object_def); LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_event: no outvb space\n")); snmp_error_response(msg_ps,SNMP_ES_TOOBIG); } } while ((msg_ps->state == SNMP_MSG_SEARCH_OBJ) && (msg_ps->vb_idx < msg_ps->invb.count)) { struct mib_node *mn; struct snmp_name_ptr np; if (msg_ps->vb_idx == 0) { msg_ps->vb_ptr = msg_ps->invb.head; } else { msg_ps->vb_ptr = msg_ps->vb_ptr->next; } /** test object identifier for .iso.org.dod.internet prefix */ if (snmp_iso_prefix_tst(msg_ps->vb_ptr->ident_len, msg_ps->vb_ptr->ident)) { mn = snmp_search_tree((struct mib_node*)&internet, msg_ps->vb_ptr->ident_len - 4, msg_ps->vb_ptr->ident + 4, &np); if (mn != NULL) { if (mn->node_type == MIB_NODE_EX) { /* external object */ struct mib_external_node *en = (struct mib_external_node*)mn; msg_ps->state = SNMP_MSG_EXTERNAL_GET_OBJDEF; /* save en && args in msg_ps!! */ msg_ps->ext_mib_node = en; msg_ps->ext_name_ptr = np; en->get_object_def_q(en->addr_inf, request_id, np.ident_len, np.ident); } else { /* internal object */ struct obj_def object_def; msg_ps->state = SNMP_MSG_INTERNAL_GET_OBJDEF; mn->get_object_def(np.ident_len, np.ident, &object_def); if ((object_def.instance != MIB_OBJECT_NONE) && (object_def.access & MIB_ACCESS_READ)) { mn = mn; } else { /* search failed, object id points to unknown object (nosuchname) */ mn = NULL; } if (mn != NULL) { struct snmp_varbind *vb; msg_ps->state = SNMP_MSG_INTERNAL_GET_VALUE; /* allocate output varbind */ vb = (struct snmp_varbind *)memp_malloc(MEMP_SNMP_VARBIND); if (vb != NULL) { vb->next = NULL; vb->prev = NULL; /* move name from invb to outvb */ vb->ident = msg_ps->vb_ptr->ident; vb->ident_len = msg_ps->vb_ptr->ident_len; /* ensure this memory is refereced once only */ msg_ps->vb_ptr->ident = NULL; msg_ps->vb_ptr->ident_len = 0; vb->value_type = object_def.asn_type; LWIP_ASSERT("invalid length", object_def.v_len <= 0xff); vb->value_len = (u8_t)object_def.v_len; if (vb->value_len > 0) { LWIP_ASSERT("SNMP_MAX_OCTET_STRING_LEN is configured too low", vb->value_len <= SNMP_MAX_VALUE_SIZE); vb->value = memp_malloc(MEMP_SNMP_VALUE); if (vb->value != NULL) { mn->get_value(&object_def, vb->value_len, vb->value); snmp_varbind_tail_add(&msg_ps->outvb, vb); msg_ps->state = SNMP_MSG_SEARCH_OBJ; msg_ps->vb_idx += 1; } else { LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_event: couldn't allocate variable space\n")); msg_ps->vb_ptr->ident = vb->ident; msg_ps->vb_ptr->ident_len = vb->ident_len; vb->ident = NULL; vb->ident_len = 0; memp_free(MEMP_SNMP_VARBIND, vb); snmp_error_response(msg_ps,SNMP_ES_TOOBIG); } } else { /* vb->value_len == 0, empty value (e.g. empty string) */ vb->value = NULL; snmp_varbind_tail_add(&msg_ps->outvb, vb); msg_ps->state = SNMP_MSG_SEARCH_OBJ; msg_ps->vb_idx += 1; } } else { LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_event: couldn't allocate outvb space\n")); snmp_error_response(msg_ps,SNMP_ES_TOOBIG); } } } } } else { mn = NULL; } if (mn == NULL) { /* mn == NULL, noSuchName */ snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME); } } if ((msg_ps->state == SNMP_MSG_SEARCH_OBJ) && (msg_ps->vb_idx == msg_ps->invb.count)) { snmp_ok_response(msg_ps); } } /** * Service an internal or external event for SNMP GETNEXT. * * @param request_id identifies requests from 0 to (SNMP_CONCURRENT_REQUESTS-1) * @param msg_ps points to the assosicated message process state */ static void snmp_msg_getnext_event(u8_t request_id, struct snmp_msg_pstat *msg_ps) { LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_getnext_event: msg_ps->state==%"U16_F"\n",(u16_t)msg_ps->state)); if (msg_ps->state == SNMP_MSG_EXTERNAL_GET_OBJDEF) { struct mib_external_node *en; /* get_object_def() answer*/ en = msg_ps->ext_mib_node; /* translate answer into a known lifeform */ en->get_object_def_a(request_id, 1, &msg_ps->ext_oid.id[msg_ps->ext_oid.len - 1], &msg_ps->ext_object_def); if (msg_ps->ext_object_def.instance != MIB_OBJECT_NONE) { msg_ps->state = SNMP_MSG_EXTERNAL_GET_VALUE; en->get_value_q(request_id, &msg_ps->ext_object_def); } else { en->get_object_def_pc(request_id, 1, &msg_ps->ext_oid.id[msg_ps->ext_oid.len - 1]); /* search failed, object id points to unknown object (nosuchname) */ snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME); } } else if (msg_ps->state == SNMP_MSG_EXTERNAL_GET_VALUE) { struct mib_external_node *en; struct snmp_varbind *vb; /* get_value() answer */ en = msg_ps->ext_mib_node; LWIP_ASSERT("invalid length", msg_ps->ext_object_def.v_len <= 0xff); vb = snmp_varbind_alloc(&msg_ps->ext_oid, msg_ps->ext_object_def.asn_type, (u8_t)msg_ps->ext_object_def.v_len); if (vb != NULL) { en->get_value_a(request_id, &msg_ps->ext_object_def, vb->value_len, vb->value); snmp_varbind_tail_add(&msg_ps->outvb, vb); msg_ps->state = SNMP_MSG_SEARCH_OBJ; msg_ps->vb_idx += 1; } else { en->get_value_pc(request_id, &msg_ps->ext_object_def); LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_getnext_event: couldn't allocate outvb space\n")); snmp_error_response(msg_ps,SNMP_ES_TOOBIG); } } while ((msg_ps->state == SNMP_MSG_SEARCH_OBJ) && (msg_ps->vb_idx < msg_ps->invb.count)) { struct mib_node *mn; struct snmp_obj_id oid; if (msg_ps->vb_idx == 0) { msg_ps->vb_ptr = msg_ps->invb.head; } else { msg_ps->vb_ptr = msg_ps->vb_ptr->next; } if (snmp_iso_prefix_expand(msg_ps->vb_ptr->ident_len, msg_ps->vb_ptr->ident, &oid)) { if (msg_ps->vb_ptr->ident_len > 3) { /* can offset ident_len and ident */ mn = snmp_expand_tree((struct mib_node*)&internet, msg_ps->vb_ptr->ident_len - 4, msg_ps->vb_ptr->ident + 4, &oid); } else { /* can't offset ident_len -4, ident + 4 */ mn = snmp_expand_tree((struct mib_node*)&internet, 0, NULL, &oid); } } else { mn = NULL; } if (mn != NULL) { if (mn->node_type == MIB_NODE_EX) { /* external object */ struct mib_external_node *en = (struct mib_external_node*)mn; msg_ps->state = SNMP_MSG_EXTERNAL_GET_OBJDEF; /* save en && args in msg_ps!! */ msg_ps->ext_mib_node = en; msg_ps->ext_oid = oid; en->get_object_def_q(en->addr_inf, request_id, 1, &oid.id[oid.len - 1]); } else { /* internal object */ struct obj_def object_def; struct snmp_varbind *vb; msg_ps->state = SNMP_MSG_INTERNAL_GET_OBJDEF; mn->get_object_def(1, &oid.id[oid.len - 1], &object_def); LWIP_ASSERT("invalid length", object_def.v_len <= 0xff); vb = snmp_varbind_alloc(&oid, object_def.asn_type, (u8_t)object_def.v_len); if (vb != NULL) { msg_ps->state = SNMP_MSG_INTERNAL_GET_VALUE; mn->get_value(&object_def, object_def.v_len, vb->value); snmp_varbind_tail_add(&msg_ps->outvb, vb); msg_ps->state = SNMP_MSG_SEARCH_OBJ; msg_ps->vb_idx += 1; } else { LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_recv couldn't allocate outvb space\n")); snmp_error_response(msg_ps,SNMP_ES_TOOBIG); } } } if (mn == NULL) { /* mn == NULL, noSuchName */ snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME); } } if ((msg_ps->state == SNMP_MSG_SEARCH_OBJ) && (msg_ps->vb_idx == msg_ps->invb.count)) { snmp_ok_response(msg_ps); } } /** * Service an internal or external event for SNMP SET. * * @param request_id identifies requests from 0 to (SNMP_CONCURRENT_REQUESTS-1) * @param msg_ps points to the assosicated message process state */ static void snmp_msg_set_event(u8_t request_id, struct snmp_msg_pstat *msg_ps) { LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_set_event: msg_ps->state==%"U16_F"\n",(u16_t)msg_ps->state)); if (msg_ps->state == SNMP_MSG_EXTERNAL_GET_OBJDEF) { struct mib_external_node *en; struct snmp_name_ptr np; /* get_object_def() answer*/ en = msg_ps->ext_mib_node; np = msg_ps->ext_name_ptr; /* translate answer into a known lifeform */ en->get_object_def_a(request_id, np.ident_len, np.ident, &msg_ps->ext_object_def); if (msg_ps->ext_object_def.instance != MIB_OBJECT_NONE) { msg_ps->state = SNMP_MSG_EXTERNAL_SET_TEST; en->set_test_q(request_id, &msg_ps->ext_object_def); } else { en->get_object_def_pc(request_id, np.ident_len, np.ident); /* search failed, object id points to unknown object (nosuchname) */ snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME); } } else if (msg_ps->state == SNMP_MSG_EXTERNAL_SET_TEST) { struct mib_external_node *en; /* set_test() answer*/ en = msg_ps->ext_mib_node; if (msg_ps->ext_object_def.access & MIB_ACCESS_WRITE) { if ((msg_ps->ext_object_def.asn_type == msg_ps->vb_ptr->value_type) && (en->set_test_a(request_id,&msg_ps->ext_object_def, msg_ps->vb_ptr->value_len,msg_ps->vb_ptr->value) != 0)) { msg_ps->state = SNMP_MSG_SEARCH_OBJ; msg_ps->vb_idx += 1; } else { en->set_test_pc(request_id,&msg_ps->ext_object_def); /* bad value */ snmp_error_response(msg_ps,SNMP_ES_BADVALUE); } } else { en->set_test_pc(request_id,&msg_ps->ext_object_def); /* object not available for set */ snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME); } } else if (msg_ps->state == SNMP_MSG_EXTERNAL_GET_OBJDEF_S) { struct mib_external_node *en; struct snmp_name_ptr np; /* get_object_def() answer*/ en = msg_ps->ext_mib_node; np = msg_ps->ext_name_ptr; /* translate answer into a known lifeform */ en->get_object_def_a(request_id, np.ident_len, np.ident, &msg_ps->ext_object_def); if (msg_ps->ext_object_def.instance != MIB_OBJECT_NONE) { msg_ps->state = SNMP_MSG_EXTERNAL_SET_VALUE; en->set_value_q(request_id, &msg_ps->ext_object_def, msg_ps->vb_ptr->value_len,msg_ps->vb_ptr->value); } else { en->get_object_def_pc(request_id, np.ident_len, np.ident); /* set_value failed, object has disappeared for some odd reason?? */ snmp_error_response(msg_ps,SNMP_ES_GENERROR); } } else if (msg_ps->state == SNMP_MSG_EXTERNAL_SET_VALUE) { struct mib_external_node *en; /** set_value_a() */ en = msg_ps->ext_mib_node; en->set_value_a(request_id, &msg_ps->ext_object_def, msg_ps->vb_ptr->value_len, msg_ps->vb_ptr->value); /** @todo use set_value_pc() if toobig */ msg_ps->state = SNMP_MSG_INTERNAL_SET_VALUE; msg_ps->vb_idx += 1; } /* test all values before setting */ while ((msg_ps->state == SNMP_MSG_SEARCH_OBJ) && (msg_ps->vb_idx < msg_ps->invb.count)) { struct mib_node *mn; struct snmp_name_ptr np; if (msg_ps->vb_idx == 0) { msg_ps->vb_ptr = msg_ps->invb.head; } else { msg_ps->vb_ptr = msg_ps->vb_ptr->next; } /** test object identifier for .iso.org.dod.internet prefix */ if (snmp_iso_prefix_tst(msg_ps->vb_ptr->ident_len, msg_ps->vb_ptr->ident)) { mn = snmp_search_tree((struct mib_node*)&internet, msg_ps->vb_ptr->ident_len - 4, msg_ps->vb_ptr->ident + 4, &np); if (mn != NULL) { if (mn->node_type == MIB_NODE_EX) { /* external object */ struct mib_external_node *en = (struct mib_external_node*)mn; msg_ps->state = SNMP_MSG_EXTERNAL_GET_OBJDEF; /* save en && args in msg_ps!! */ msg_ps->ext_mib_node = en; msg_ps->ext_name_ptr = np; en->get_object_def_q(en->addr_inf, request_id, np.ident_len, np.ident); } else { /* internal object */ struct obj_def object_def; msg_ps->state = SNMP_MSG_INTERNAL_GET_OBJDEF; mn->get_object_def(np.ident_len, np.ident, &object_def); if (object_def.instance != MIB_OBJECT_NONE) { mn = mn; } else { /* search failed, object id points to unknown object (nosuchname) */ mn = NULL; } if (mn != NULL) { msg_ps->state = SNMP_MSG_INTERNAL_SET_TEST; if (object_def.access & MIB_ACCESS_WRITE) { if ((object_def.asn_type == msg_ps->vb_ptr->value_type) && (mn->set_test(&object_def,msg_ps->vb_ptr->value_len,msg_ps->vb_ptr->value) != 0)) { msg_ps->state = SNMP_MSG_SEARCH_OBJ; msg_ps->vb_idx += 1; } else { /* bad value */ snmp_error_response(msg_ps,SNMP_ES_BADVALUE); } } else { /* object not available for set */ snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME); } } } } } else { mn = NULL; } if (mn == NULL) { /* mn == NULL, noSuchName */ snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME); } } if ((msg_ps->state == SNMP_MSG_SEARCH_OBJ) && (msg_ps->vb_idx == msg_ps->invb.count)) { msg_ps->vb_idx = 0; msg_ps->state = SNMP_MSG_INTERNAL_SET_VALUE; } /* set all values "atomically" (be as "atomic" as possible) */ while ((msg_ps->state == SNMP_MSG_INTERNAL_SET_VALUE) && (msg_ps->vb_idx < msg_ps->invb.count)) { struct mib_node *mn; struct snmp_name_ptr np; if (msg_ps->vb_idx == 0) { msg_ps->vb_ptr = msg_ps->invb.head; } else { msg_ps->vb_ptr = msg_ps->vb_ptr->next; } /* skip iso prefix test, was done previously while settesting() */ mn = snmp_search_tree((struct mib_node*)&internet, msg_ps->vb_ptr->ident_len - 4, msg_ps->vb_ptr->ident + 4, &np); /* check if object is still available (e.g. external hot-plug thingy present?) */ if (mn != NULL) { if (mn->node_type == MIB_NODE_EX) { /* external object */ struct mib_external_node *en = (struct mib_external_node*)mn; msg_ps->state = SNMP_MSG_EXTERNAL_GET_OBJDEF_S; /* save en && args in msg_ps!! */ msg_ps->ext_mib_node = en; msg_ps->ext_name_ptr = np; en->get_object_def_q(en->addr_inf, request_id, np.ident_len, np.ident); } else { /* internal object */ struct obj_def object_def; msg_ps->state = SNMP_MSG_INTERNAL_GET_OBJDEF_S; mn->get_object_def(np.ident_len, np.ident, &object_def); msg_ps->state = SNMP_MSG_INTERNAL_SET_VALUE; mn->set_value(&object_def,msg_ps->vb_ptr->value_len,msg_ps->vb_ptr->value); msg_ps->vb_idx += 1; } } } if ((msg_ps->state == SNMP_MSG_INTERNAL_SET_VALUE) && (msg_ps->vb_idx == msg_ps->invb.count)) { /* simply echo the input if we can set it @todo do we need to return the actual value? e.g. if value is silently modified or behaves sticky? */ msg_ps->outvb = msg_ps->invb; msg_ps->invb.head = NULL; msg_ps->invb.tail = NULL; msg_ps->invb.count = 0; snmp_ok_response(msg_ps); } } /** * Handle one internal or external event. * Called for one async event. (recv external/private answer) * * @param request_id identifies requests from 0 to (SNMP_CONCURRENT_REQUESTS-1) */ void snmp_msg_event(u8_t request_id) { struct snmp_msg_pstat *msg_ps; if (request_id < SNMP_CONCURRENT_REQUESTS) { msg_ps = &msg_input_list[request_id]; if (msg_ps->rt == SNMP_ASN1_PDU_GET_NEXT_REQ) { snmp_msg_getnext_event(request_id, msg_ps); } else if (msg_ps->rt == SNMP_ASN1_PDU_GET_REQ) { snmp_msg_get_event(request_id, msg_ps); } else if(msg_ps->rt == SNMP_ASN1_PDU_SET_REQ) { snmp_msg_set_event(request_id, msg_ps); } } } /* lwIP UDP receive callback function */ static void snmp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port) { struct snmp_msg_pstat *msg_ps; u8_t req_idx; err_t err_ret; u16_t payload_len = p->tot_len; u16_t payload_ofs = 0; u16_t varbind_ofs = 0; /* suppress unused argument warning */ LWIP_UNUSED_ARG(arg); /* traverse input message process list, look for SNMP_MSG_EMPTY */ msg_ps = &msg_input_list[0]; req_idx = 0; while ((req_idx < SNMP_CONCURRENT_REQUESTS) && (msg_ps->state != SNMP_MSG_EMPTY)) { req_idx++; msg_ps++; } if (req_idx == SNMP_CONCURRENT_REQUESTS) { /* exceeding number of concurrent requests */ pbuf_free(p); return; } /* accepting request */ snmp_inc_snmpinpkts(); /* record used 'protocol control block' */ msg_ps->pcb = pcb; /* source address (network order) */ msg_ps->sip = *addr; /* source port (host order (lwIP oddity)) */ msg_ps->sp = port; /* check total length, version, community, pdu type */ err_ret = snmp_pdu_header_check(p, payload_ofs, payload_len, &varbind_ofs, msg_ps); /* Only accept requests and requests without error (be robust) */ /* Reject response and trap headers or error requests as input! */ if ((err_ret != ERR_OK) || ((msg_ps->rt != SNMP_ASN1_PDU_GET_REQ) && (msg_ps->rt != SNMP_ASN1_PDU_GET_NEXT_REQ) && (msg_ps->rt != SNMP_ASN1_PDU_SET_REQ)) || ((msg_ps->error_status != SNMP_ES_NOERROR) || (msg_ps->error_index != 0)) ) { /* header check failed drop request silently, do not return error! */ pbuf_free(p); LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_pdu_header_check() failed\n")); return; } LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_recv ok, community %s\n", msg_ps->community)); /* Builds a list of variable bindings. Copy the varbinds from the pbuf chain to glue them when these are divided over two or more pbuf's. */ err_ret = snmp_pdu_dec_varbindlist(p, varbind_ofs, &varbind_ofs, msg_ps); /* we've decoded the incoming message, release input msg now */ pbuf_free(p); if ((err_ret != ERR_OK) || (msg_ps->invb.count == 0)) { /* varbind-list decode failed, or varbind list empty. drop request silently, do not return error! (errors are only returned for a specific varbind failure) */ LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_pdu_dec_varbindlist() failed\n")); return; } msg_ps->error_status = SNMP_ES_NOERROR; msg_ps->error_index = 0; /* find object for each variable binding */ msg_ps->state = SNMP_MSG_SEARCH_OBJ; /* first variable binding from list to inspect */ msg_ps->vb_idx = 0; LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_recv varbind cnt=%"U16_F"\n",(u16_t)msg_ps->invb.count)); /* handle input event and as much objects as possible in one go */ snmp_msg_event(req_idx); } /** * Checks and decodes incoming SNMP message header, logs header errors. * * @param p points to pbuf chain of SNMP message (UDP payload) * @param ofs points to first octet of SNMP message * @param pdu_len the length of the UDP payload * @param ofs_ret returns the ofset of the variable bindings * @param m_stat points to the current message request state return * @return * - ERR_OK SNMP header is sane and accepted * - ERR_ARG SNMP header is either malformed or rejected */ static err_t snmp_pdu_header_check(struct pbuf *p, u16_t ofs, u16_t pdu_len, u16_t *ofs_ret, struct snmp_msg_pstat *m_stat) { err_t derr; u16_t len, ofs_base; u8_t len_octets; u8_t type; s32_t version; ofs_base = ofs; snmp_asn1_dec_type(p, ofs, &type); derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len); if ((derr != ERR_OK) || (pdu_len != (1 + len_octets + len)) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ))) { snmp_inc_snmpinasnparseerrs(); return ERR_ARG; } ofs += (1 + len_octets); snmp_asn1_dec_type(p, ofs, &type); derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len); if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG))) { /* can't decode or no integer (version) */ snmp_inc_snmpinasnparseerrs(); return ERR_ARG; } derr = snmp_asn1_dec_s32t(p, ofs + 1 + len_octets, len, &version); if (derr != ERR_OK) { /* can't decode */ snmp_inc_snmpinasnparseerrs(); return ERR_ARG; } if (version != 0) { /* not version 1 */ snmp_inc_snmpinbadversions(); return ERR_ARG; } ofs += (1 + len_octets + len); snmp_asn1_dec_type(p, ofs, &type); derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len); if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR))) { /* can't decode or no octet string (community) */ snmp_inc_snmpinasnparseerrs(); return ERR_ARG; } derr = snmp_asn1_dec_raw(p, ofs + 1 + len_octets, len, SNMP_COMMUNITY_STR_LEN, m_stat->community); if (derr != ERR_OK) { snmp_inc_snmpinasnparseerrs(); return ERR_ARG; } /* add zero terminator */ len = ((len < (SNMP_COMMUNITY_STR_LEN))?(len):(SNMP_COMMUNITY_STR_LEN)); m_stat->community[len] = 0; m_stat->com_strlen = (u8_t)len; if (strncmp(snmp_publiccommunity, (const char*)m_stat->community, SNMP_COMMUNITY_STR_LEN) != 0) { /** @todo: move this if we need to check more names */ snmp_inc_snmpinbadcommunitynames(); snmp_authfail_trap(); return ERR_ARG; } ofs += (1 + len_octets + len); snmp_asn1_dec_type(p, ofs, &type); derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len); if (derr != ERR_OK) { snmp_inc_snmpinasnparseerrs(); return ERR_ARG; } switch(type) { case (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_GET_REQ): /* GetRequest PDU */ snmp_inc_snmpingetrequests(); derr = ERR_OK; break; case (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_GET_NEXT_REQ): /* GetNextRequest PDU */ snmp_inc_snmpingetnexts(); derr = ERR_OK; break; case (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_GET_RESP): /* GetResponse PDU */ snmp_inc_snmpingetresponses(); derr = ERR_ARG; break; case (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_SET_REQ): /* SetRequest PDU */ snmp_inc_snmpinsetrequests(); derr = ERR_OK; break; case (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_TRAP): /* Trap PDU */ snmp_inc_snmpintraps(); derr = ERR_ARG; break; default: snmp_inc_snmpinasnparseerrs(); derr = ERR_ARG; break; } if (derr != ERR_OK) { /* unsupported input PDU for this agent (no parse error) */ return ERR_ARG; } m_stat->rt = type & 0x1F; ofs += (1 + len_octets); if (len != (pdu_len - (ofs - ofs_base))) { /* decoded PDU length does not equal actual payload length */ snmp_inc_snmpinasnparseerrs(); return ERR_ARG; } snmp_asn1_dec_type(p, ofs, &type); derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len); if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG))) { /* can't decode or no integer (request ID) */ snmp_inc_snmpinasnparseerrs(); return ERR_ARG; } derr = snmp_asn1_dec_s32t(p, ofs + 1 + len_octets, len, &m_stat->rid); if (derr != ERR_OK) { /* can't decode */ snmp_inc_snmpinasnparseerrs(); return ERR_ARG; } ofs += (1 + len_octets + len); snmp_asn1_dec_type(p, ofs, &type); derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len); if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG))) { /* can't decode or no integer (error-status) */ snmp_inc_snmpinasnparseerrs(); return ERR_ARG; } /* must be noError (0) for incoming requests. log errors for mib-2 completeness and for debug purposes */ derr = snmp_asn1_dec_s32t(p, ofs + 1 + len_octets, len, &m_stat->error_status); if (derr != ERR_OK) { /* can't decode */ snmp_inc_snmpinasnparseerrs(); return ERR_ARG; } switch (m_stat->error_status) { case SNMP_ES_NOERROR: /* nothing to do */ break; case SNMP_ES_TOOBIG: snmp_inc_snmpintoobigs(); break; case SNMP_ES_NOSUCHNAME: snmp_inc_snmpinnosuchnames(); break; case SNMP_ES_BADVALUE: snmp_inc_snmpinbadvalues(); break; case SNMP_ES_READONLY: snmp_inc_snmpinreadonlys(); break; case SNMP_ES_GENERROR: snmp_inc_snmpingenerrs(); break; default: LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_pdu_header_check(): unknown error_status: %d\n", m_stat->error_status)); break; } ofs += (1 + len_octets + len); snmp_asn1_dec_type(p, ofs, &type); derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len); if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG))) { /* can't decode or no integer (error-index) */ snmp_inc_snmpinasnparseerrs(); return ERR_ARG; } /* must be 0 for incoming requests. decode anyway to catch bad integers (and dirty tricks) */ derr = snmp_asn1_dec_s32t(p, ofs + 1 + len_octets, len, &m_stat->error_index); if (derr != ERR_OK) { /* can't decode */ snmp_inc_snmpinasnparseerrs(); return ERR_ARG; } ofs += (1 + len_octets + len); *ofs_ret = ofs; return ERR_OK; } static err_t snmp_pdu_dec_varbindlist(struct pbuf *p, u16_t ofs, u16_t *ofs_ret, struct snmp_msg_pstat *m_stat) { err_t derr; u16_t len, vb_len; u8_t len_octets; u8_t type; /* variable binding list */ snmp_asn1_dec_type(p, ofs, &type); derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &vb_len); if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ))) { snmp_inc_snmpinasnparseerrs(); return ERR_ARG; } ofs += (1 + len_octets); /* start with empty list */ m_stat->invb.count = 0; m_stat->invb.head = NULL; m_stat->invb.tail = NULL; while (vb_len > 0) { struct snmp_obj_id oid, oid_value; struct snmp_varbind *vb; snmp_asn1_dec_type(p, ofs, &type); derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len); if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ)) || (len == 0) || (len > vb_len)) { snmp_inc_snmpinasnparseerrs(); /* free varbinds (if available) */ snmp_varbind_list_free(&m_stat->invb); return ERR_ARG; } ofs += (1 + len_octets); vb_len -= (1 + len_octets); snmp_asn1_dec_type(p, ofs, &type); derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len); if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID))) { /* can't decode object name length */ snmp_inc_snmpinasnparseerrs(); /* free varbinds (if available) */ snmp_varbind_list_free(&m_stat->invb); return ERR_ARG; } derr = snmp_asn1_dec_oid(p, ofs + 1 + len_octets, len, &oid); if (derr != ERR_OK) { /* can't decode object name */ snmp_inc_snmpinasnparseerrs(); /* free varbinds (if available) */ snmp_varbind_list_free(&m_stat->invb); return ERR_ARG; } ofs += (1 + len_octets + len); vb_len -= (1 + len_octets + len); snmp_asn1_dec_type(p, ofs, &type); derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len); if (derr != ERR_OK) { /* can't decode object value length */ snmp_inc_snmpinasnparseerrs(); /* free varbinds (if available) */ snmp_varbind_list_free(&m_stat->invb); return ERR_ARG; } switch (type) { case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG): vb = snmp_varbind_alloc(&oid, type, sizeof(s32_t)); if (vb != NULL) { s32_t *vptr = (s32_t*)vb->value; derr = snmp_asn1_dec_s32t(p, ofs + 1 + len_octets, len, vptr); snmp_varbind_tail_add(&m_stat->invb, vb); } else { derr = ERR_ARG; } break; case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER): case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_GAUGE): case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_TIMETICKS): vb = snmp_varbind_alloc(&oid, type, sizeof(u32_t)); if (vb != NULL) { u32_t *vptr = (u32_t*)vb->value; derr = snmp_asn1_dec_u32t(p, ofs + 1 + len_octets, len, vptr); snmp_varbind_tail_add(&m_stat->invb, vb); } else { derr = ERR_ARG; } break; case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR): case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_OPAQUE): LWIP_ASSERT("invalid length", len <= 0xff); vb = snmp_varbind_alloc(&oid, type, (u8_t)len); if (vb != NULL) { derr = snmp_asn1_dec_raw(p, ofs + 1 + len_octets, len, vb->value_len, (u8_t*)vb->value); snmp_varbind_tail_add(&m_stat->invb, vb); } else { derr = ERR_ARG; } break; case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_NUL): vb = snmp_varbind_alloc(&oid, type, 0); if (vb != NULL) { snmp_varbind_tail_add(&m_stat->invb, vb); derr = ERR_OK; } else { derr = ERR_ARG; } break; case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID): derr = snmp_asn1_dec_oid(p, ofs + 1 + len_octets, len, &oid_value); if (derr == ERR_OK) { vb = snmp_varbind_alloc(&oid, type, oid_value.len * sizeof(s32_t)); if (vb != NULL) { u8_t i = oid_value.len; s32_t *vptr = (s32_t*)vb->value; while(i > 0) { i--; vptr[i] = oid_value.id[i]; } snmp_varbind_tail_add(&m_stat->invb, vb); derr = ERR_OK; } else { derr = ERR_ARG; } } break; case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR): if (len == 4) { /* must be exactly 4 octets! */ vb = snmp_varbind_alloc(&oid, type, 4); if (vb != NULL) { derr = snmp_asn1_dec_raw(p, ofs + 1 + len_octets, len, vb->value_len, (u8_t*)vb->value); snmp_varbind_tail_add(&m_stat->invb, vb); } else { derr = ERR_ARG; } } else { derr = ERR_ARG; } break; default: derr = ERR_ARG; break; } if (derr != ERR_OK) { snmp_inc_snmpinasnparseerrs(); /* free varbinds (if available) */ snmp_varbind_list_free(&m_stat->invb); return ERR_ARG; } ofs += (1 + len_octets + len); vb_len -= (1 + len_octets + len); } if (m_stat->rt == SNMP_ASN1_PDU_SET_REQ) { snmp_add_snmpintotalsetvars(m_stat->invb.count); } else { snmp_add_snmpintotalreqvars(m_stat->invb.count); } *ofs_ret = ofs; return ERR_OK; } struct snmp_varbind* snmp_varbind_alloc(struct snmp_obj_id *oid, u8_t type, u8_t len) { struct snmp_varbind *vb; vb = (struct snmp_varbind *)memp_malloc(MEMP_SNMP_VARBIND); if (vb != NULL) { u8_t i; vb->next = NULL; vb->prev = NULL; i = oid->len; vb->ident_len = i; if (i > 0) { LWIP_ASSERT("SNMP_MAX_TREE_DEPTH is configured too low", i <= SNMP_MAX_TREE_DEPTH); /* allocate array of s32_t for our object identifier */ vb->ident = (s32_t*)memp_malloc(MEMP_SNMP_VALUE); if (vb->ident == NULL) { LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_varbind_alloc: couldn't allocate ident value space\n")); memp_free(MEMP_SNMP_VARBIND, vb); return NULL; } while(i > 0) { i--; vb->ident[i] = oid->id[i]; } } else { /* i == 0, pass zero length object identifier */ vb->ident = NULL; } vb->value_type = type; vb->value_len = len; if (len > 0) { LWIP_ASSERT("SNMP_MAX_OCTET_STRING_LEN is configured too low", vb->value_len <= SNMP_MAX_VALUE_SIZE); /* allocate raw bytes for our object value */ vb->value = memp_malloc(MEMP_SNMP_VALUE); if (vb->value == NULL) { LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_varbind_alloc: couldn't allocate value space\n")); if (vb->ident != NULL) { memp_free(MEMP_SNMP_VALUE, vb->ident); } memp_free(MEMP_SNMP_VARBIND, vb); return NULL; } } else { /* ASN1_NUL type, or zero length ASN1_OC_STR */ vb->value = NULL; } } else { LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_varbind_alloc: couldn't allocate varbind space\n")); } return vb; } void snmp_varbind_free(struct snmp_varbind *vb) { if (vb->value != NULL ) { memp_free(MEMP_SNMP_VALUE, vb->value); } if (vb->ident != NULL ) { memp_free(MEMP_SNMP_VALUE, vb->ident); } memp_free(MEMP_SNMP_VARBIND, vb); } void snmp_varbind_list_free(struct snmp_varbind_root *root) { struct snmp_varbind *vb, *prev; vb = root->tail; while ( vb != NULL ) { prev = vb->prev; snmp_varbind_free(vb); vb = prev; } root->count = 0; root->head = NULL; root->tail = NULL; } void snmp_varbind_tail_add(struct snmp_varbind_root *root, struct snmp_varbind *vb) { if (root->count == 0) { /* add first varbind to list */ root->head = vb; root->tail = vb; } else { /* add nth varbind to list tail */ root->tail->next = vb; vb->prev = root->tail; root->tail = vb; } root->count += 1; } struct snmp_varbind* snmp_varbind_tail_remove(struct snmp_varbind_root *root) { struct snmp_varbind* vb; if (root->count > 0) { /* remove tail varbind */ vb = root->tail; root->tail = vb->prev; vb->prev->next = NULL; root->count -= 1; } else { /* nothing to remove */ vb = NULL; } return vb; } #endif /* LWIP_SNMP */ ocproxy-1.60/lwip/src/core/snmp/msg_out.c000066400000000000000000000533471303453231400204450ustar00rootroot00000000000000/** * @file * SNMP output message processing (RFC1157). * * Output responses and traps are build in two passes: * * Pass 0: iterate over the output message backwards to determine encoding lengths * Pass 1: the actual forward encoding of internal form into ASN1 * * The single-pass encoding method described by Comer & Stevens * requires extra buffer space and copying for reversal of the packet. * The buffer requirement can be prohibitively large for big payloads * (>= 484) therefore we use the two encoding passes. */ /* * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * Author: Christiaan Simons */ #include "lwip/opt.h" #if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */ #include "lwip/udp.h" #include "lwip/netif.h" #include "lwip/snmp.h" #include "lwip/snmp_asn1.h" #include "lwip/snmp_msg.h" struct snmp_trap_dst { /* destination IP address in network order */ ip_addr_t dip; /* set to 0 when disabled, >0 when enabled */ u8_t enable; }; struct snmp_trap_dst trap_dst[SNMP_TRAP_DESTINATIONS]; /** TRAP message structure */ struct snmp_msg_trap trap_msg; static u16_t snmp_resp_header_sum(struct snmp_msg_pstat *m_stat, u16_t vb_len); static u16_t snmp_trap_header_sum(struct snmp_msg_trap *m_trap, u16_t vb_len); static u16_t snmp_varbind_list_sum(struct snmp_varbind_root *root); static u16_t snmp_resp_header_enc(struct snmp_msg_pstat *m_stat, struct pbuf *p); static u16_t snmp_trap_header_enc(struct snmp_msg_trap *m_trap, struct pbuf *p); static u16_t snmp_varbind_list_enc(struct snmp_varbind_root *root, struct pbuf *p, u16_t ofs); /** * Sets enable switch for this trap destination. * @param dst_idx index in 0 .. SNMP_TRAP_DESTINATIONS-1 * @param enable switch if 0 destination is disabled >0 enabled. */ void snmp_trap_dst_enable(u8_t dst_idx, u8_t enable) { if (dst_idx < SNMP_TRAP_DESTINATIONS) { trap_dst[dst_idx].enable = enable; } } /** * Sets IPv4 address for this trap destination. * @param dst_idx index in 0 .. SNMP_TRAP_DESTINATIONS-1 * @param dst IPv4 address in host order. */ void snmp_trap_dst_ip_set(u8_t dst_idx, ip_addr_t *dst) { if (dst_idx < SNMP_TRAP_DESTINATIONS) { ip_addr_set(&trap_dst[dst_idx].dip, dst); } } /** * Sends a 'getresponse' message to the request originator. * * @param m_stat points to the current message request state source * @return ERR_OK when success, ERR_MEM if we're out of memory * * @note the caller is responsible for filling in outvb in the m_stat * and provide error-status and index (except for tooBig errors) ... */ err_t snmp_send_response(struct snmp_msg_pstat *m_stat) { struct snmp_varbind_root emptyvb = {NULL, NULL, 0, 0, 0}; struct pbuf *p; u16_t tot_len; err_t err; /* pass 0, calculate length fields */ tot_len = snmp_varbind_list_sum(&m_stat->outvb); tot_len = snmp_resp_header_sum(m_stat, tot_len); /* try allocating pbuf(s) for complete response */ p = pbuf_alloc(PBUF_TRANSPORT, tot_len, PBUF_POOL); if (p == NULL) { LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_snd_response() tooBig\n")); /* can't construct reply, return error-status tooBig */ m_stat->error_status = SNMP_ES_TOOBIG; m_stat->error_index = 0; /* pass 0, recalculate lengths, for empty varbind-list */ tot_len = snmp_varbind_list_sum(&emptyvb); tot_len = snmp_resp_header_sum(m_stat, tot_len); /* retry allocation once for header and empty varbind-list */ p = pbuf_alloc(PBUF_TRANSPORT, tot_len, PBUF_POOL); } if (p != NULL) { /* first pbuf alloc try or retry alloc success */ u16_t ofs; LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_snd_response() p != NULL\n")); /* pass 1, size error, encode packet ino the pbuf(s) */ ofs = snmp_resp_header_enc(m_stat, p); snmp_varbind_list_enc(&m_stat->outvb, p, ofs); switch (m_stat->error_status) { case SNMP_ES_NOERROR: /* nothing to do */ break; case SNMP_ES_TOOBIG: snmp_inc_snmpouttoobigs(); break; case SNMP_ES_NOSUCHNAME: snmp_inc_snmpoutnosuchnames(); break; case SNMP_ES_BADVALUE: snmp_inc_snmpoutbadvalues(); break; case SNMP_ES_GENERROR: snmp_inc_snmpoutgenerrs(); break; default: LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_send_response(): unknown error_status: %d\n", m_stat->error_status)); break; } snmp_inc_snmpoutgetresponses(); snmp_inc_snmpoutpkts(); /** @todo do we need separate rx and tx pcbs for threaded case? */ /** connect to the originating source */ udp_connect(m_stat->pcb, &m_stat->sip, m_stat->sp); err = udp_send(m_stat->pcb, p); if (err == ERR_MEM) { /** @todo release some memory, retry and return tooBig? tooMuchHassle? */ err = ERR_MEM; } else { err = ERR_OK; } /** disassociate remote address and port with this pcb */ udp_disconnect(m_stat->pcb); pbuf_free(p); LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_snd_response() done\n")); return err; } else { /* first pbuf alloc try or retry alloc failed very low on memory, couldn't return tooBig */ return ERR_MEM; } } /** * Sends an generic or enterprise specific trap message. * * @param generic_trap is the trap code * @param eoid points to enterprise object identifier * @param specific_trap used for enterprise traps when generic_trap == 6 * @return ERR_OK when success, ERR_MEM if we're out of memory * * @note the caller is responsible for filling in outvb in the trap_msg * @note the use of the enterpise identifier field * is per RFC1215. * Use .iso.org.dod.internet.mgmt.mib-2.snmp for generic traps * and .iso.org.dod.internet.private.enterprises.yourenterprise * (sysObjectID) for specific traps. */ err_t snmp_send_trap(s8_t generic_trap, struct snmp_obj_id *eoid, s32_t specific_trap) { struct snmp_trap_dst *td; struct netif *dst_if; ip_addr_t dst_ip; struct pbuf *p; u16_t i,tot_len; err_t err = ERR_OK; for (i=0, td = &trap_dst[0]; ienable != 0) && !ip_addr_isany(&td->dip)) { /* network order trap destination */ ip_addr_copy(trap_msg.dip, td->dip); /* lookup current source address for this dst */ dst_if = ip_route(&td->dip); if (dst_if != NULL) { ip_addr_copy(dst_ip, dst_if->ip_addr); /* @todo: what about IPv6? */ trap_msg.sip_raw[0] = ip4_addr1(&dst_ip); trap_msg.sip_raw[1] = ip4_addr2(&dst_ip); trap_msg.sip_raw[2] = ip4_addr3(&dst_ip); trap_msg.sip_raw[3] = ip4_addr4(&dst_ip); trap_msg.gen_trap = generic_trap; trap_msg.spc_trap = specific_trap; if (generic_trap == SNMP_GENTRAP_ENTERPRISESPC) { /* enterprise-Specific trap */ trap_msg.enterprise = eoid; } else { /* generic (MIB-II) trap */ snmp_get_snmpgrpid_ptr(&trap_msg.enterprise); } snmp_get_sysuptime(&trap_msg.ts); /* pass 0, calculate length fields */ tot_len = snmp_varbind_list_sum(&trap_msg.outvb); tot_len = snmp_trap_header_sum(&trap_msg, tot_len); /* allocate pbuf(s) */ p = pbuf_alloc(PBUF_TRANSPORT, tot_len, PBUF_POOL); if (p != NULL) { u16_t ofs; /* pass 1, encode packet ino the pbuf(s) */ ofs = snmp_trap_header_enc(&trap_msg, p); snmp_varbind_list_enc(&trap_msg.outvb, p, ofs); snmp_inc_snmpouttraps(); snmp_inc_snmpoutpkts(); /** send to the TRAP destination */ udp_sendto(trap_msg.pcb, p, &trap_msg.dip, SNMP_TRAP_PORT); pbuf_free(p); } else { err = ERR_MEM; } } else { /* routing error */ err = ERR_RTE; } } } return err; } void snmp_coldstart_trap(void) { trap_msg.outvb.head = NULL; trap_msg.outvb.tail = NULL; trap_msg.outvb.count = 0; snmp_send_trap(SNMP_GENTRAP_COLDSTART, NULL, 0); } void snmp_authfail_trap(void) { u8_t enable; snmp_get_snmpenableauthentraps(&enable); if (enable == 1) { trap_msg.outvb.head = NULL; trap_msg.outvb.tail = NULL; trap_msg.outvb.count = 0; snmp_send_trap(SNMP_GENTRAP_AUTHFAIL, NULL, 0); } } /** * Sums response header field lengths from tail to head and * returns resp_header_lengths for second encoding pass. * * @param vb_len varbind-list length * @param rhl points to returned header lengths * @return the required lenght for encoding the response header */ static u16_t snmp_resp_header_sum(struct snmp_msg_pstat *m_stat, u16_t vb_len) { u16_t tot_len; struct snmp_resp_header_lengths *rhl; rhl = &m_stat->rhl; tot_len = vb_len; snmp_asn1_enc_s32t_cnt(m_stat->error_index, &rhl->erridxlen); snmp_asn1_enc_length_cnt(rhl->erridxlen, &rhl->erridxlenlen); tot_len += 1 + rhl->erridxlenlen + rhl->erridxlen; snmp_asn1_enc_s32t_cnt(m_stat->error_status, &rhl->errstatlen); snmp_asn1_enc_length_cnt(rhl->errstatlen, &rhl->errstatlenlen); tot_len += 1 + rhl->errstatlenlen + rhl->errstatlen; snmp_asn1_enc_s32t_cnt(m_stat->rid, &rhl->ridlen); snmp_asn1_enc_length_cnt(rhl->ridlen, &rhl->ridlenlen); tot_len += 1 + rhl->ridlenlen + rhl->ridlen; rhl->pdulen = tot_len; snmp_asn1_enc_length_cnt(rhl->pdulen, &rhl->pdulenlen); tot_len += 1 + rhl->pdulenlen; rhl->comlen = m_stat->com_strlen; snmp_asn1_enc_length_cnt(rhl->comlen, &rhl->comlenlen); tot_len += 1 + rhl->comlenlen + rhl->comlen; snmp_asn1_enc_s32t_cnt(snmp_version, &rhl->verlen); snmp_asn1_enc_length_cnt(rhl->verlen, &rhl->verlenlen); tot_len += 1 + rhl->verlen + rhl->verlenlen; rhl->seqlen = tot_len; snmp_asn1_enc_length_cnt(rhl->seqlen, &rhl->seqlenlen); tot_len += 1 + rhl->seqlenlen; return tot_len; } /** * Sums trap header field lengths from tail to head and * returns trap_header_lengths for second encoding pass. * * @param vb_len varbind-list length * @param thl points to returned header lengths * @return the required lenght for encoding the trap header */ static u16_t snmp_trap_header_sum(struct snmp_msg_trap *m_trap, u16_t vb_len) { u16_t tot_len; struct snmp_trap_header_lengths *thl; thl = &m_trap->thl; tot_len = vb_len; snmp_asn1_enc_u32t_cnt(m_trap->ts, &thl->tslen); snmp_asn1_enc_length_cnt(thl->tslen, &thl->tslenlen); tot_len += 1 + thl->tslen + thl->tslenlen; snmp_asn1_enc_s32t_cnt(m_trap->spc_trap, &thl->strplen); snmp_asn1_enc_length_cnt(thl->strplen, &thl->strplenlen); tot_len += 1 + thl->strplen + thl->strplenlen; snmp_asn1_enc_s32t_cnt(m_trap->gen_trap, &thl->gtrplen); snmp_asn1_enc_length_cnt(thl->gtrplen, &thl->gtrplenlen); tot_len += 1 + thl->gtrplen + thl->gtrplenlen; thl->aaddrlen = 4; snmp_asn1_enc_length_cnt(thl->aaddrlen, &thl->aaddrlenlen); tot_len += 1 + thl->aaddrlen + thl->aaddrlenlen; snmp_asn1_enc_oid_cnt(m_trap->enterprise->len, &m_trap->enterprise->id[0], &thl->eidlen); snmp_asn1_enc_length_cnt(thl->eidlen, &thl->eidlenlen); tot_len += 1 + thl->eidlen + thl->eidlenlen; thl->pdulen = tot_len; snmp_asn1_enc_length_cnt(thl->pdulen, &thl->pdulenlen); tot_len += 1 + thl->pdulenlen; thl->comlen = sizeof(snmp_publiccommunity) - 1; snmp_asn1_enc_length_cnt(thl->comlen, &thl->comlenlen); tot_len += 1 + thl->comlenlen + thl->comlen; snmp_asn1_enc_s32t_cnt(snmp_version, &thl->verlen); snmp_asn1_enc_length_cnt(thl->verlen, &thl->verlenlen); tot_len += 1 + thl->verlen + thl->verlenlen; thl->seqlen = tot_len; snmp_asn1_enc_length_cnt(thl->seqlen, &thl->seqlenlen); tot_len += 1 + thl->seqlenlen; return tot_len; } /** * Sums varbind lengths from tail to head and * annotates lengths in varbind for second encoding pass. * * @param root points to the root of the variable binding list * @return the required lenght for encoding the variable bindings */ static u16_t snmp_varbind_list_sum(struct snmp_varbind_root *root) { struct snmp_varbind *vb; u32_t *uint_ptr; s32_t *sint_ptr; u16_t tot_len; tot_len = 0; vb = root->tail; while ( vb != NULL ) { /* encoded value lenght depends on type */ switch (vb->value_type) { case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG): sint_ptr = (s32_t*)vb->value; snmp_asn1_enc_s32t_cnt(*sint_ptr, &vb->vlen); break; case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER): case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_GAUGE): case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_TIMETICKS): uint_ptr = (u32_t*)vb->value; snmp_asn1_enc_u32t_cnt(*uint_ptr, &vb->vlen); break; case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR): case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_NUL): case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR): case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_OPAQUE): vb->vlen = vb->value_len; break; case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID): sint_ptr = (s32_t*)vb->value; snmp_asn1_enc_oid_cnt(vb->value_len / sizeof(s32_t), sint_ptr, &vb->vlen); break; default: /* unsupported type */ vb->vlen = 0; break; }; /* encoding length of value length field */ snmp_asn1_enc_length_cnt(vb->vlen, &vb->vlenlen); snmp_asn1_enc_oid_cnt(vb->ident_len, vb->ident, &vb->olen); snmp_asn1_enc_length_cnt(vb->olen, &vb->olenlen); vb->seqlen = 1 + vb->vlenlen + vb->vlen; vb->seqlen += 1 + vb->olenlen + vb->olen; snmp_asn1_enc_length_cnt(vb->seqlen, &vb->seqlenlen); /* varbind seq */ tot_len += 1 + vb->seqlenlen + vb->seqlen; vb = vb->prev; } /* varbind-list seq */ root->seqlen = tot_len; snmp_asn1_enc_length_cnt(root->seqlen, &root->seqlenlen); tot_len += 1 + root->seqlenlen; return tot_len; } /** * Encodes response header from head to tail. */ static u16_t snmp_resp_header_enc(struct snmp_msg_pstat *m_stat, struct pbuf *p) { u16_t ofs; ofs = 0; snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ)); ofs += 1; snmp_asn1_enc_length(p, ofs, m_stat->rhl.seqlen); ofs += m_stat->rhl.seqlenlen; snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG)); ofs += 1; snmp_asn1_enc_length(p, ofs, m_stat->rhl.verlen); ofs += m_stat->rhl.verlenlen; snmp_asn1_enc_s32t(p, ofs, m_stat->rhl.verlen, snmp_version); ofs += m_stat->rhl.verlen; snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR)); ofs += 1; snmp_asn1_enc_length(p, ofs, m_stat->rhl.comlen); ofs += m_stat->rhl.comlenlen; snmp_asn1_enc_raw(p, ofs, m_stat->rhl.comlen, m_stat->community); ofs += m_stat->rhl.comlen; snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_GET_RESP)); ofs += 1; snmp_asn1_enc_length(p, ofs, m_stat->rhl.pdulen); ofs += m_stat->rhl.pdulenlen; snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG)); ofs += 1; snmp_asn1_enc_length(p, ofs, m_stat->rhl.ridlen); ofs += m_stat->rhl.ridlenlen; snmp_asn1_enc_s32t(p, ofs, m_stat->rhl.ridlen, m_stat->rid); ofs += m_stat->rhl.ridlen; snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG)); ofs += 1; snmp_asn1_enc_length(p, ofs, m_stat->rhl.errstatlen); ofs += m_stat->rhl.errstatlenlen; snmp_asn1_enc_s32t(p, ofs, m_stat->rhl.errstatlen, m_stat->error_status); ofs += m_stat->rhl.errstatlen; snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG)); ofs += 1; snmp_asn1_enc_length(p, ofs, m_stat->rhl.erridxlen); ofs += m_stat->rhl.erridxlenlen; snmp_asn1_enc_s32t(p, ofs, m_stat->rhl.erridxlen, m_stat->error_index); ofs += m_stat->rhl.erridxlen; return ofs; } /** * Encodes trap header from head to tail. */ static u16_t snmp_trap_header_enc(struct snmp_msg_trap *m_trap, struct pbuf *p) { u16_t ofs; ofs = 0; snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ)); ofs += 1; snmp_asn1_enc_length(p, ofs, m_trap->thl.seqlen); ofs += m_trap->thl.seqlenlen; snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG)); ofs += 1; snmp_asn1_enc_length(p, ofs, m_trap->thl.verlen); ofs += m_trap->thl.verlenlen; snmp_asn1_enc_s32t(p, ofs, m_trap->thl.verlen, snmp_version); ofs += m_trap->thl.verlen; snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR)); ofs += 1; snmp_asn1_enc_length(p, ofs, m_trap->thl.comlen); ofs += m_trap->thl.comlenlen; snmp_asn1_enc_raw(p, ofs, m_trap->thl.comlen, (u8_t *)&snmp_publiccommunity[0]); ofs += m_trap->thl.comlen; snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_TRAP)); ofs += 1; snmp_asn1_enc_length(p, ofs, m_trap->thl.pdulen); ofs += m_trap->thl.pdulenlen; snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID)); ofs += 1; snmp_asn1_enc_length(p, ofs, m_trap->thl.eidlen); ofs += m_trap->thl.eidlenlen; snmp_asn1_enc_oid(p, ofs, m_trap->enterprise->len, &m_trap->enterprise->id[0]); ofs += m_trap->thl.eidlen; snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR)); ofs += 1; snmp_asn1_enc_length(p, ofs, m_trap->thl.aaddrlen); ofs += m_trap->thl.aaddrlenlen; snmp_asn1_enc_raw(p, ofs, m_trap->thl.aaddrlen, &m_trap->sip_raw[0]); ofs += m_trap->thl.aaddrlen; snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG)); ofs += 1; snmp_asn1_enc_length(p, ofs, m_trap->thl.gtrplen); ofs += m_trap->thl.gtrplenlen; snmp_asn1_enc_u32t(p, ofs, m_trap->thl.gtrplen, m_trap->gen_trap); ofs += m_trap->thl.gtrplen; snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG)); ofs += 1; snmp_asn1_enc_length(p, ofs, m_trap->thl.strplen); ofs += m_trap->thl.strplenlen; snmp_asn1_enc_u32t(p, ofs, m_trap->thl.strplen, m_trap->spc_trap); ofs += m_trap->thl.strplen; snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_TIMETICKS)); ofs += 1; snmp_asn1_enc_length(p, ofs, m_trap->thl.tslen); ofs += m_trap->thl.tslenlen; snmp_asn1_enc_u32t(p, ofs, m_trap->thl.tslen, m_trap->ts); ofs += m_trap->thl.tslen; return ofs; } /** * Encodes varbind list from head to tail. */ static u16_t snmp_varbind_list_enc(struct snmp_varbind_root *root, struct pbuf *p, u16_t ofs) { struct snmp_varbind *vb; s32_t *sint_ptr; u32_t *uint_ptr; u8_t *raw_ptr; snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ)); ofs += 1; snmp_asn1_enc_length(p, ofs, root->seqlen); ofs += root->seqlenlen; vb = root->head; while ( vb != NULL ) { snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ)); ofs += 1; snmp_asn1_enc_length(p, ofs, vb->seqlen); ofs += vb->seqlenlen; snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID)); ofs += 1; snmp_asn1_enc_length(p, ofs, vb->olen); ofs += vb->olenlen; snmp_asn1_enc_oid(p, ofs, vb->ident_len, &vb->ident[0]); ofs += vb->olen; snmp_asn1_enc_type(p, ofs, vb->value_type); ofs += 1; snmp_asn1_enc_length(p, ofs, vb->vlen); ofs += vb->vlenlen; switch (vb->value_type) { case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG): sint_ptr = (s32_t*)vb->value; snmp_asn1_enc_s32t(p, ofs, vb->vlen, *sint_ptr); break; case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER): case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_GAUGE): case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_TIMETICKS): uint_ptr = (u32_t*)vb->value; snmp_asn1_enc_u32t(p, ofs, vb->vlen, *uint_ptr); break; case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR): case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR): case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_OPAQUE): raw_ptr = (u8_t*)vb->value; snmp_asn1_enc_raw(p, ofs, vb->vlen, raw_ptr); break; case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_NUL): break; case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID): sint_ptr = (s32_t*)vb->value; snmp_asn1_enc_oid(p, ofs, vb->value_len / sizeof(s32_t), sint_ptr); break; default: /* unsupported type */ break; }; ofs += vb->vlen; vb = vb->next; } return ofs; } #endif /* LWIP_SNMP */ ocproxy-1.60/lwip/src/core/stats.c000066400000000000000000000145261303453231400171450ustar00rootroot00000000000000/** * @file * Statistics module * */ /* * Copyright (c) 2001-2004 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #include "lwip/opt.h" #if LWIP_STATS /* don't build if not configured for use in lwipopts.h */ #include "lwip/def.h" #include "lwip/stats.h" #include "lwip/mem.h" #include struct stats_ lwip_stats; void stats_init(void) { #ifdef LWIP_DEBUG #if MEMP_STATS const char * memp_names[] = { #define LWIP_MEMPOOL(name,num,size,desc) desc, #include "lwip/memp_std.h" }; int i; for (i = 0; i < MEMP_MAX; i++) { lwip_stats.memp[i].name = memp_names[i]; } #endif /* MEMP_STATS */ #if MEM_STATS lwip_stats.mem.name = "MEM"; #endif /* MEM_STATS */ #endif /* LWIP_DEBUG */ } #if LWIP_STATS_DISPLAY void stats_display_proto(struct stats_proto *proto, const char *name) { LWIP_PLATFORM_DIAG(("\n%s\n\t", name)); LWIP_PLATFORM_DIAG(("xmit: %"STAT_COUNTER_F"\n\t", proto->xmit)); LWIP_PLATFORM_DIAG(("recv: %"STAT_COUNTER_F"\n\t", proto->recv)); LWIP_PLATFORM_DIAG(("fw: %"STAT_COUNTER_F"\n\t", proto->fw)); LWIP_PLATFORM_DIAG(("drop: %"STAT_COUNTER_F"\n\t", proto->drop)); LWIP_PLATFORM_DIAG(("chkerr: %"STAT_COUNTER_F"\n\t", proto->chkerr)); LWIP_PLATFORM_DIAG(("lenerr: %"STAT_COUNTER_F"\n\t", proto->lenerr)); LWIP_PLATFORM_DIAG(("memerr: %"STAT_COUNTER_F"\n\t", proto->memerr)); LWIP_PLATFORM_DIAG(("rterr: %"STAT_COUNTER_F"\n\t", proto->rterr)); LWIP_PLATFORM_DIAG(("proterr: %"STAT_COUNTER_F"\n\t", proto->proterr)); LWIP_PLATFORM_DIAG(("opterr: %"STAT_COUNTER_F"\n\t", proto->opterr)); LWIP_PLATFORM_DIAG(("err: %"STAT_COUNTER_F"\n\t", proto->err)); LWIP_PLATFORM_DIAG(("cachehit: %"STAT_COUNTER_F"\n", proto->cachehit)); } #if IGMP_STATS || MLD6_STATS void stats_display_igmp(struct stats_igmp *igmp, const char *name) { LWIP_PLATFORM_DIAG(("\n%s\n\t", name)); LWIP_PLATFORM_DIAG(("xmit: %"STAT_COUNTER_F"\n\t", igmp->xmit)); LWIP_PLATFORM_DIAG(("recv: %"STAT_COUNTER_F"\n\t", igmp->recv)); LWIP_PLATFORM_DIAG(("drop: %"STAT_COUNTER_F"\n\t", igmp->drop)); LWIP_PLATFORM_DIAG(("chkerr: %"STAT_COUNTER_F"\n\t", igmp->chkerr)); LWIP_PLATFORM_DIAG(("lenerr: %"STAT_COUNTER_F"\n\t", igmp->lenerr)); LWIP_PLATFORM_DIAG(("memerr: %"STAT_COUNTER_F"\n\t", igmp->memerr)); LWIP_PLATFORM_DIAG(("proterr: %"STAT_COUNTER_F"\n\t", igmp->proterr)); LWIP_PLATFORM_DIAG(("rx_v1: %"STAT_COUNTER_F"\n\t", igmp->rx_v1)); LWIP_PLATFORM_DIAG(("rx_group: %"STAT_COUNTER_F"\n\t", igmp->rx_group)); LWIP_PLATFORM_DIAG(("rx_general: %"STAT_COUNTER_F"\n\t", igmp->rx_general)); LWIP_PLATFORM_DIAG(("rx_report: %"STAT_COUNTER_F"\n\t", igmp->rx_report)); LWIP_PLATFORM_DIAG(("tx_join: %"STAT_COUNTER_F"\n\t", igmp->tx_join)); LWIP_PLATFORM_DIAG(("tx_leave: %"STAT_COUNTER_F"\n\t", igmp->tx_leave)); LWIP_PLATFORM_DIAG(("tx_report: %"STAT_COUNTER_F"\n\t", igmp->tx_report)); } #endif /* IGMP_STATS || MLD6_STATS */ #if MEM_STATS || MEMP_STATS void stats_display_mem(struct stats_mem *mem, const char *name) { LWIP_PLATFORM_DIAG(("\nMEM %s\n\t", name)); LWIP_PLATFORM_DIAG(("avail: %"U32_F"\n\t", (u32_t)mem->avail)); LWIP_PLATFORM_DIAG(("used: %"U32_F"\n\t", (u32_t)mem->used)); LWIP_PLATFORM_DIAG(("max: %"U32_F"\n\t", (u32_t)mem->max)); LWIP_PLATFORM_DIAG(("err: %"U32_F"\n", (u32_t)mem->err)); } #if MEMP_STATS void stats_display_memp(struct stats_mem *mem, int index) { char * memp_names[] = { #define LWIP_MEMPOOL(name,num,size,desc) desc, #include "lwip/memp_std.h" }; if(index < MEMP_MAX) { stats_display_mem(mem, memp_names[index]); } } #endif /* MEMP_STATS */ #endif /* MEM_STATS || MEMP_STATS */ #if SYS_STATS void stats_display_sys(struct stats_sys *sys) { LWIP_PLATFORM_DIAG(("\nSYS\n\t")); LWIP_PLATFORM_DIAG(("sem.used: %"U32_F"\n\t", (u32_t)sys->sem.used)); LWIP_PLATFORM_DIAG(("sem.max: %"U32_F"\n\t", (u32_t)sys->sem.max)); LWIP_PLATFORM_DIAG(("sem.err: %"U32_F"\n\t", (u32_t)sys->sem.err)); LWIP_PLATFORM_DIAG(("mutex.used: %"U32_F"\n\t", (u32_t)sys->mutex.used)); LWIP_PLATFORM_DIAG(("mutex.max: %"U32_F"\n\t", (u32_t)sys->mutex.max)); LWIP_PLATFORM_DIAG(("mutex.err: %"U32_F"\n\t", (u32_t)sys->mutex.err)); LWIP_PLATFORM_DIAG(("mbox.used: %"U32_F"\n\t", (u32_t)sys->mbox.used)); LWIP_PLATFORM_DIAG(("mbox.max: %"U32_F"\n\t", (u32_t)sys->mbox.max)); LWIP_PLATFORM_DIAG(("mbox.err: %"U32_F"\n\t", (u32_t)sys->mbox.err)); } #endif /* SYS_STATS */ void stats_display(void) { s16_t i; LINK_STATS_DISPLAY(); ETHARP_STATS_DISPLAY(); IPFRAG_STATS_DISPLAY(); IP6_FRAG_STATS_DISPLAY(); IP_STATS_DISPLAY(); ND6_STATS_DISPLAY(); IP6_STATS_DISPLAY(); IGMP_STATS_DISPLAY(); MLD6_STATS_DISPLAY(); ICMP_STATS_DISPLAY(); ICMP6_STATS_DISPLAY(); UDP_STATS_DISPLAY(); TCP_STATS_DISPLAY(); MEM_STATS_DISPLAY(); for (i = 0; i < MEMP_MAX; i++) { MEMP_STATS_DISPLAY(i); } SYS_STATS_DISPLAY(); } #endif /* LWIP_STATS_DISPLAY */ #endif /* LWIP_STATS */ ocproxy-1.60/lwip/src/core/sys.c000066400000000000000000000042701303453231400166200ustar00rootroot00000000000000/** * @file * lwIP Operating System abstraction * */ /* * Copyright (c) 2001-2004 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #include "lwip/opt.h" #include "lwip/sys.h" /* Most of the functions defined in sys.h must be implemented in the * architecture-dependent file sys_arch.c */ #if !NO_SYS #ifndef sys_msleep /** * Sleep for some ms. Timeouts are NOT processed while sleeping. * * @param ms number of milliseconds to sleep */ void sys_msleep(u32_t ms) { if (ms > 0) { sys_sem_t delaysem; err_t err = sys_sem_new(&delaysem, 0); if (err == ERR_OK) { sys_arch_sem_wait(&delaysem, ms); sys_sem_free(&delaysem); } } } #endif /* sys_msleep */ #endif /* !NO_SYS */ ocproxy-1.60/lwip/src/core/tcp.c000066400000000000000000001604131303453231400165720ustar00rootroot00000000000000/** * @file * Transmission Control Protocol for IP * * This file contains common functions for the TCP implementation, such as functinos * for manipulating the data structures and the TCP timer functions. TCP functions * related to input and output is found in tcp_in.c and tcp_out.c respectively. * */ /* * Copyright (c) 2001-2004 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #include "lwip/opt.h" #if LWIP_TCP /* don't build if not configured for use in lwipopts.h */ #include "lwip/def.h" #include "lwip/mem.h" #include "lwip/memp.h" #include "lwip/snmp.h" #include "lwip/tcp.h" #include "lwip/tcp_impl.h" #include "lwip/debug.h" #include "lwip/stats.h" #include "lwip/ip6.h" #include "lwip/ip6_addr.h" #include "lwip/nd6.h" #include #ifndef TCP_LOCAL_PORT_RANGE_START /* From http://www.iana.org/assignments/port-numbers: "The Dynamic and/or Private Ports are those from 49152 through 65535" */ #define TCP_LOCAL_PORT_RANGE_START 0xc000 #define TCP_LOCAL_PORT_RANGE_END 0xffff #define TCP_ENSURE_LOCAL_PORT_RANGE(port) (((port) & ~TCP_LOCAL_PORT_RANGE_START) + TCP_LOCAL_PORT_RANGE_START) #endif #if LWIP_TCP_KEEPALIVE #define TCP_KEEP_DUR(pcb) ((pcb)->keep_cnt * (pcb)->keep_intvl) #define TCP_KEEP_INTVL(pcb) ((pcb)->keep_intvl) #else /* LWIP_TCP_KEEPALIVE */ #define TCP_KEEP_DUR(pcb) TCP_MAXIDLE #define TCP_KEEP_INTVL(pcb) TCP_KEEPINTVL_DEFAULT #endif /* LWIP_TCP_KEEPALIVE */ const char * const tcp_state_str[] = { "CLOSED", "LISTEN", "SYN_SENT", "SYN_RCVD", "ESTABLISHED", "FIN_WAIT_1", "FIN_WAIT_2", "CLOSE_WAIT", "CLOSING", "LAST_ACK", "TIME_WAIT" }; /* last local TCP port */ static u16_t tcp_port = TCP_LOCAL_PORT_RANGE_START; /* Incremented every coarse grained timer shot (typically every 500 ms). */ u32_t tcp_ticks; const u8_t tcp_backoff[13] = { 1, 2, 3, 4, 5, 6, 7, 7, 7, 7, 7, 7, 7}; /* Times per slowtmr hits */ const u8_t tcp_persist_backoff[7] = { 3, 6, 12, 24, 48, 96, 120 }; /* The TCP PCB lists. */ /** List of all TCP PCBs bound but not yet (connected || listening) */ struct tcp_pcb *tcp_bound_pcbs; /** List of all TCP PCBs in LISTEN state */ union tcp_listen_pcbs_t tcp_listen_pcbs; /** List of all TCP PCBs that are in a state in which * they accept or send data. */ struct tcp_pcb *tcp_active_pcbs; /** List of all TCP PCBs in TIME-WAIT state */ struct tcp_pcb *tcp_tw_pcbs; #define NUM_TCP_PCB_LISTS 4 #define NUM_TCP_PCB_LISTS_NO_TIME_WAIT 3 /** An array with all (non-temporary) PCB lists, mainly used for smaller code size */ struct tcp_pcb ** const tcp_pcb_lists[] = {&tcp_listen_pcbs.pcbs, &tcp_bound_pcbs, &tcp_active_pcbs, &tcp_tw_pcbs}; /** Only used for temporary storage. */ struct tcp_pcb *tcp_tmp_pcb; u8_t tcp_active_pcbs_changed; /** Timer counter to handle calling slow-timer from tcp_tmr() */ static u8_t tcp_timer; static u8_t tcp_timer_ctr; static u16_t tcp_new_port(void); /** * Initialize this module. */ void tcp_init(void) { #if LWIP_RANDOMIZE_INITIAL_LOCAL_PORTS && defined(LWIP_RAND) tcp_port = TCP_ENSURE_LOCAL_PORT_RANGE(LWIP_RAND()); #endif /* LWIP_RANDOMIZE_INITIAL_LOCAL_PORTS && defined(LWIP_RAND) */ } /** * Called periodically to dispatch TCP timers. */ void tcp_tmr(void) { /* Call tcp_fasttmr() every 250 ms */ tcp_fasttmr(); if (++tcp_timer & 1) { /* Call tcp_tmr() every 500 ms, i.e., every other timer tcp_tmr() is called. */ tcp_slowtmr(); } } /** * Closes the TX side of a connection held by the PCB. * For tcp_close(), a RST is sent if the application didn't receive all data * (tcp_recved() not called for all data passed to recv callback). * * Listening pcbs are freed and may not be referenced any more. * Connection pcbs are freed if not yet connected and may not be referenced * any more. If a connection is established (at least SYN received or in * a closing state), the connection is closed, and put in a closing state. * The pcb is then automatically freed in tcp_slowtmr(). It is therefore * unsafe to reference it. * * @param pcb the tcp_pcb to close * @return ERR_OK if connection has been closed * another err_t if closing failed and pcb is not freed */ static err_t tcp_close_shutdown(struct tcp_pcb *pcb, u8_t rst_on_unacked_data) { err_t err; if (rst_on_unacked_data && ((pcb->state == ESTABLISHED) || (pcb->state == CLOSE_WAIT))) { if ((pcb->refused_data != NULL) || (pcb->rcv_wnd != TCP_WND)) { /* Not all data received by application, send RST to tell the remote side about this. */ LWIP_ASSERT("pcb->flags & TF_RXCLOSED", pcb->flags & TF_RXCLOSED); /* don't call tcp_abort here: we must not deallocate the pcb since that might not be expected when calling tcp_close */ tcp_rst(pcb->snd_nxt, pcb->rcv_nxt, &pcb->local_ip, &pcb->remote_ip, pcb->local_port, pcb->remote_port, PCB_ISIPV6(pcb)); tcp_pcb_purge(pcb); TCP_RMV_ACTIVE(pcb); if (pcb->state == ESTABLISHED) { /* move to TIME_WAIT since we close actively */ pcb->state = TIME_WAIT; TCP_REG(&tcp_tw_pcbs, pcb); } else { /* CLOSE_WAIT: deallocate the pcb since we already sent a RST for it */ memp_free(MEMP_TCP_PCB, pcb); } return ERR_OK; } } switch (pcb->state) { case CLOSED: /* Closing a pcb in the CLOSED state might seem erroneous, * however, it is in this state once allocated and as yet unused * and the user needs some way to free it should the need arise. * Calling tcp_close() with a pcb that has already been closed, (i.e. twice) * or for a pcb that has been used and then entered the CLOSED state * is erroneous, but this should never happen as the pcb has in those cases * been freed, and so any remaining handles are bogus. */ err = ERR_OK; if (pcb->local_port != 0) { TCP_RMV(&tcp_bound_pcbs, pcb); } memp_free(MEMP_TCP_PCB, pcb); pcb = NULL; break; case LISTEN: err = ERR_OK; tcp_pcb_remove(&tcp_listen_pcbs.pcbs, pcb); memp_free(MEMP_TCP_PCB_LISTEN, pcb); pcb = NULL; break; case SYN_SENT: err = ERR_OK; TCP_PCB_REMOVE_ACTIVE(pcb); memp_free(MEMP_TCP_PCB, pcb); pcb = NULL; snmp_inc_tcpattemptfails(); break; case SYN_RCVD: err = tcp_send_fin(pcb); if (err == ERR_OK) { snmp_inc_tcpattemptfails(); pcb->state = FIN_WAIT_1; } break; case ESTABLISHED: err = tcp_send_fin(pcb); if (err == ERR_OK) { snmp_inc_tcpestabresets(); pcb->state = FIN_WAIT_1; } break; case CLOSE_WAIT: err = tcp_send_fin(pcb); if (err == ERR_OK) { snmp_inc_tcpestabresets(); pcb->state = LAST_ACK; } break; default: /* Has already been closed, do nothing. */ err = ERR_OK; pcb = NULL; break; } if (pcb != NULL && err == ERR_OK) { /* To ensure all data has been sent when tcp_close returns, we have to make sure tcp_output doesn't fail. Since we don't really have to ensure all data has been sent when tcp_close returns (unsent data is sent from tcp timer functions, also), we don't care for the return value of tcp_output for now. */ /* @todo: When implementing SO_LINGER, this must be changed somehow: If SOF_LINGER is set, the data should be sent and acked before close returns. This can only be valid for sequential APIs, not for the raw API. */ tcp_output(pcb); } return err; } /** * Closes the connection held by the PCB. * * Listening pcbs are freed and may not be referenced any more. * Connection pcbs are freed if not yet connected and may not be referenced * any more. If a connection is established (at least SYN received or in * a closing state), the connection is closed, and put in a closing state. * The pcb is then automatically freed in tcp_slowtmr(). It is therefore * unsafe to reference it (unless an error is returned). * * @param pcb the tcp_pcb to close * @return ERR_OK if connection has been closed * another err_t if closing failed and pcb is not freed */ err_t tcp_close(struct tcp_pcb *pcb) { #if TCP_DEBUG LWIP_DEBUGF(TCP_DEBUG, ("tcp_close: closing in ")); tcp_debug_print_state(pcb->state); #endif /* TCP_DEBUG */ if (pcb->state != LISTEN) { /* Set a flag not to receive any more data... */ pcb->flags |= TF_RXCLOSED; } /* ... and close */ return tcp_close_shutdown(pcb, 1); } /** * Causes all or part of a full-duplex connection of this PCB to be shut down. * This doesn't deallocate the PCB unless shutting down both sides! * Shutting down both sides is the same as calling tcp_close, so if it succeds, * the PCB should not be referenced any more. * * @param pcb PCB to shutdown * @param shut_rx shut down receive side if this is != 0 * @param shut_tx shut down send side if this is != 0 * @return ERR_OK if shutdown succeeded (or the PCB has already been shut down) * another err_t on error. */ err_t tcp_shutdown(struct tcp_pcb *pcb, int shut_rx, int shut_tx) { if (pcb->state == LISTEN) { return ERR_CONN; } if (shut_rx) { /* shut down the receive side: set a flag not to receive any more data... */ pcb->flags |= TF_RXCLOSED; if (shut_tx) { /* shutting down the tx AND rx side is the same as closing for the raw API */ return tcp_close_shutdown(pcb, 1); } /* ... and free buffered data */ if (pcb->refused_data != NULL) { pbuf_free(pcb->refused_data); pcb->refused_data = NULL; } } if (shut_tx) { /* This can't happen twice since if it succeeds, the pcb's state is changed. Only close in these states as the others directly deallocate the PCB */ switch (pcb->state) { case SYN_RCVD: case ESTABLISHED: case CLOSE_WAIT: return tcp_close_shutdown(pcb, shut_rx); default: /* Not (yet?) connected, cannot shutdown the TX side as that would bring us into CLOSED state, where the PCB is deallocated. */ return ERR_CONN; } } return ERR_OK; } /** * Abandons a connection and optionally sends a RST to the remote * host. Deletes the local protocol control block. This is done when * a connection is killed because of shortage of memory. * * @param pcb the tcp_pcb to abort * @param reset boolean to indicate whether a reset should be sent */ void tcp_abandon(struct tcp_pcb *pcb, int reset) { u32_t seqno, ackno; #if LWIP_CALLBACK_API tcp_err_fn errf; #endif /* LWIP_CALLBACK_API */ void *errf_arg; /* pcb->state LISTEN not allowed here */ LWIP_ASSERT("don't call tcp_abort/tcp_abandon for listen-pcbs", pcb->state != LISTEN); /* Figure out on which TCP PCB list we are, and remove us. If we are in an active state, call the receive function associated with the PCB with a NULL argument, and send an RST to the remote end. */ if (pcb->state == TIME_WAIT) { tcp_pcb_remove(&tcp_tw_pcbs, pcb); memp_free(MEMP_TCP_PCB, pcb); } else { int send_rst = reset && (pcb->state != CLOSED); seqno = pcb->snd_nxt; ackno = pcb->rcv_nxt; #if LWIP_CALLBACK_API errf = pcb->errf; #endif /* LWIP_CALLBACK_API */ errf_arg = pcb->callback_arg; TCP_PCB_REMOVE_ACTIVE(pcb); if (pcb->unacked != NULL) { tcp_segs_free(pcb->unacked); } if (pcb->unsent != NULL) { tcp_segs_free(pcb->unsent); } #if TCP_QUEUE_OOSEQ if (pcb->ooseq != NULL) { tcp_segs_free(pcb->ooseq); } #endif /* TCP_QUEUE_OOSEQ */ if (send_rst) { LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_abandon: sending RST\n")); tcp_rst(seqno, ackno, &pcb->local_ip, &pcb->remote_ip, pcb->local_port, pcb->remote_port, PCB_ISIPV6(pcb)); } memp_free(MEMP_TCP_PCB, pcb); TCP_EVENT_ERR(errf, errf_arg, ERR_ABRT); } } /** * Aborts the connection by sending a RST (reset) segment to the remote * host. The pcb is deallocated. This function never fails. * * ATTENTION: When calling this from one of the TCP callbacks, make * sure you always return ERR_ABRT (and never return ERR_ABRT otherwise * or you will risk accessing deallocated memory or memory leaks! * * @param pcb the tcp pcb to abort */ void tcp_abort(struct tcp_pcb *pcb) { tcp_abandon(pcb, 1); } /** * Binds the connection to a local portnumber and IP address. If the * IP address is not given (i.e., ipaddr == NULL), the IP address of * the outgoing network interface is used instead. * * @param pcb the tcp_pcb to bind (no check is done whether this pcb is * already bound!) * @param ipaddr the local ip address to bind to (use IP_ADDR_ANY to bind * to any local address * @param port the local port to bind to * @return ERR_USE if the port is already in use * ERR_VAL if bind failed because the PCB is not in a valid state * ERR_OK if bound */ err_t tcp_bind(struct tcp_pcb *pcb, ip_addr_t *ipaddr, u16_t port) { int i; int max_pcb_list = NUM_TCP_PCB_LISTS; struct tcp_pcb *cpcb; LWIP_ERROR("tcp_bind: can only bind in state CLOSED", pcb->state == CLOSED, return ERR_VAL); #if SO_REUSE /* Unless the REUSEADDR flag is set, we have to check the pcbs in TIME-WAIT state, also. We do not dump TIME_WAIT pcb's; they can still be matched by incoming packets using both local and remote IP addresses and ports to distinguish. */ if (ip_get_option(pcb, SOF_REUSEADDR)) { max_pcb_list = NUM_TCP_PCB_LISTS_NO_TIME_WAIT; } #endif /* SO_REUSE */ if (port == 0) { port = tcp_new_port(); if (port == 0) { return ERR_BUF; } } /* Check if the address already is in use (on all lists) */ for (i = 0; i < max_pcb_list; i++) { for(cpcb = *tcp_pcb_lists[i]; cpcb != NULL; cpcb = cpcb->next) { if (cpcb->local_port == port) { #if SO_REUSE /* Omit checking for the same port if both pcbs have REUSEADDR set. For SO_REUSEADDR, the duplicate-check for a 5-tuple is done in tcp_connect. */ if (!ip_get_option(pcb, SOF_REUSEADDR) || !ip_get_option(cpcb, SOF_REUSEADDR)) #endif /* SO_REUSE */ { /* @todo: check accept_any_ip_version */ if (IP_PCB_IPVER_EQ(pcb, cpcb) && (ipX_addr_isany(PCB_ISIPV6(pcb), &cpcb->local_ip) || ipX_addr_isany(PCB_ISIPV6(pcb), ip_2_ipX(ipaddr)) || ipX_addr_cmp(PCB_ISIPV6(pcb), &cpcb->local_ip, ip_2_ipX(ipaddr)))) { return ERR_USE; } } } } } if (!ipX_addr_isany(PCB_ISIPV6(pcb), ip_2_ipX(ipaddr))) { ipX_addr_set(PCB_ISIPV6(pcb), &pcb->local_ip, ip_2_ipX(ipaddr)); } pcb->local_port = port; TCP_REG(&tcp_bound_pcbs, pcb); LWIP_DEBUGF(TCP_DEBUG, ("tcp_bind: bind to port %"U16_F"\n", port)); return ERR_OK; } #if LWIP_CALLBACK_API /** * Default accept callback if no accept callback is specified by the user. */ static err_t tcp_accept_null(void *arg, struct tcp_pcb *pcb, err_t err) { LWIP_UNUSED_ARG(arg); LWIP_UNUSED_ARG(pcb); LWIP_UNUSED_ARG(err); return ERR_ABRT; } #endif /* LWIP_CALLBACK_API */ /** * Set the state of the connection to be LISTEN, which means that it * is able to accept incoming connections. The protocol control block * is reallocated in order to consume less memory. Setting the * connection to LISTEN is an irreversible process. * * @param pcb the original tcp_pcb * @param backlog the incoming connections queue limit * @return tcp_pcb used for listening, consumes less memory. * * @note The original tcp_pcb is freed. This function therefore has to be * called like this: * tpcb = tcp_listen(tpcb); */ struct tcp_pcb * tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog) { struct tcp_pcb_listen *lpcb; LWIP_UNUSED_ARG(backlog); LWIP_ERROR("tcp_listen: pcb already connected", pcb->state == CLOSED, return NULL); /* already listening? */ if (pcb->state == LISTEN) { return pcb; } #if SO_REUSE if (ip_get_option(pcb, SOF_REUSEADDR)) { /* Since SOF_REUSEADDR allows reusing a local address before the pcb's usage is declared (listen-/connection-pcb), we have to make sure now that this port is only used once for every local IP. */ for(lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) { if ((lpcb->local_port == pcb->local_port) && IP_PCB_IPVER_EQ(pcb, lpcb)) { if (ipX_addr_cmp(PCB_ISIPV6(pcb), &lpcb->local_ip, &pcb->local_ip)) { /* this address/port is already used */ return NULL; } } } } #endif /* SO_REUSE */ lpcb = (struct tcp_pcb_listen *)memp_malloc(MEMP_TCP_PCB_LISTEN); if (lpcb == NULL) { return NULL; } lpcb->callback_arg = pcb->callback_arg; lpcb->local_port = pcb->local_port; lpcb->state = LISTEN; lpcb->prio = pcb->prio; lpcb->so_options = pcb->so_options; ip_set_option(lpcb, SOF_ACCEPTCONN); lpcb->ttl = pcb->ttl; lpcb->tos = pcb->tos; #if LWIP_IPV6 PCB_ISIPV6(lpcb) = PCB_ISIPV6(pcb); lpcb->accept_any_ip_version = 0; #endif /* LWIP_IPV6 */ ipX_addr_copy(PCB_ISIPV6(pcb), lpcb->local_ip, pcb->local_ip); if (pcb->local_port != 0) { TCP_RMV(&tcp_bound_pcbs, pcb); } memp_free(MEMP_TCP_PCB, pcb); #if LWIP_CALLBACK_API lpcb->accept = tcp_accept_null; #endif /* LWIP_CALLBACK_API */ #if TCP_LISTEN_BACKLOG lpcb->accepts_pending = 0; lpcb->backlog = (backlog ? backlog : 1); #endif /* TCP_LISTEN_BACKLOG */ TCP_REG(&tcp_listen_pcbs.pcbs, (struct tcp_pcb *)lpcb); return (struct tcp_pcb *)lpcb; } #if LWIP_IPV6 /** * Same as tcp_listen_with_backlog, but allows to accept IPv4 and IPv6 * connections, if the pcb's local address is set to ANY. */ struct tcp_pcb * tcp_listen_dual_with_backlog(struct tcp_pcb *pcb, u8_t backlog) { struct tcp_pcb *lpcb; lpcb = tcp_listen_with_backlog(pcb, backlog); if ((lpcb != NULL) && ipX_addr_isany(PCB_ISIPV6(pcb), &pcb->local_ip)) { /* The default behavior is to accept connections on either * IPv4 or IPv6, if not bound. */ /* @see NETCONN_FLAG_IPV6_V6ONLY for changing this behavior */ ((struct tcp_pcb_listen*)lpcb)->accept_any_ip_version = 1; } return lpcb; } #endif /* LWIP_IPV6 */ /** * Update the state that tracks the available window space to advertise. * * Returns how much extra window would be advertised if we sent an * update now. */ u32_t tcp_update_rcv_ann_wnd(struct tcp_pcb *pcb) { u32_t new_right_edge = pcb->rcv_nxt + pcb->rcv_wnd; if (TCP_SEQ_GEQ(new_right_edge, pcb->rcv_ann_right_edge + LWIP_MIN((TCP_WND / 2), pcb->mss))) { /* we can advertise more window */ pcb->rcv_ann_wnd = pcb->rcv_wnd; return new_right_edge - pcb->rcv_ann_right_edge; } else { if (TCP_SEQ_GT(pcb->rcv_nxt, pcb->rcv_ann_right_edge)) { /* Can happen due to other end sending out of advertised window, * but within actual available (but not yet advertised) window */ pcb->rcv_ann_wnd = 0; } else { /* keep the right edge of window constant */ u32_t new_rcv_ann_wnd = pcb->rcv_ann_right_edge - pcb->rcv_nxt; #if !LWIP_WND_SCALE LWIP_ASSERT("new_rcv_ann_wnd <= 0xffff", new_rcv_ann_wnd <= 0xffff); #endif pcb->rcv_ann_wnd = (tcpwnd_size_t)new_rcv_ann_wnd; } return 0; } } /** * This function should be called by the application when it has * processed the data. The purpose is to advertise a larger window * when the data has been processed. * * @param pcb the tcp_pcb for which data is read * @param len the amount of bytes that have been read by the application */ void tcp_recved(struct tcp_pcb *pcb, u16_t len) { int wnd_inflation; /* pcb->state LISTEN not allowed here */ LWIP_ASSERT("don't call tcp_recved for listen-pcbs", pcb->state != LISTEN); pcb->rcv_wnd += len; if (pcb->rcv_wnd > TCP_WND) { pcb->rcv_wnd = TCP_WND; } else if(pcb->rcv_wnd == 0) { /* rcv_wnd overflowed */ if ((pcb->state == CLOSE_WAIT) || (pcb->state == LAST_ACK)) { /* In passive close, we allow this, since the FIN bit is added to rcv_wnd by the stack itself, since it is not mandatory for an application to call tcp_recved() for the FIN bit, but e.g. the netconn API does so. */ pcb->rcv_wnd = TCP_WND; } else { LWIP_ASSERT("tcp_recved: len wrapped rcv_wnd\n", 0); } } wnd_inflation = tcp_update_rcv_ann_wnd(pcb); /* If the change in the right edge of window is significant (default * watermark is TCP_WND/4), then send an explicit update now. * Otherwise wait for a packet to be sent in the normal course of * events (or more window to be available later) */ if (wnd_inflation >= TCP_WND_UPDATE_THRESHOLD) { tcp_ack_now(pcb); tcp_output(pcb); } LWIP_DEBUGF(TCP_DEBUG, ("tcp_recved: received %"U16_F" bytes, wnd %"U16_F" (%"U16_F").\n", len, pcb->rcv_wnd, TCP_WND - pcb->rcv_wnd)); } /** * Allocate a new local TCP port. * * @return a new (free) local TCP port number */ static u16_t tcp_new_port(void) { u8_t i; u16_t n = 0; struct tcp_pcb *pcb; again: if (tcp_port++ == TCP_LOCAL_PORT_RANGE_END) { tcp_port = TCP_LOCAL_PORT_RANGE_START; } /* Check all PCB lists. */ for (i = 0; i < NUM_TCP_PCB_LISTS; i++) { for(pcb = *tcp_pcb_lists[i]; pcb != NULL; pcb = pcb->next) { if (pcb->local_port == tcp_port) { if (++n > (TCP_LOCAL_PORT_RANGE_END - TCP_LOCAL_PORT_RANGE_START)) { return 0; } goto again; } } } return tcp_port; } /** * Connects to another host. The function given as the "connected" * argument will be called when the connection has been established. * * @param pcb the tcp_pcb used to establish the connection * @param ipaddr the remote ip address to connect to * @param port the remote tcp port to connect to * @param connected callback function to call when connected (on error, the err calback will be called) * @return ERR_VAL if invalid arguments are given * ERR_OK if connect request has been sent * other err_t values if connect request couldn't be sent */ err_t tcp_connect(struct tcp_pcb *pcb, ip_addr_t *ipaddr, u16_t port, tcp_connected_fn connected) { err_t ret; u32_t iss; u16_t old_local_port; LWIP_ERROR("tcp_connect: can only connect from state CLOSED", pcb->state == CLOSED, return ERR_ISCONN); LWIP_DEBUGF(TCP_DEBUG, ("tcp_connect to port %"U16_F"\n", port)); if (ipaddr != NULL) { ipX_addr_set(PCB_ISIPV6(pcb), &pcb->remote_ip, ip_2_ipX(ipaddr)); } else { return ERR_VAL; } pcb->remote_port = port; /* check if we have a route to the remote host */ if (ipX_addr_isany(PCB_ISIPV6(pcb), &pcb->local_ip)) { /* no local IP address set, yet. */ struct netif *netif; ipX_addr_t *local_ip; ipX_route_get_local_ipX(PCB_ISIPV6(pcb), &pcb->local_ip, &pcb->remote_ip, netif, local_ip); if ((netif == NULL) || (local_ip == NULL)) { /* Don't even try to send a SYN packet if we have no route since that will fail. */ return ERR_RTE; } /* Use the address as local address of the pcb. */ ipX_addr_copy(PCB_ISIPV6(pcb), pcb->local_ip, *local_ip); } old_local_port = pcb->local_port; if (pcb->local_port == 0) { pcb->local_port = tcp_new_port(); if (pcb->local_port == 0) { return ERR_BUF; } } #if SO_REUSE if (ip_get_option(pcb, SOF_REUSEADDR)) { /* Since SOF_REUSEADDR allows reusing a local address, we have to make sure now that the 5-tuple is unique. */ struct tcp_pcb *cpcb; int i; /* Don't check listen- and bound-PCBs, check active- and TIME-WAIT PCBs. */ for (i = 2; i < NUM_TCP_PCB_LISTS; i++) { for(cpcb = *tcp_pcb_lists[i]; cpcb != NULL; cpcb = cpcb->next) { if ((cpcb->local_port == pcb->local_port) && (cpcb->remote_port == port) && IP_PCB_IPVER_EQ(cpcb, pcb) && ipX_addr_cmp(PCB_ISIPV6(pcb), &cpcb->local_ip, &pcb->local_ip) && ipX_addr_cmp(PCB_ISIPV6(pcb), &cpcb->remote_ip, ip_2_ipX(ipaddr))) { /* linux returns EISCONN here, but ERR_USE should be OK for us */ return ERR_USE; } } } } #endif /* SO_REUSE */ iss = tcp_next_iss(); pcb->rcv_nxt = 0; pcb->snd_nxt = iss; pcb->lastack = iss - 1; pcb->snd_lbb = iss - 1; pcb->rcv_wnd = TCP_WND; pcb->rcv_ann_wnd = TCP_WND; pcb->rcv_ann_right_edge = pcb->rcv_nxt; pcb->snd_wnd = TCP_WND; /* As initial send MSS, we use TCP_MSS but limit it to 536. The send MSS is updated when an MSS option is received. */ pcb->mss = (TCP_MSS > 536) ? 536 : TCP_MSS; #if TCP_CALCULATE_EFF_SEND_MSS pcb->mss = tcp_eff_send_mss(pcb->mss, &pcb->local_ip, &pcb->remote_ip, PCB_ISIPV6(pcb)); #endif /* TCP_CALCULATE_EFF_SEND_MSS */ pcb->cwnd = 1; pcb->ssthresh = pcb->mss * 10; #if LWIP_CALLBACK_API pcb->connected = connected; #else /* LWIP_CALLBACK_API */ LWIP_UNUSED_ARG(connected); #endif /* LWIP_CALLBACK_API */ /* Send a SYN together with the MSS option. */ ret = tcp_enqueue_flags(pcb, TCP_SYN); if (ret == ERR_OK) { /* SYN segment was enqueued, changed the pcbs state now */ pcb->state = SYN_SENT; if (old_local_port != 0) { TCP_RMV(&tcp_bound_pcbs, pcb); } TCP_REG_ACTIVE(pcb); snmp_inc_tcpactiveopens(); tcp_output(pcb); } return ret; } /** * Called every 500 ms and implements the retransmission timer and the timer that * removes PCBs that have been in TIME-WAIT for enough time. It also increments * various timers such as the inactivity timer in each PCB. * * Automatically called from tcp_tmr(). */ void tcp_slowtmr(void) { struct tcp_pcb *pcb, *prev; tcpwnd_size_t eff_wnd; u8_t pcb_remove; /* flag if a PCB should be removed */ u8_t pcb_reset; /* flag if a RST should be sent when removing */ err_t err; err = ERR_OK; ++tcp_ticks; ++tcp_timer_ctr; tcp_slowtmr_start: /* Steps through all of the active PCBs. */ prev = NULL; pcb = tcp_active_pcbs; if (pcb == NULL) { LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: no active pcbs\n")); } while (pcb != NULL) { LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: processing active pcb\n")); LWIP_ASSERT("tcp_slowtmr: active pcb->state != CLOSED\n", pcb->state != CLOSED); LWIP_ASSERT("tcp_slowtmr: active pcb->state != LISTEN\n", pcb->state != LISTEN); LWIP_ASSERT("tcp_slowtmr: active pcb->state != TIME-WAIT\n", pcb->state != TIME_WAIT); if (pcb->last_timer == tcp_timer_ctr) { /* skip this pcb, we have already processed it */ pcb = pcb->next; continue; } pcb->last_timer = tcp_timer_ctr; pcb_remove = 0; pcb_reset = 0; if (pcb->state == SYN_SENT && pcb->nrtx == TCP_SYNMAXRTX) { ++pcb_remove; LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: max SYN retries reached\n")); } else if (pcb->nrtx == TCP_MAXRTX) { ++pcb_remove; LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: max DATA retries reached\n")); } else { if (pcb->persist_backoff > 0) { /* If snd_wnd is zero, use persist timer to send 1 byte probes * instead of using the standard retransmission mechanism. */ pcb->persist_cnt++; if (pcb->persist_cnt >= tcp_persist_backoff[pcb->persist_backoff-1]) { pcb->persist_cnt = 0; if (pcb->persist_backoff < sizeof(tcp_persist_backoff)) { pcb->persist_backoff++; } tcp_zero_window_probe(pcb); } } else { /* Increase the retransmission timer if it is running */ if(pcb->rtime >= 0) { ++pcb->rtime; } if (pcb->unacked != NULL && pcb->rtime >= pcb->rto) { /* Time for a retransmission. */ LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_slowtmr: rtime %"S16_F " pcb->rto %"S16_F"\n", pcb->rtime, pcb->rto)); /* Double retransmission time-out unless we are trying to * connect to somebody (i.e., we are in SYN_SENT). */ if (pcb->state != SYN_SENT) { pcb->rto = ((pcb->sa >> 3) + pcb->sv) << tcp_backoff[pcb->nrtx]; } /* Reset the retransmission timer. */ pcb->rtime = 0; /* Reduce congestion window and ssthresh. */ eff_wnd = LWIP_MIN(pcb->cwnd, pcb->snd_wnd); pcb->ssthresh = eff_wnd >> 1; if (pcb->ssthresh < (tcpwnd_size_t)(pcb->mss << 1)) { pcb->ssthresh = (pcb->mss << 1); } pcb->cwnd = pcb->mss; LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_slowtmr: cwnd %"TCPWNDSIZE_F " ssthresh %"TCPWNDSIZE_F"\n", pcb->cwnd, pcb->ssthresh)); /* The following needs to be called AFTER cwnd is set to one mss - STJ */ tcp_rexmit_rto(pcb); } } } /* Check if this PCB has stayed too long in FIN-WAIT-2 */ if (pcb->state == FIN_WAIT_2) { /* If this PCB is in FIN_WAIT_2 because of SHUT_WR don't let it time out. */ if (pcb->flags & TF_RXCLOSED) { /* PCB was fully closed (either through close() or SHUT_RDWR): normal FIN-WAIT timeout handling. */ if ((u32_t)(tcp_ticks - pcb->tmr) > TCP_FIN_WAIT_TIMEOUT / TCP_SLOW_INTERVAL) { ++pcb_remove; LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: removing pcb stuck in FIN-WAIT-2\n")); } } } /* Check if KEEPALIVE should be sent */ if(ip_get_option(pcb, SOF_KEEPALIVE) && ((pcb->state == ESTABLISHED) || (pcb->state == CLOSE_WAIT))) { if((u32_t)(tcp_ticks - pcb->tmr) > (pcb->keep_idle + TCP_KEEP_DUR(pcb)) / TCP_SLOW_INTERVAL) { LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: KEEPALIVE timeout. Aborting connection to ")); ipX_addr_debug_print(PCB_ISIPV6(pcb), TCP_DEBUG, &pcb->remote_ip); LWIP_DEBUGF(TCP_DEBUG, ("\n")); ++pcb_remove; ++pcb_reset; } else if((u32_t)(tcp_ticks - pcb->tmr) > (pcb->keep_idle + pcb->keep_cnt_sent * TCP_KEEP_INTVL(pcb)) / TCP_SLOW_INTERVAL) { tcp_keepalive(pcb); pcb->keep_cnt_sent++; } } /* If this PCB has queued out of sequence data, but has been inactive for too long, will drop the data (it will eventually be retransmitted). */ #if TCP_QUEUE_OOSEQ if (pcb->ooseq != NULL && (u32_t)tcp_ticks - pcb->tmr >= pcb->rto * TCP_OOSEQ_TIMEOUT) { tcp_segs_free(pcb->ooseq); pcb->ooseq = NULL; LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_slowtmr: dropping OOSEQ queued data\n")); } #endif /* TCP_QUEUE_OOSEQ */ /* Check if this PCB has stayed too long in SYN-RCVD */ if (pcb->state == SYN_RCVD) { if ((u32_t)(tcp_ticks - pcb->tmr) > TCP_SYN_RCVD_TIMEOUT / TCP_SLOW_INTERVAL) { ++pcb_remove; LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: removing pcb stuck in SYN-RCVD\n")); } } /* Check if this PCB has stayed too long in LAST-ACK */ if (pcb->state == LAST_ACK) { if ((u32_t)(tcp_ticks - pcb->tmr) > 2 * TCP_MSL / TCP_SLOW_INTERVAL) { ++pcb_remove; LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: removing pcb stuck in LAST-ACK\n")); } } /* If the PCB should be removed, do it. */ if (pcb_remove) { struct tcp_pcb *pcb2; tcp_err_fn err_fn; void *err_arg; tcp_pcb_purge(pcb); /* Remove PCB from tcp_active_pcbs list. */ if (prev != NULL) { LWIP_ASSERT("tcp_slowtmr: middle tcp != tcp_active_pcbs", pcb != tcp_active_pcbs); prev->next = pcb->next; } else { /* This PCB was the first. */ LWIP_ASSERT("tcp_slowtmr: first pcb == tcp_active_pcbs", tcp_active_pcbs == pcb); tcp_active_pcbs = pcb->next; } if (pcb_reset) { tcp_rst(pcb->snd_nxt, pcb->rcv_nxt, &pcb->local_ip, &pcb->remote_ip, pcb->local_port, pcb->remote_port, PCB_ISIPV6(pcb)); } err_fn = pcb->errf; err_arg = pcb->callback_arg; pcb2 = pcb; pcb = pcb->next; memp_free(MEMP_TCP_PCB, pcb2); tcp_active_pcbs_changed = 0; TCP_EVENT_ERR(err_fn, err_arg, ERR_ABRT); if (tcp_active_pcbs_changed) { goto tcp_slowtmr_start; } } else { /* get the 'next' element now and work with 'prev' below (in case of abort) */ prev = pcb; pcb = pcb->next; /* We check if we should poll the connection. */ ++prev->polltmr; if (prev->polltmr >= prev->pollinterval) { prev->polltmr = 0; LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: polling application\n")); tcp_active_pcbs_changed = 0; TCP_EVENT_POLL(prev, err); if (tcp_active_pcbs_changed) { goto tcp_slowtmr_start; } /* if err == ERR_ABRT, 'prev' is already deallocated */ if (err == ERR_OK) { tcp_output(prev); } } } } /* Steps through all of the TIME-WAIT PCBs. */ prev = NULL; pcb = tcp_tw_pcbs; while (pcb != NULL) { LWIP_ASSERT("tcp_slowtmr: TIME-WAIT pcb->state == TIME-WAIT", pcb->state == TIME_WAIT); pcb_remove = 0; /* Check if this PCB has stayed long enough in TIME-WAIT */ if ((u32_t)(tcp_ticks - pcb->tmr) > 2 * TCP_MSL / TCP_SLOW_INTERVAL) { ++pcb_remove; } /* If the PCB should be removed, do it. */ if (pcb_remove) { struct tcp_pcb *pcb2; tcp_pcb_purge(pcb); /* Remove PCB from tcp_tw_pcbs list. */ if (prev != NULL) { LWIP_ASSERT("tcp_slowtmr: middle tcp != tcp_tw_pcbs", pcb != tcp_tw_pcbs); prev->next = pcb->next; } else { /* This PCB was the first. */ LWIP_ASSERT("tcp_slowtmr: first pcb == tcp_tw_pcbs", tcp_tw_pcbs == pcb); tcp_tw_pcbs = pcb->next; } pcb2 = pcb; pcb = pcb->next; memp_free(MEMP_TCP_PCB, pcb2); } else { prev = pcb; pcb = pcb->next; } } } /** * Is called every TCP_FAST_INTERVAL (250 ms) and process data previously * "refused" by upper layer (application) and sends delayed ACKs. * * Automatically called from tcp_tmr(). */ void tcp_fasttmr(void) { struct tcp_pcb *pcb; ++tcp_timer_ctr; tcp_fasttmr_start: pcb = tcp_active_pcbs; while(pcb != NULL) { if (pcb->last_timer != tcp_timer_ctr) { struct tcp_pcb *next; pcb->last_timer = tcp_timer_ctr; /* send delayed ACKs */ if (pcb->flags & TF_ACK_DELAY) { LWIP_DEBUGF(TCP_DEBUG, ("tcp_fasttmr: delayed ACK\n")); tcp_ack_now(pcb); tcp_output(pcb); pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW); } next = pcb->next; /* If there is data which was previously "refused" by upper layer */ if (pcb->refused_data != NULL) { tcp_active_pcbs_changed = 0; tcp_process_refused_data(pcb); if (tcp_active_pcbs_changed) { /* application callback has changed the pcb list: restart the loop */ goto tcp_fasttmr_start; } } pcb = next; } else { pcb = pcb->next; } } } /** Pass pcb->refused_data to the recv callback */ err_t tcp_process_refused_data(struct tcp_pcb *pcb) { #if TCP_QUEUE_OOSEQ && LWIP_WND_SCALE struct pbuf *rest; while (pcb->refused_data != NULL) #endif /* TCP_QUEUE_OOSEQ && LWIP_WND_SCALE */ { err_t err; u8_t refused_flags = pcb->refused_data->flags; /* set pcb->refused_data to NULL in case the callback frees it and then closes the pcb */ struct pbuf *refused_data = pcb->refused_data; #if TCP_QUEUE_OOSEQ && LWIP_WND_SCALE pbuf_split_64k(refused_data, &rest); pcb->refused_data = rest; #else /* TCP_QUEUE_OOSEQ && LWIP_WND_SCALE */ pcb->refused_data = NULL; #endif /* TCP_QUEUE_OOSEQ && LWIP_WND_SCALE */ /* Notify again application with data previously received. */ LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: notify kept packet\n")); TCP_EVENT_RECV(pcb, refused_data, ERR_OK, err); if (err == ERR_OK) { /* did refused_data include a FIN? */ if (refused_flags & PBUF_FLAG_TCP_FIN #if TCP_QUEUE_OOSEQ && LWIP_WND_SCALE && (rest == NULL) #endif /* TCP_QUEUE_OOSEQ && LWIP_WND_SCALE */ ) { /* correct rcv_wnd as the application won't call tcp_recved() for the FIN's seqno */ if (pcb->rcv_wnd != TCP_WND) { pcb->rcv_wnd++; } TCP_EVENT_CLOSED(pcb, err); if (err == ERR_ABRT) { return ERR_ABRT; } } } else if (err == ERR_ABRT) { /* if err == ERR_ABRT, 'pcb' is already deallocated */ /* Drop incoming packets because pcb is "full" (only if the incoming segment contains data). */ LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: drop incoming packets, because pcb is \"full\"\n")); return ERR_ABRT; } else { /* data is still refused, pbuf is still valid (go on for ACK-only packets) */ #if TCP_QUEUE_OOSEQ && LWIP_WND_SCALE if (rest != NULL) { pbuf_cat(refused_data, rest); } #endif /* TCP_QUEUE_OOSEQ && LWIP_WND_SCALE */ pcb->refused_data = refused_data; return ERR_INPROGRESS; } } return ERR_OK; } /** * Deallocates a list of TCP segments (tcp_seg structures). * * @param seg tcp_seg list of TCP segments to free */ void tcp_segs_free(struct tcp_seg *seg) { while (seg != NULL) { struct tcp_seg *next = seg->next; tcp_seg_free(seg); seg = next; } } /** * Frees a TCP segment (tcp_seg structure). * * @param seg single tcp_seg to free */ void tcp_seg_free(struct tcp_seg *seg) { if (seg != NULL) { if (seg->p != NULL) { pbuf_free(seg->p); #if TCP_DEBUG seg->p = NULL; #endif /* TCP_DEBUG */ } memp_free(MEMP_TCP_SEG, seg); } } /** * Sets the priority of a connection. * * @param pcb the tcp_pcb to manipulate * @param prio new priority */ void tcp_setprio(struct tcp_pcb *pcb, u8_t prio) { pcb->prio = prio; } #if TCP_QUEUE_OOSEQ /** * Returns a copy of the given TCP segment. * The pbuf and data are not copied, only the pointers * * @param seg the old tcp_seg * @return a copy of seg */ struct tcp_seg * tcp_seg_copy(struct tcp_seg *seg) { struct tcp_seg *cseg; cseg = (struct tcp_seg *)memp_malloc(MEMP_TCP_SEG); if (cseg == NULL) { return NULL; } SMEMCPY((u8_t *)cseg, (const u8_t *)seg, sizeof(struct tcp_seg)); pbuf_ref(cseg->p); return cseg; } #endif /* TCP_QUEUE_OOSEQ */ #if LWIP_CALLBACK_API /** * Default receive callback that is called if the user didn't register * a recv callback for the pcb. */ err_t tcp_recv_null(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err) { LWIP_UNUSED_ARG(arg); if (p != NULL) { tcp_recved(pcb, p->tot_len); pbuf_free(p); } else if (err == ERR_OK) { return tcp_close(pcb); } return ERR_OK; } #endif /* LWIP_CALLBACK_API */ /** * Kills the oldest active connection that has the same or lower priority than * 'prio'. * * @param prio minimum priority */ static void tcp_kill_prio(u8_t prio) { struct tcp_pcb *pcb, *inactive; u32_t inactivity; u8_t mprio; mprio = TCP_PRIO_MAX; /* We kill the oldest active connection that has lower priority than prio. */ inactivity = 0; inactive = NULL; for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) { if (pcb->prio <= prio && pcb->prio <= mprio && (u32_t)(tcp_ticks - pcb->tmr) >= inactivity) { inactivity = tcp_ticks - pcb->tmr; inactive = pcb; mprio = pcb->prio; } } if (inactive != NULL) { LWIP_DEBUGF(TCP_DEBUG, ("tcp_kill_prio: killing oldest PCB %p (%"S32_F")\n", (void *)inactive, inactivity)); tcp_abort(inactive); } } /** * Kills the oldest connection that is in TIME_WAIT state. * Called from tcp_alloc() if no more connections are available. */ static void tcp_kill_timewait(void) { struct tcp_pcb *pcb, *inactive; u32_t inactivity; inactivity = 0; inactive = NULL; /* Go through the list of TIME_WAIT pcbs and get the oldest pcb. */ for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) { if ((u32_t)(tcp_ticks - pcb->tmr) >= inactivity) { inactivity = tcp_ticks - pcb->tmr; inactive = pcb; } } if (inactive != NULL) { LWIP_DEBUGF(TCP_DEBUG, ("tcp_kill_timewait: killing oldest TIME-WAIT PCB %p (%"S32_F")\n", (void *)inactive, inactivity)); tcp_abort(inactive); } } /** * Allocate a new tcp_pcb structure. * * @param prio priority for the new pcb * @return a new tcp_pcb that initially is in state CLOSED */ struct tcp_pcb * tcp_alloc(u8_t prio) { struct tcp_pcb *pcb; u32_t iss; pcb = (struct tcp_pcb *)memp_malloc(MEMP_TCP_PCB); if (pcb == NULL) { /* Try killing oldest connection in TIME-WAIT. */ LWIP_DEBUGF(TCP_DEBUG, ("tcp_alloc: killing off oldest TIME-WAIT connection\n")); tcp_kill_timewait(); /* Try to allocate a tcp_pcb again. */ pcb = (struct tcp_pcb *)memp_malloc(MEMP_TCP_PCB); if (pcb == NULL) { /* Try killing active connections with lower priority than the new one. */ LWIP_DEBUGF(TCP_DEBUG, ("tcp_alloc: killing connection with prio lower than %d\n", prio)); tcp_kill_prio(prio); /* Try to allocate a tcp_pcb again. */ pcb = (struct tcp_pcb *)memp_malloc(MEMP_TCP_PCB); if (pcb != NULL) { /* adjust err stats: memp_malloc failed twice before */ MEMP_STATS_DEC(err, MEMP_TCP_PCB); } } if (pcb != NULL) { /* adjust err stats: timewait PCB was freed above */ MEMP_STATS_DEC(err, MEMP_TCP_PCB); } } if (pcb != NULL) { memset(pcb, 0, sizeof(struct tcp_pcb)); pcb->prio = prio; pcb->snd_buf = TCP_SND_BUF; pcb->snd_queuelen = 0; pcb->rcv_wnd = TCP_WND; pcb->rcv_ann_wnd = TCP_WND; #if LWIP_WND_SCALE /* snd_scale and rcv_scale are zero unless both sides agree to use scaling */ pcb->snd_scale = 0; pcb->rcv_scale = 0; #endif pcb->tos = 0; pcb->ttl = TCP_TTL; /* As initial send MSS, we use TCP_MSS but limit it to 536. The send MSS is updated when an MSS option is received. */ pcb->mss = (TCP_MSS > 536) ? 536 : TCP_MSS; pcb->rto = 3000 / TCP_SLOW_INTERVAL; pcb->sa = 0; pcb->sv = 3000 / TCP_SLOW_INTERVAL; pcb->rtime = -1; pcb->cwnd = 1; iss = tcp_next_iss(); pcb->snd_wl2 = iss; pcb->snd_nxt = iss; pcb->lastack = iss; pcb->snd_lbb = iss; pcb->tmr = tcp_ticks; pcb->last_timer = tcp_timer_ctr; pcb->polltmr = 0; #if LWIP_CALLBACK_API pcb->recv = tcp_recv_null; #endif /* LWIP_CALLBACK_API */ /* Init KEEPALIVE timer */ pcb->keep_idle = TCP_KEEPIDLE_DEFAULT; #if LWIP_TCP_KEEPALIVE pcb->keep_intvl = TCP_KEEPINTVL_DEFAULT; pcb->keep_cnt = TCP_KEEPCNT_DEFAULT; #endif /* LWIP_TCP_KEEPALIVE */ pcb->keep_cnt_sent = 0; } return pcb; } /** * Creates a new TCP protocol control block but doesn't place it on * any of the TCP PCB lists. * The pcb is not put on any list until binding using tcp_bind(). * * @internal: Maybe there should be a idle TCP PCB list where these * PCBs are put on. Port reservation using tcp_bind() is implemented but * allocated pcbs that are not bound can't be killed automatically if wanting * to allocate a pcb with higher prio (@see tcp_kill_prio()) * * @return a new tcp_pcb that initially is in state CLOSED */ struct tcp_pcb * tcp_new(void) { return tcp_alloc(TCP_PRIO_NORMAL); } #if LWIP_IPV6 /** * Creates a new TCP-over-IPv6 protocol control block but doesn't * place it on any of the TCP PCB lists. * The pcb is not put on any list until binding using tcp_bind(). * * @return a new tcp_pcb that initially is in state CLOSED */ struct tcp_pcb * tcp_new_ip6(void) { struct tcp_pcb * pcb; pcb = tcp_alloc(TCP_PRIO_NORMAL); ip_set_v6(pcb, 1); return pcb; } #endif /* LWIP_IPV6 */ /** * Used to specify the argument that should be passed callback * functions. * * @param pcb tcp_pcb to set the callback argument * @param arg void pointer argument to pass to callback functions */ void tcp_arg(struct tcp_pcb *pcb, void *arg) { /* This function is allowed to be called for both listen pcbs and connection pcbs. */ pcb->callback_arg = arg; } #if LWIP_CALLBACK_API /** * Used to specify the function that should be called when a TCP * connection receives data. * * @param pcb tcp_pcb to set the recv callback * @param recv callback function to call for this pcb when data is received */ void tcp_recv(struct tcp_pcb *pcb, tcp_recv_fn recv) { LWIP_ASSERT("invalid socket state for recv callback", pcb->state != LISTEN); pcb->recv = recv; } /** * Used to specify the function that should be called when TCP data * has been successfully delivered to the remote host. * * @param pcb tcp_pcb to set the sent callback * @param sent callback function to call for this pcb when data is successfully sent */ void tcp_sent(struct tcp_pcb *pcb, tcp_sent_fn sent) { LWIP_ASSERT("invalid socket state for sent callback", pcb->state != LISTEN); pcb->sent = sent; } /** * Used to specify the function that should be called when a fatal error * has occured on the connection. * * @param pcb tcp_pcb to set the err callback * @param err callback function to call for this pcb when a fatal error * has occured on the connection */ void tcp_err(struct tcp_pcb *pcb, tcp_err_fn err) { LWIP_ASSERT("invalid socket state for err callback", pcb->state != LISTEN); pcb->errf = err; } /** * Used for specifying the function that should be called when a * LISTENing connection has been connected to another host. * * @param pcb tcp_pcb to set the accept callback * @param accept callback function to call for this pcb when LISTENing * connection has been connected to another host */ void tcp_accept(struct tcp_pcb *pcb, tcp_accept_fn accept) { /* This function is allowed to be called for both listen pcbs and connection pcbs. */ pcb->accept = accept; } #endif /* LWIP_CALLBACK_API */ /** * Used to specify the function that should be called periodically * from TCP. The interval is specified in terms of the TCP coarse * timer interval, which is called twice a second. * */ void tcp_poll(struct tcp_pcb *pcb, tcp_poll_fn poll, u8_t interval) { LWIP_ASSERT("invalid socket state for poll", pcb->state != LISTEN); #if LWIP_CALLBACK_API pcb->poll = poll; #else /* LWIP_CALLBACK_API */ LWIP_UNUSED_ARG(poll); #endif /* LWIP_CALLBACK_API */ pcb->pollinterval = interval; } /** * Purges a TCP PCB. Removes any buffered data and frees the buffer memory * (pcb->ooseq, pcb->unsent and pcb->unacked are freed). * * @param pcb tcp_pcb to purge. The pcb itself is not deallocated! */ void tcp_pcb_purge(struct tcp_pcb *pcb) { if (pcb->state != CLOSED && pcb->state != TIME_WAIT && pcb->state != LISTEN) { LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge\n")); #if TCP_LISTEN_BACKLOG if (pcb->state == SYN_RCVD) { /* Need to find the corresponding listen_pcb and decrease its accepts_pending */ struct tcp_pcb_listen *lpcb; LWIP_ASSERT("tcp_pcb_purge: pcb->state == SYN_RCVD but tcp_listen_pcbs is NULL", tcp_listen_pcbs.listen_pcbs != NULL); for (lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) { if ((lpcb->local_port == pcb->local_port) && IP_PCB_IPVER_EQ(pcb, lpcb) && (ipX_addr_isany(PCB_ISIPV6(lpcb), &lpcb->local_ip) || ipX_addr_cmp(PCB_ISIPV6(lpcb), &pcb->local_ip, &lpcb->local_ip))) { /* port and address of the listen pcb match the timed-out pcb */ LWIP_ASSERT("tcp_pcb_purge: listen pcb does not have accepts pending", lpcb->accepts_pending > 0); lpcb->accepts_pending--; break; } } } #endif /* TCP_LISTEN_BACKLOG */ if (pcb->refused_data != NULL) { LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: data left on ->refused_data\n")); pbuf_free(pcb->refused_data); pcb->refused_data = NULL; } if (pcb->unsent != NULL) { LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: not all data sent\n")); } if (pcb->unacked != NULL) { LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: data left on ->unacked\n")); } #if TCP_QUEUE_OOSEQ if (pcb->ooseq != NULL) { LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: data left on ->ooseq\n")); } tcp_segs_free(pcb->ooseq); pcb->ooseq = NULL; #endif /* TCP_QUEUE_OOSEQ */ /* Stop the retransmission timer as it will expect data on unacked queue if it fires */ pcb->rtime = -1; tcp_segs_free(pcb->unsent); tcp_segs_free(pcb->unacked); pcb->unacked = pcb->unsent = NULL; #if TCP_OVERSIZE pcb->unsent_oversize = 0; #endif /* TCP_OVERSIZE */ } } /** * Purges the PCB and removes it from a PCB list. Any delayed ACKs are sent first. * * @param pcblist PCB list to purge. * @param pcb tcp_pcb to purge. The pcb itself is NOT deallocated! */ void tcp_pcb_remove(struct tcp_pcb **pcblist, struct tcp_pcb *pcb) { TCP_RMV(pcblist, pcb); tcp_pcb_purge(pcb); /* if there is an outstanding delayed ACKs, send it */ if (pcb->state != TIME_WAIT && pcb->state != LISTEN && pcb->flags & TF_ACK_DELAY) { pcb->flags |= TF_ACK_NOW; tcp_output(pcb); } if (pcb->state != LISTEN) { LWIP_ASSERT("unsent segments leaking", pcb->unsent == NULL); LWIP_ASSERT("unacked segments leaking", pcb->unacked == NULL); #if TCP_QUEUE_OOSEQ LWIP_ASSERT("ooseq segments leaking", pcb->ooseq == NULL); #endif /* TCP_QUEUE_OOSEQ */ } pcb->state = CLOSED; LWIP_ASSERT("tcp_pcb_remove: tcp_pcbs_sane()", tcp_pcbs_sane()); } /** * Calculates a new initial sequence number for new connections. * * @return u32_t pseudo random sequence number */ u32_t tcp_next_iss(void) { static u32_t iss = 6510; iss += tcp_ticks; /* XXX */ return iss; } #if TCP_CALCULATE_EFF_SEND_MSS /** * Calcluates the effective send mss that can be used for a specific IP address * by using ip_route to determin the netif used to send to the address and * calculating the minimum of TCP_MSS and that netif's mtu (if set). */ u16_t tcp_eff_send_mss_impl(u16_t sendmss, ipX_addr_t *dest #if LWIP_IPV6 , ipX_addr_t *src, u8_t isipv6 #endif /* LWIP_IPV6 */ ) { u16_t mss_s; struct netif *outif; s16_t mtu; outif = ipX_route(isipv6, src, dest); #if LWIP_IPV6 if (isipv6) { /* First look in destination cache, to see if there is a Path MTU. */ mtu = nd6_get_destination_mtu(ipX_2_ip6(dest), outif); } else #endif /* LWIP_IPV6 */ { if (outif == NULL) { return sendmss; } mtu = outif->mtu; } if (mtu != 0) { mss_s = mtu - IP_HLEN - TCP_HLEN; #if LWIP_IPV6 /* for IPv6, substract the difference in header size */ mss_s -= (IP6_HLEN - IP_HLEN); #endif /* LWIP_IPV6 */ /* RFC 1122, chap 4.2.2.6: * Eff.snd.MSS = min(SendMSS+20, MMS_S) - TCPhdrsize - IPoptionsize * We correct for TCP options in tcp_write(), and don't support IP options. */ sendmss = LWIP_MIN(sendmss, mss_s); } return sendmss; } #endif /* TCP_CALCULATE_EFF_SEND_MSS */ const char* tcp_debug_state_str(enum tcp_state s) { return tcp_state_str[s]; } #if TCP_DEBUG || TCP_INPUT_DEBUG || TCP_OUTPUT_DEBUG /** * Print a tcp header for debugging purposes. * * @param tcphdr pointer to a struct tcp_hdr */ void tcp_debug_print(struct tcp_hdr *tcphdr) { LWIP_DEBUGF(TCP_DEBUG, ("TCP header:\n")); LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n")); LWIP_DEBUGF(TCP_DEBUG, ("| %5"U16_F" | %5"U16_F" | (src port, dest port)\n", ntohs(tcphdr->src), ntohs(tcphdr->dest))); LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n")); LWIP_DEBUGF(TCP_DEBUG, ("| %010"U32_F" | (seq no)\n", ntohl(tcphdr->seqno))); LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n")); LWIP_DEBUGF(TCP_DEBUG, ("| %010"U32_F" | (ack no)\n", ntohl(tcphdr->ackno))); LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n")); LWIP_DEBUGF(TCP_DEBUG, ("| %2"U16_F" | |%"U16_F"%"U16_F"%"U16_F"%"U16_F"%"U16_F"%"U16_F"| %5"U16_F" | (hdrlen, flags (", TCPH_HDRLEN(tcphdr), TCPH_FLAGS(tcphdr) >> 5 & 1, TCPH_FLAGS(tcphdr) >> 4 & 1, TCPH_FLAGS(tcphdr) >> 3 & 1, TCPH_FLAGS(tcphdr) >> 2 & 1, TCPH_FLAGS(tcphdr) >> 1 & 1, TCPH_FLAGS(tcphdr) & 1, ntohs(tcphdr->wnd))); tcp_debug_print_flags(TCPH_FLAGS(tcphdr)); LWIP_DEBUGF(TCP_DEBUG, ("), win)\n")); LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n")); LWIP_DEBUGF(TCP_DEBUG, ("| 0x%04"X16_F" | %5"U16_F" | (chksum, urgp)\n", ntohs(tcphdr->chksum), ntohs(tcphdr->urgp))); LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n")); } /** * Print a tcp state for debugging purposes. * * @param s enum tcp_state to print */ void tcp_debug_print_state(enum tcp_state s) { LWIP_DEBUGF(TCP_DEBUG, ("State: %s\n", tcp_state_str[s])); } /** * Print tcp flags for debugging purposes. * * @param flags tcp flags, all active flags are printed */ void tcp_debug_print_flags(u8_t flags) { if (flags & TCP_FIN) { LWIP_DEBUGF(TCP_DEBUG, ("FIN ")); } if (flags & TCP_SYN) { LWIP_DEBUGF(TCP_DEBUG, ("SYN ")); } if (flags & TCP_RST) { LWIP_DEBUGF(TCP_DEBUG, ("RST ")); } if (flags & TCP_PSH) { LWIP_DEBUGF(TCP_DEBUG, ("PSH ")); } if (flags & TCP_ACK) { LWIP_DEBUGF(TCP_DEBUG, ("ACK ")); } if (flags & TCP_URG) { LWIP_DEBUGF(TCP_DEBUG, ("URG ")); } if (flags & TCP_ECE) { LWIP_DEBUGF(TCP_DEBUG, ("ECE ")); } if (flags & TCP_CWR) { LWIP_DEBUGF(TCP_DEBUG, ("CWR ")); } LWIP_DEBUGF(TCP_DEBUG, ("\n")); } /** * Print all tcp_pcbs in every list for debugging purposes. */ void tcp_debug_print_pcbs(void) { struct tcp_pcb *pcb; LWIP_DEBUGF(TCP_DEBUG, ("Active PCB states:\n")); for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) { LWIP_DEBUGF(TCP_DEBUG, ("Local port %"U16_F", foreign port %"U16_F" snd_nxt %"U32_F" rcv_nxt %"U32_F" ", pcb->local_port, pcb->remote_port, pcb->snd_nxt, pcb->rcv_nxt)); tcp_debug_print_state(pcb->state); } LWIP_DEBUGF(TCP_DEBUG, ("Listen PCB states:\n")); for(pcb = (struct tcp_pcb *)tcp_listen_pcbs.pcbs; pcb != NULL; pcb = pcb->next) { LWIP_DEBUGF(TCP_DEBUG, ("Local port %"U16_F", foreign port %"U16_F" snd_nxt %"U32_F" rcv_nxt %"U32_F" ", pcb->local_port, pcb->remote_port, pcb->snd_nxt, pcb->rcv_nxt)); tcp_debug_print_state(pcb->state); } LWIP_DEBUGF(TCP_DEBUG, ("TIME-WAIT PCB states:\n")); for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) { LWIP_DEBUGF(TCP_DEBUG, ("Local port %"U16_F", foreign port %"U16_F" snd_nxt %"U32_F" rcv_nxt %"U32_F" ", pcb->local_port, pcb->remote_port, pcb->snd_nxt, pcb->rcv_nxt)); tcp_debug_print_state(pcb->state); } } /** * Check state consistency of the tcp_pcb lists. */ s16_t tcp_pcbs_sane(void) { struct tcp_pcb *pcb; for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) { LWIP_ASSERT("tcp_pcbs_sane: active pcb->state != CLOSED", pcb->state != CLOSED); LWIP_ASSERT("tcp_pcbs_sane: active pcb->state != LISTEN", pcb->state != LISTEN); LWIP_ASSERT("tcp_pcbs_sane: active pcb->state != TIME-WAIT", pcb->state != TIME_WAIT); } for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) { LWIP_ASSERT("tcp_pcbs_sane: tw pcb->state == TIME-WAIT", pcb->state == TIME_WAIT); } return 1; } #endif /* TCP_DEBUG */ #endif /* LWIP_TCP */ ocproxy-1.60/lwip/src/core/tcp_in.c000066400000000000000000002011721303453231400172560ustar00rootroot00000000000000/** * @file * Transmission Control Protocol, incoming traffic * * The input processing functions of the TCP layer. * * These functions are generally called in the order (ip_input() ->) * tcp_input() -> * tcp_process() -> tcp_receive() (-> application). * */ /* * Copyright (c) 2001-2004 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #include "lwip/opt.h" #if LWIP_TCP /* don't build if not configured for use in lwipopts.h */ #include "lwip/tcp_impl.h" #include "lwip/def.h" #include "lwip/ip_addr.h" #include "lwip/netif.h" #include "lwip/mem.h" #include "lwip/memp.h" #include "lwip/inet_chksum.h" #include "lwip/stats.h" #include "lwip/snmp.h" #include "arch/perf.h" #include "lwip/ip6.h" #include "lwip/ip6_addr.h" #include "lwip/inet_chksum.h" #if LWIP_ND6_TCP_REACHABILITY_HINTS #include "lwip/nd6.h" #endif /* LWIP_ND6_TCP_REACHABILITY_HINTS */ /* These variables are global to all functions involved in the input processing of TCP segments. They are set by the tcp_input() function. */ static struct tcp_seg inseg; static struct tcp_hdr *tcphdr; static u16_t tcphdr_opt1len; static u8_t* tcphdr_opt2; static u16_t tcp_optidx; static u32_t seqno, ackno; static u8_t flags; static u16_t tcplen; static u8_t recv_flags; static struct pbuf *recv_data; struct tcp_pcb *tcp_input_pcb; /* Forward declarations. */ static err_t tcp_process(struct tcp_pcb *pcb); static void tcp_receive(struct tcp_pcb *pcb); static void tcp_parseopt(struct tcp_pcb *pcb); static err_t tcp_listen_input(struct tcp_pcb_listen *pcb); static err_t tcp_timewait_input(struct tcp_pcb *pcb); /** * The initial input processing of TCP. It verifies the TCP header, demultiplexes * the segment between the PCBs and passes it on to tcp_process(), which implements * the TCP finite state machine. This function is called by the IP layer (in * ip_input()). * * @param p received TCP segment to process (p->payload pointing to the TCP header) * @param inp network interface on which this segment was received */ void tcp_input(struct pbuf *p, struct netif *inp) { struct tcp_pcb *pcb, *prev; struct tcp_pcb_listen *lpcb; #if SO_REUSE struct tcp_pcb *lpcb_prev = NULL; struct tcp_pcb_listen *lpcb_any = NULL; #endif /* SO_REUSE */ u8_t hdrlen; err_t err; #if CHECKSUM_CHECK_TCP u16_t chksum; #endif /* CHECKSUM_CHECK_TCP */ PERF_START; TCP_STATS_INC(tcp.recv); snmp_inc_tcpinsegs(); tcphdr = (struct tcp_hdr *)p->payload; #if TCP_INPUT_DEBUG tcp_debug_print(tcphdr); #endif /* Check that TCP header fits in payload */ if (p->len < sizeof(struct tcp_hdr)) { /* drop short packets */ LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: short packet (%"U16_F" bytes) discarded\n", p->tot_len)); TCP_STATS_INC(tcp.lenerr); goto dropped; } /* Don't even process incoming broadcasts/multicasts. */ if ((!ip_current_is_v6() && ip_addr_isbroadcast(ip_current_dest_addr(), inp)) || ipX_addr_ismulticast(ip_current_is_v6(), ipX_current_dest_addr())) { TCP_STATS_INC(tcp.proterr); goto dropped; } #if CHECKSUM_CHECK_TCP /* Verify TCP checksum. */ chksum = ipX_chksum_pseudo(ip_current_is_v6(), p, IP_PROTO_TCP, p->tot_len, ipX_current_src_addr(), ipX_current_dest_addr()); if (chksum != 0) { LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: packet discarded due to failing checksum 0x%04"X16_F"\n", chksum)); tcp_debug_print(tcphdr); TCP_STATS_INC(tcp.chkerr); goto dropped; } #endif /* CHECKSUM_CHECK_TCP */ /* Move the payload pointer in the pbuf so that it points to the TCP data instead of the TCP header. */ hdrlen = TCPH_HDRLEN(tcphdr); tcphdr_opt1len = (hdrlen * 4) - TCP_HLEN; tcphdr_opt2 = NULL; if (p->len < hdrlen * 4) { if (p->len >= TCP_HLEN) { /* TCP header fits into first pbuf, options don't - data is in the next pbuf */ u16_t optlen = tcphdr_opt1len; pbuf_header(p, -TCP_HLEN); /* cannot fail */ LWIP_ASSERT("tcphdr_opt1len >= p->len", tcphdr_opt1len >= p->len); LWIP_ASSERT("p->next != NULL", p->next != NULL); tcphdr_opt1len = p->len; if (optlen > tcphdr_opt1len) { s16_t opt2len; /* options continue in the next pbuf: set p to zero length and hide the options in the next pbuf (adjusting p->tot_len) */ u8_t phret = pbuf_header(p, -(s16_t)tcphdr_opt1len); LWIP_ASSERT("phret == 0", phret == 0); tcphdr_opt2 = (u8_t*)p->next->payload; opt2len = optlen - tcphdr_opt1len; phret = pbuf_header(p->next, -opt2len); LWIP_ASSERT("phret == 0", phret == 0); /* p->next->payload now points to the TCP data */ /* manually adjust p->tot_len to changed p->next->tot_len change */ p->tot_len -= opt2len; } LWIP_ASSERT("p->len == 0", p->len == 0); } else { /* drop short packets */ LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: short packet\n")); TCP_STATS_INC(tcp.lenerr); goto dropped; } } else { pbuf_header(p, -(hdrlen * 4)); /* cannot fail */ } /* Convert fields in TCP header to host byte order. */ tcphdr->src = ntohs(tcphdr->src); tcphdr->dest = ntohs(tcphdr->dest); seqno = tcphdr->seqno = ntohl(tcphdr->seqno); ackno = tcphdr->ackno = ntohl(tcphdr->ackno); tcphdr->wnd = ntohs(tcphdr->wnd); flags = TCPH_FLAGS(tcphdr); tcplen = p->tot_len + ((flags & (TCP_FIN | TCP_SYN)) ? 1 : 0); /* Demultiplex an incoming segment. First, we check if it is destined for an active connection. */ prev = NULL; for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) { LWIP_ASSERT("tcp_input: active pcb->state != CLOSED", pcb->state != CLOSED); LWIP_ASSERT("tcp_input: active pcb->state != TIME-WAIT", pcb->state != TIME_WAIT); LWIP_ASSERT("tcp_input: active pcb->state != LISTEN", pcb->state != LISTEN); if (pcb->remote_port == tcphdr->src && pcb->local_port == tcphdr->dest && IP_PCB_IPVER_INPUT_MATCH(pcb) && ipX_addr_cmp(ip_current_is_v6(), &pcb->remote_ip, ipX_current_src_addr()) && ipX_addr_cmp(ip_current_is_v6(),&pcb->local_ip, ipX_current_dest_addr())) { /* Move this PCB to the front of the list so that subsequent lookups will be faster (we exploit locality in TCP segment arrivals). */ LWIP_ASSERT("tcp_input: pcb->next != pcb (before cache)", pcb->next != pcb); if (prev != NULL) { prev->next = pcb->next; pcb->next = tcp_active_pcbs; tcp_active_pcbs = pcb; } LWIP_ASSERT("tcp_input: pcb->next != pcb (after cache)", pcb->next != pcb); break; } prev = pcb; } if (pcb == NULL) { /* If it did not go to an active connection, we check the connections in the TIME-WAIT state. */ for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) { LWIP_ASSERT("tcp_input: TIME-WAIT pcb->state == TIME-WAIT", pcb->state == TIME_WAIT); if (pcb->remote_port == tcphdr->src && pcb->local_port == tcphdr->dest && IP_PCB_IPVER_INPUT_MATCH(pcb) && ipX_addr_cmp(ip_current_is_v6(), &pcb->remote_ip, ipX_current_src_addr()) && ipX_addr_cmp(ip_current_is_v6(),&pcb->local_ip, ipX_current_dest_addr())) { /* We don't really care enough to move this PCB to the front of the list since we are not very likely to receive that many segments for connections in TIME-WAIT. */ LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: packed for TIME_WAITing connection.\n")); tcp_timewait_input(pcb); pbuf_free(p); return; } } /* Finally, if we still did not get a match, we check all PCBs that are LISTENing for incoming connections. */ prev = NULL; for(lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) { if (lpcb->local_port == tcphdr->dest) { #if LWIP_IPV6 if (lpcb->accept_any_ip_version) { /* found an ANY-match */ #if SO_REUSE lpcb_any = lpcb; lpcb_prev = prev; #else /* SO_REUSE */ break; #endif /* SO_REUSE */ } else #endif /* LWIP_IPV6 */ if (IP_PCB_IPVER_INPUT_MATCH(lpcb)) { if (ipX_addr_cmp(ip_current_is_v6(), &lpcb->local_ip, ipX_current_dest_addr())) { /* found an exact match */ break; } else if (ipX_addr_isany(ip_current_is_v6(), &lpcb->local_ip)) { /* found an ANY-match */ #if SO_REUSE lpcb_any = lpcb; lpcb_prev = prev; #else /* SO_REUSE */ break; #endif /* SO_REUSE */ } } } prev = (struct tcp_pcb *)lpcb; } #if SO_REUSE /* first try specific local IP */ if (lpcb == NULL) { /* only pass to ANY if no specific local IP has been found */ lpcb = lpcb_any; prev = lpcb_prev; } #endif /* SO_REUSE */ if (lpcb != NULL) { /* Move this PCB to the front of the list so that subsequent lookups will be faster (we exploit locality in TCP segment arrivals). */ if (prev != NULL) { ((struct tcp_pcb_listen *)prev)->next = lpcb->next; /* our successor is the remainder of the listening list */ lpcb->next = tcp_listen_pcbs.listen_pcbs; /* put this listening pcb at the head of the listening list */ tcp_listen_pcbs.listen_pcbs = lpcb; } LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: packed for LISTENing connection.\n")); tcp_listen_input(lpcb); pbuf_free(p); return; } } #if TCP_INPUT_DEBUG LWIP_DEBUGF(TCP_INPUT_DEBUG, ("+-+-+-+-+-+-+-+-+-+-+-+-+-+- tcp_input: flags ")); tcp_debug_print_flags(TCPH_FLAGS(tcphdr)); LWIP_DEBUGF(TCP_INPUT_DEBUG, ("-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n")); #endif /* TCP_INPUT_DEBUG */ if (pcb != NULL) { /* The incoming segment belongs to a connection. */ #if TCP_INPUT_DEBUG #if TCP_DEBUG tcp_debug_print_state(pcb->state); #endif /* TCP_DEBUG */ #endif /* TCP_INPUT_DEBUG */ /* Set up a tcp_seg structure. */ inseg.next = NULL; inseg.len = p->tot_len; inseg.p = p; inseg.tcphdr = tcphdr; recv_data = NULL; recv_flags = 0; if (flags & TCP_PSH) { p->flags |= PBUF_FLAG_PUSH; } /* If there is data which was previously "refused" by upper layer */ if (pcb->refused_data != NULL) { if ((tcp_process_refused_data(pcb) == ERR_ABRT) || ((pcb->refused_data != NULL) && (tcplen > 0))) { /* pcb has been aborted or refused data is still refused and the new segment contains data */ TCP_STATS_INC(tcp.drop); snmp_inc_tcpinerrs(); goto aborted; } } tcp_input_pcb = pcb; err = tcp_process(pcb); /* A return value of ERR_ABRT means that tcp_abort() was called and that the pcb has been freed. If so, we don't do anything. */ if (err != ERR_ABRT) { if (recv_flags & TF_RESET) { /* TF_RESET means that the connection was reset by the other end. We then call the error callback to inform the application that the connection is dead before we deallocate the PCB. */ TCP_EVENT_ERR(pcb->errf, pcb->callback_arg, ERR_RST); tcp_pcb_remove(&tcp_active_pcbs, pcb); memp_free(MEMP_TCP_PCB, pcb); } else if (recv_flags & TF_CLOSED) { /* The connection has been closed and we will deallocate the PCB. */ if (!(pcb->flags & TF_RXCLOSED)) { /* Connection closed although the application has only shut down the tx side: call the PCB's err callback and indicate the closure to ensure the application doesn't continue using the PCB. */ TCP_EVENT_ERR(pcb->errf, pcb->callback_arg, ERR_CLSD); } tcp_pcb_remove(&tcp_active_pcbs, pcb); memp_free(MEMP_TCP_PCB, pcb); } else { err = ERR_OK; /* If the application has registered a "sent" function to be called when new send buffer space is available, we call it now. */ if (pcb->acked > 0) { u16_t acked; #if LWIP_WND_SCALE /* pcb->acked is u32_t but the sent callback only takes a u16_t, so we might have to call it multiple times. */ u32_t pcb_acked = pcb->acked; while(pcb_acked > 0) { acked = (u16_t)LWIP_MIN(pcb_acked, 0xffffu); pcb_acked -= acked; #else { acked = pcb->acked; #endif TCP_EVENT_SENT(pcb, (u16_t)acked, err); if (err == ERR_ABRT) { goto aborted; } } } #if TCP_QUEUE_OOSEQ && LWIP_WND_SCALE while (recv_data != NULL) { struct pbuf *rest = NULL; pbuf_split_64k(recv_data, &rest); #else /* TCP_QUEUE_OOSEQ && LWIP_WND_SCALE */ if (recv_data != NULL) { #endif /* TCP_QUEUE_OOSEQ && LWIP_WND_SCALE */ LWIP_ASSERT("pcb->refused_data == NULL", pcb->refused_data == NULL); if (pcb->flags & TF_RXCLOSED) { /* received data although already closed -> abort (send RST) to notify the remote host that not all data has been processed */ pbuf_free(recv_data); #if TCP_QUEUE_OOSEQ && LWIP_WND_SCALE if (rest != NULL) { pbuf_free(rest); } #endif /* TCP_QUEUE_OOSEQ && LWIP_WND_SCALE */ tcp_abort(pcb); goto aborted; } /* Notify application that data has been received. */ TCP_EVENT_RECV(pcb, recv_data, ERR_OK, err); if (err == ERR_ABRT) { #if TCP_QUEUE_OOSEQ && LWIP_WND_SCALE if (rest != NULL) { pbuf_free(rest); } #endif /* TCP_QUEUE_OOSEQ && LWIP_WND_SCALE */ goto aborted; } /* If the upper layer can't receive this data, store it */ if (err != ERR_OK) { #if TCP_QUEUE_OOSEQ && LWIP_WND_SCALE if (rest != NULL) { pbuf_cat(recv_data, rest); } #endif /* TCP_QUEUE_OOSEQ && LWIP_WND_SCALE */ pcb->refused_data = recv_data; LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: keep incoming packet, because pcb is \"full\"\n")); #if TCP_QUEUE_OOSEQ && LWIP_WND_SCALE break; } else { /* Upper layer received the data, go on with the rest if > 64K */ recv_data = rest; #endif /* TCP_QUEUE_OOSEQ && LWIP_WND_SCALE */ } } /* If a FIN segment was received, we call the callback function with a NULL buffer to indicate EOF. */ if (recv_flags & TF_GOT_FIN) { if (pcb->refused_data != NULL) { /* Delay this if we have refused data. */ pcb->refused_data->flags |= PBUF_FLAG_TCP_FIN; } else { /* correct rcv_wnd as the application won't call tcp_recved() for the FIN's seqno */ if (pcb->rcv_wnd != TCP_WND) { pcb->rcv_wnd++; } TCP_EVENT_CLOSED(pcb, err); if (err == ERR_ABRT) { goto aborted; } } } tcp_input_pcb = NULL; /* Try to send something out. */ tcp_output(pcb); #if TCP_INPUT_DEBUG #if TCP_DEBUG tcp_debug_print_state(pcb->state); #endif /* TCP_DEBUG */ #endif /* TCP_INPUT_DEBUG */ } } /* Jump target if pcb has been aborted in a callback (by calling tcp_abort()). Below this line, 'pcb' may not be dereferenced! */ aborted: tcp_input_pcb = NULL; recv_data = NULL; /* give up our reference to inseg.p */ if (inseg.p != NULL) { pbuf_free(inseg.p); inseg.p = NULL; } } else { /* If no matching PCB was found, send a TCP RST (reset) to the sender. */ LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_input: no PCB match found, resetting.\n")); if (!(TCPH_FLAGS(tcphdr) & TCP_RST)) { TCP_STATS_INC(tcp.proterr); TCP_STATS_INC(tcp.drop); tcp_rst(ackno, seqno + tcplen, ipX_current_dest_addr(), ipX_current_src_addr(), tcphdr->dest, tcphdr->src, ip_current_is_v6()); } pbuf_free(p); } LWIP_ASSERT("tcp_input: tcp_pcbs_sane()", tcp_pcbs_sane()); PERF_STOP("tcp_input"); return; dropped: TCP_STATS_INC(tcp.drop); snmp_inc_tcpinerrs(); pbuf_free(p); } /** * Called by tcp_input() when a segment arrives for a listening * connection (from tcp_input()). * * @param pcb the tcp_pcb_listen for which a segment arrived * @return ERR_OK if the segment was processed * another err_t on error * * @note the return value is not (yet?) used in tcp_input() * @note the segment which arrived is saved in global variables, therefore only the pcb * involved is passed as a parameter to this function */ static err_t tcp_listen_input(struct tcp_pcb_listen *pcb) { struct tcp_pcb *npcb; err_t rc; if (flags & TCP_RST) { /* An incoming RST should be ignored. Return. */ return ERR_OK; } /* In the LISTEN state, we check for incoming SYN segments, creates a new PCB, and responds with a SYN|ACK. */ if (flags & TCP_ACK) { /* For incoming segments with the ACK flag set, respond with a RST. */ LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_listen_input: ACK in LISTEN, sending reset\n")); tcp_rst(ackno, seqno + tcplen, ipX_current_dest_addr(), ipX_current_src_addr(), tcphdr->dest, tcphdr->src, ip_current_is_v6()); } else if (flags & TCP_SYN) { LWIP_DEBUGF(TCP_DEBUG, ("TCP connection request %"U16_F" -> %"U16_F".\n", tcphdr->src, tcphdr->dest)); #if TCP_LISTEN_BACKLOG if (pcb->accepts_pending >= pcb->backlog) { LWIP_DEBUGF(TCP_DEBUG, ("tcp_listen_input: listen backlog exceeded for port %"U16_F"\n", tcphdr->dest)); return ERR_ABRT; } #endif /* TCP_LISTEN_BACKLOG */ npcb = tcp_alloc(pcb->prio); /* If a new PCB could not be created (probably due to lack of memory), we don't do anything, but rely on the sender will retransmit the SYN at a time when we have more memory available. */ if (npcb == NULL) { LWIP_DEBUGF(TCP_DEBUG, ("tcp_listen_input: could not allocate PCB\n")); TCP_STATS_INC(tcp.memerr); return ERR_MEM; } #if TCP_LISTEN_BACKLOG pcb->accepts_pending++; #endif /* TCP_LISTEN_BACKLOG */ /* Set up the new PCB. */ #if LWIP_IPV6 PCB_ISIPV6(npcb) = ip_current_is_v6(); #endif /* LWIP_IPV6 */ ipX_addr_copy(ip_current_is_v6(), npcb->local_ip, *ipX_current_dest_addr()); ipX_addr_copy(ip_current_is_v6(), npcb->remote_ip, *ipX_current_src_addr()); npcb->local_port = pcb->local_port; npcb->remote_port = tcphdr->src; npcb->state = SYN_RCVD; npcb->rcv_nxt = seqno + 1; npcb->rcv_ann_right_edge = npcb->rcv_nxt; npcb->snd_wl1 = seqno - 1;/* initialise to seqno-1 to force window update */ npcb->callback_arg = pcb->callback_arg; #if LWIP_CALLBACK_API npcb->accept = pcb->accept; #endif /* LWIP_CALLBACK_API */ /* inherit socket options */ npcb->so_options = pcb->so_options & SOF_INHERITED; /* Register the new PCB so that we can begin receiving segments for it. */ TCP_REG_ACTIVE(npcb); /* Parse any options in the SYN. */ tcp_parseopt(npcb); npcb->snd_wnd = SND_WND_SCALE(npcb, tcphdr->wnd); npcb->snd_wnd_max = npcb->snd_wnd; npcb->ssthresh = npcb->snd_wnd; #if TCP_CALCULATE_EFF_SEND_MSS npcb->mss = tcp_eff_send_mss(npcb->mss, &npcb->local_ip, &npcb->remote_ip, PCB_ISIPV6(npcb)); #endif /* TCP_CALCULATE_EFF_SEND_MSS */ snmp_inc_tcppassiveopens(); /* Send a SYN|ACK together with the MSS option. */ rc = tcp_enqueue_flags(npcb, TCP_SYN | TCP_ACK); if (rc != ERR_OK) { tcp_abandon(npcb, 0); return rc; } return tcp_output(npcb); } return ERR_OK; } /** * Called by tcp_input() when a segment arrives for a connection in * TIME_WAIT. * * @param pcb the tcp_pcb for which a segment arrived * * @note the segment which arrived is saved in global variables, therefore only the pcb * involved is passed as a parameter to this function */ static err_t tcp_timewait_input(struct tcp_pcb *pcb) { /* RFC 1337: in TIME_WAIT, ignore RST and ACK FINs + any 'acceptable' segments */ /* RFC 793 3.9 Event Processing - Segment Arrives: * - first check sequence number - we skip that one in TIME_WAIT (always * acceptable since we only send ACKs) * - second check the RST bit (... return) */ if (flags & TCP_RST) { return ERR_OK; } /* - fourth, check the SYN bit, */ if (flags & TCP_SYN) { /* If an incoming segment is not acceptable, an acknowledgment should be sent in reply */ if (TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, pcb->rcv_nxt+pcb->rcv_wnd)) { /* If the SYN is in the window it is an error, send a reset */ tcp_rst(ackno, seqno + tcplen, ipX_current_dest_addr(), ipX_current_src_addr(), tcphdr->dest, tcphdr->src, ip_current_is_v6()); return ERR_OK; } } else if (flags & TCP_FIN) { /* - eighth, check the FIN bit: Remain in the TIME-WAIT state. Restart the 2 MSL time-wait timeout.*/ pcb->tmr = tcp_ticks; } if ((tcplen > 0)) { /* Acknowledge data, FIN or out-of-window SYN */ pcb->flags |= TF_ACK_NOW; return tcp_output(pcb); } return ERR_OK; } /** * Implements the TCP state machine. Called by tcp_input. In some * states tcp_receive() is called to receive data. The tcp_seg * argument will be freed by the caller (tcp_input()) unless the * recv_data pointer in the pcb is set. * * @param pcb the tcp_pcb for which a segment arrived * * @note the segment which arrived is saved in global variables, therefore only the pcb * involved is passed as a parameter to this function */ static err_t tcp_process(struct tcp_pcb *pcb) { struct tcp_seg *rseg; u8_t acceptable = 0; err_t err; err = ERR_OK; /* Process incoming RST segments. */ if (flags & TCP_RST) { /* First, determine if the reset is acceptable. */ if (pcb->state == SYN_SENT) { if (ackno == pcb->snd_nxt) { acceptable = 1; } } else { if (TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, pcb->rcv_nxt+pcb->rcv_wnd)) { acceptable = 1; } } if (acceptable) { LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_process: Connection RESET\n")); LWIP_ASSERT("tcp_input: pcb->state != CLOSED", pcb->state != CLOSED); recv_flags |= TF_RESET; pcb->flags &= ~TF_ACK_DELAY; return ERR_RST; } else { LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_process: unacceptable reset seqno %"U32_F" rcv_nxt %"U32_F"\n", seqno, pcb->rcv_nxt)); LWIP_DEBUGF(TCP_DEBUG, ("tcp_process: unacceptable reset seqno %"U32_F" rcv_nxt %"U32_F"\n", seqno, pcb->rcv_nxt)); return ERR_OK; } } if ((flags & TCP_SYN) && (pcb->state != SYN_SENT && pcb->state != SYN_RCVD)) { /* Cope with new connection attempt after remote end crashed */ tcp_ack_now(pcb); return ERR_OK; } if ((pcb->flags & TF_RXCLOSED) == 0) { /* Update the PCB (in)activity timer unless rx is closed (see tcp_shutdown) */ pcb->tmr = tcp_ticks; } pcb->keep_cnt_sent = 0; tcp_parseopt(pcb); /* Do different things depending on the TCP state. */ switch (pcb->state) { case SYN_SENT: LWIP_DEBUGF(TCP_INPUT_DEBUG, ("SYN-SENT: ackno %"U32_F" pcb->snd_nxt %"U32_F" unacked %"U32_F"\n", ackno, pcb->snd_nxt, ntohl(pcb->unacked->tcphdr->seqno))); /* received SYN ACK with expected sequence number? */ if ((flags & TCP_ACK) && (flags & TCP_SYN) && ackno == ntohl(pcb->unacked->tcphdr->seqno) + 1) { pcb->snd_buf++; pcb->rcv_nxt = seqno + 1; pcb->rcv_ann_right_edge = pcb->rcv_nxt; pcb->lastack = ackno; pcb->snd_wnd = SND_WND_SCALE(pcb, tcphdr->wnd); pcb->snd_wnd_max = pcb->snd_wnd; pcb->snd_wl1 = seqno - 1; /* initialise to seqno - 1 to force window update */ pcb->state = ESTABLISHED; #if TCP_CALCULATE_EFF_SEND_MSS pcb->mss = tcp_eff_send_mss(pcb->mss, &pcb->local_ip, &pcb->remote_ip, PCB_ISIPV6(pcb)); #endif /* TCP_CALCULATE_EFF_SEND_MSS */ /* Set ssthresh again after changing pcb->mss (already set in tcp_connect * but for the default value of pcb->mss) */ pcb->ssthresh = pcb->mss * 10; pcb->cwnd = ((pcb->cwnd == 1) ? (pcb->mss * 2) : pcb->mss); LWIP_ASSERT("pcb->snd_queuelen > 0", (pcb->snd_queuelen > 0)); --pcb->snd_queuelen; LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_process: SYN-SENT --queuelen %"TCPWNDSIZE_F"\n", (tcpwnd_size_t)pcb->snd_queuelen)); rseg = pcb->unacked; pcb->unacked = rseg->next; tcp_seg_free(rseg); /* If there's nothing left to acknowledge, stop the retransmit timer, otherwise reset it to start again */ if(pcb->unacked == NULL) pcb->rtime = -1; else { pcb->rtime = 0; pcb->nrtx = 0; } /* Call the user specified function to call when sucessfully * connected. */ TCP_EVENT_CONNECTED(pcb, ERR_OK, err); if (err == ERR_ABRT) { return ERR_ABRT; } tcp_ack_now(pcb); } /* received ACK? possibly a half-open connection */ else if (flags & TCP_ACK) { /* send a RST to bring the other side in a non-synchronized state. */ tcp_rst(ackno, seqno + tcplen, ipX_current_dest_addr(), ipX_current_src_addr(), tcphdr->dest, tcphdr->src, ip_current_is_v6()); } break; case SYN_RCVD: if (flags & TCP_ACK) { /* expected ACK number? */ if (TCP_SEQ_BETWEEN(ackno, pcb->lastack+1, pcb->snd_nxt)) { tcpwnd_size_t old_cwnd; pcb->state = ESTABLISHED; LWIP_DEBUGF(TCP_DEBUG, ("TCP connection established %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest)); #if LWIP_CALLBACK_API LWIP_ASSERT("pcb->accept != NULL", pcb->accept != NULL); #endif /* Call the accept function. */ TCP_EVENT_ACCEPT(pcb, ERR_OK, err); if (err != ERR_OK) { /* If the accept function returns with an error, we abort * the connection. */ /* Already aborted? */ if (err != ERR_ABRT) { tcp_abort(pcb); } return ERR_ABRT; } old_cwnd = pcb->cwnd; /* If there was any data contained within this ACK, * we'd better pass it on to the application as well. */ tcp_receive(pcb); /* Prevent ACK for SYN to generate a sent event */ if (pcb->acked != 0) { pcb->acked--; } pcb->cwnd = ((old_cwnd == 1) ? (pcb->mss * 2) : pcb->mss); if (recv_flags & TF_GOT_FIN) { tcp_ack_now(pcb); pcb->state = CLOSE_WAIT; } } else { /* incorrect ACK number, send RST */ tcp_rst(ackno, seqno + tcplen, ipX_current_dest_addr(), ipX_current_src_addr(), tcphdr->dest, tcphdr->src, ip_current_is_v6()); } } else if ((flags & TCP_SYN) && (seqno == pcb->rcv_nxt - 1)) { /* Looks like another copy of the SYN - retransmit our SYN-ACK */ tcp_rexmit(pcb); } break; case CLOSE_WAIT: /* FALLTHROUGH */ case ESTABLISHED: tcp_receive(pcb); if (recv_flags & TF_GOT_FIN) { /* passive close */ tcp_ack_now(pcb); pcb->state = CLOSE_WAIT; } break; case FIN_WAIT_1: tcp_receive(pcb); if (recv_flags & TF_GOT_FIN) { if ((flags & TCP_ACK) && (ackno == pcb->snd_nxt)) { LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed: FIN_WAIT_1 %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest)); tcp_ack_now(pcb); tcp_pcb_purge(pcb); TCP_RMV_ACTIVE(pcb); pcb->state = TIME_WAIT; TCP_REG(&tcp_tw_pcbs, pcb); } else { tcp_ack_now(pcb); pcb->state = CLOSING; } } else if ((flags & TCP_ACK) && (ackno == pcb->snd_nxt)) { pcb->state = FIN_WAIT_2; } break; case FIN_WAIT_2: tcp_receive(pcb); if (recv_flags & TF_GOT_FIN) { LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed: FIN_WAIT_2 %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest)); tcp_ack_now(pcb); tcp_pcb_purge(pcb); TCP_RMV_ACTIVE(pcb); pcb->state = TIME_WAIT; TCP_REG(&tcp_tw_pcbs, pcb); } break; case CLOSING: tcp_receive(pcb); if (flags & TCP_ACK && ackno == pcb->snd_nxt) { LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed: CLOSING %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest)); tcp_pcb_purge(pcb); TCP_RMV_ACTIVE(pcb); pcb->state = TIME_WAIT; TCP_REG(&tcp_tw_pcbs, pcb); } break; case LAST_ACK: tcp_receive(pcb); if (flags & TCP_ACK && ackno == pcb->snd_nxt) { LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed: LAST_ACK %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest)); /* bugfix #21699: don't set pcb->state to CLOSED here or we risk leaking segments */ recv_flags |= TF_CLOSED; } break; default: break; } return ERR_OK; } #if TCP_QUEUE_OOSEQ /** * Insert segment into the list (segments covered with new one will be deleted) * * Called from tcp_receive() */ static void tcp_oos_insert_segment(struct tcp_seg *cseg, struct tcp_seg *next) { struct tcp_seg *old_seg; if (TCPH_FLAGS(cseg->tcphdr) & TCP_FIN) { /* received segment overlaps all following segments */ tcp_segs_free(next); next = NULL; } else { /* delete some following segments oos queue may have segments with FIN flag */ while (next && TCP_SEQ_GEQ((seqno + cseg->len), (next->tcphdr->seqno + next->len))) { /* cseg with FIN already processed */ if (TCPH_FLAGS(next->tcphdr) & TCP_FIN) { TCPH_SET_FLAG(cseg->tcphdr, TCP_FIN); } old_seg = next; next = next->next; tcp_seg_free(old_seg); } if (next && TCP_SEQ_GT(seqno + cseg->len, next->tcphdr->seqno)) { /* We need to trim the incoming segment. */ cseg->len = (u16_t)(next->tcphdr->seqno - seqno); pbuf_realloc(cseg->p, cseg->len); } } cseg->next = next; } #endif /* TCP_QUEUE_OOSEQ */ /** * Called by tcp_process. Checks if the given segment is an ACK for outstanding * data, and if so frees the memory of the buffered data. Next, is places the * segment on any of the receive queues (pcb->recved or pcb->ooseq). If the segment * is buffered, the pbuf is referenced by pbuf_ref so that it will not be freed until * it has been removed from the buffer. * * If the incoming segment constitutes an ACK for a segment that was used for RTT * estimation, the RTT is estimated here as well. * * Called from tcp_process(). */ static void tcp_receive(struct tcp_pcb *pcb) { struct tcp_seg *next; #if TCP_QUEUE_OOSEQ struct tcp_seg *prev, *cseg; #endif /* TCP_QUEUE_OOSEQ */ struct pbuf *p; s32_t off; s16_t m; u32_t right_wnd_edge; u16_t new_tot_len; int found_dupack = 0; #if TCP_OOSEQ_MAX_BYTES || TCP_OOSEQ_MAX_PBUFS u32_t ooseq_blen; u16_t ooseq_qlen; #endif /* TCP_OOSEQ_MAX_BYTES || TCP_OOSEQ_MAX_PBUFS */ LWIP_ASSERT("tcp_receive: wrong state", pcb->state >= ESTABLISHED); if (flags & TCP_ACK) { right_wnd_edge = pcb->snd_wnd + pcb->snd_wl2; /* Update window. */ if (TCP_SEQ_LT(pcb->snd_wl1, seqno) || (pcb->snd_wl1 == seqno && TCP_SEQ_LT(pcb->snd_wl2, ackno)) || (pcb->snd_wl2 == ackno && tcphdr->wnd > pcb->snd_wnd)) { pcb->snd_wnd = SND_WND_SCALE(pcb, tcphdr->wnd); /* keep track of the biggest window announced by the remote host to calculate the maximum segment size */ if (pcb->snd_wnd_max < pcb->snd_wnd) { pcb->snd_wnd_max = pcb->snd_wnd; } pcb->snd_wl1 = seqno; pcb->snd_wl2 = ackno; if (pcb->snd_wnd == 0) { if (pcb->persist_backoff == 0) { /* start persist timer */ pcb->persist_cnt = 0; pcb->persist_backoff = 1; } } else if (pcb->persist_backoff > 0) { /* stop persist timer */ pcb->persist_backoff = 0; } LWIP_DEBUGF(TCP_WND_DEBUG, ("tcp_receive: window update %"U16_F"\n", pcb->snd_wnd)); #if TCP_WND_DEBUG } else { if (pcb->snd_wnd != tcphdr->wnd) { LWIP_DEBUGF(TCP_WND_DEBUG, ("tcp_receive: no window update lastack %"U32_F" ackno %" U32_F" wl1 %"U32_F" seqno %"U32_F" wl2 %"U32_F"\n", pcb->lastack, ackno, pcb->snd_wl1, seqno, pcb->snd_wl2)); } #endif /* TCP_WND_DEBUG */ } /* (From Stevens TCP/IP Illustrated Vol II, p970.) Its only a * duplicate ack if: * 1) It doesn't ACK new data * 2) length of received packet is zero (i.e. no payload) * 3) the advertised window hasn't changed * 4) There is outstanding unacknowledged data (retransmission timer running) * 5) The ACK is == biggest ACK sequence number so far seen (snd_una) * * If it passes all five, should process as a dupack: * a) dupacks < 3: do nothing * b) dupacks == 3: fast retransmit * c) dupacks > 3: increase cwnd * * If it only passes 1-3, should reset dupack counter (and add to * stats, which we don't do in lwIP) * * If it only passes 1, should reset dupack counter * */ /* Clause 1 */ if (TCP_SEQ_LEQ(ackno, pcb->lastack)) { pcb->acked = 0; /* Clause 2 */ if (tcplen == 0) { /* Clause 3 */ if (pcb->snd_wl2 + pcb->snd_wnd == right_wnd_edge){ /* Clause 4 */ if (pcb->rtime >= 0) { /* Clause 5 */ if (pcb->lastack == ackno) { found_dupack = 1; if ((u8_t)(pcb->dupacks + 1) > pcb->dupacks) { ++pcb->dupacks; } if (pcb->dupacks > 3) { /* Inflate the congestion window, but not if it means that the value overflows. */ if ((tcpwnd_size_t)(pcb->cwnd + pcb->mss) > pcb->cwnd) { pcb->cwnd += pcb->mss; } } else if (pcb->dupacks == 3) { /* Do fast retransmit */ tcp_rexmit_fast(pcb); } } } } } /* If Clause (1) or more is true, but not a duplicate ack, reset * count of consecutive duplicate acks */ if (!found_dupack) { pcb->dupacks = 0; } } else if (TCP_SEQ_BETWEEN(ackno, pcb->lastack+1, pcb->snd_nxt)){ /* We come here when the ACK acknowledges new data. */ /* Reset the "IN Fast Retransmit" flag, since we are no longer in fast retransmit. Also reset the congestion window to the slow start threshold. */ if (pcb->flags & TF_INFR) { pcb->flags &= ~TF_INFR; pcb->cwnd = pcb->ssthresh; } /* Reset the number of retransmissions. */ pcb->nrtx = 0; /* Reset the retransmission time-out. */ pcb->rto = (pcb->sa >> 3) + pcb->sv; /* Update the send buffer space. Diff between the two can never exceed 64K unless window scaling is used. */ pcb->acked = (tcpwnd_size_t)(ackno - pcb->lastack); pcb->snd_buf += pcb->acked; /* Reset the fast retransmit variables. */ pcb->dupacks = 0; pcb->lastack = ackno; /* Update the congestion control variables (cwnd and ssthresh). */ if (pcb->state >= ESTABLISHED) { if (pcb->cwnd < pcb->ssthresh) { if ((tcpwnd_size_t)(pcb->cwnd + pcb->mss) > pcb->cwnd) { pcb->cwnd += pcb->mss; } LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_receive: slow start cwnd %"TCPWNDSIZE_F"\n", pcb->cwnd)); } else { tcpwnd_size_t new_cwnd = (pcb->cwnd + pcb->mss * pcb->mss / pcb->cwnd); if (new_cwnd > pcb->cwnd) { pcb->cwnd = new_cwnd; } LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_receive: congestion avoidance cwnd %"TCPWNDSIZE_F"\n", pcb->cwnd)); } } LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: ACK for %"U32_F", unacked->seqno %"U32_F":%"U32_F"\n", ackno, pcb->unacked != NULL? ntohl(pcb->unacked->tcphdr->seqno): 0, pcb->unacked != NULL? ntohl(pcb->unacked->tcphdr->seqno) + TCP_TCPLEN(pcb->unacked): 0)); /* Remove segment from the unacknowledged list if the incoming ACK acknowlegdes them. */ while (pcb->unacked != NULL && TCP_SEQ_LEQ(ntohl(pcb->unacked->tcphdr->seqno) + TCP_TCPLEN(pcb->unacked), ackno)) { LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: removing %"U32_F":%"U32_F" from pcb->unacked\n", ntohl(pcb->unacked->tcphdr->seqno), ntohl(pcb->unacked->tcphdr->seqno) + TCP_TCPLEN(pcb->unacked))); next = pcb->unacked; pcb->unacked = pcb->unacked->next; LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_receive: queuelen %"TCPWNDSIZE_F" ... ", (tcpwnd_size_t)pcb->snd_queuelen)); LWIP_ASSERT("pcb->snd_queuelen >= pbuf_clen(next->p)", (pcb->snd_queuelen >= pbuf_clen(next->p))); /* Prevent ACK for FIN to generate a sent event */ if ((pcb->acked != 0) && ((TCPH_FLAGS(next->tcphdr) & TCP_FIN) != 0)) { pcb->acked--; } pcb->snd_queuelen -= pbuf_clen(next->p); tcp_seg_free(next); LWIP_DEBUGF(TCP_QLEN_DEBUG, ("%"TCPWNDSIZE_F" (after freeing unacked)\n", (tcpwnd_size_t)pcb->snd_queuelen)); if (pcb->snd_queuelen != 0) { LWIP_ASSERT("tcp_receive: valid queue length", pcb->unacked != NULL || pcb->unsent != NULL); } } /* If there's nothing left to acknowledge, stop the retransmit timer, otherwise reset it to start again */ if (pcb->unacked == NULL) { pcb->rtime = -1; } else { pcb->rtime = 0; } pcb->polltmr = 0; #if LWIP_IPV6 && LWIP_ND6_TCP_REACHABILITY_HINTS if (PCB_ISIPV6(pcb)) { /* Inform neighbor reachability of forward progress. */ nd6_reachability_hint(ip6_current_src_addr()); } #endif /* LWIP_IPV6 && LWIP_ND6_TCP_REACHABILITY_HINTS*/ } else { /* Out of sequence ACK, didn't really ack anything */ pcb->acked = 0; tcp_send_empty_ack(pcb); } /* We go through the ->unsent list to see if any of the segments on the list are acknowledged by the ACK. This may seem strange since an "unsent" segment shouldn't be acked. The rationale is that lwIP puts all outstanding segments on the ->unsent list after a retransmission, so these segments may in fact have been sent once. */ while (pcb->unsent != NULL && TCP_SEQ_BETWEEN(ackno, ntohl(pcb->unsent->tcphdr->seqno) + TCP_TCPLEN(pcb->unsent), pcb->snd_nxt)) { LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: removing %"U32_F":%"U32_F" from pcb->unsent\n", ntohl(pcb->unsent->tcphdr->seqno), ntohl(pcb->unsent->tcphdr->seqno) + TCP_TCPLEN(pcb->unsent))); next = pcb->unsent; pcb->unsent = pcb->unsent->next; #if TCP_OVERSIZE if (pcb->unsent == NULL) { pcb->unsent_oversize = 0; } #endif /* TCP_OVERSIZE */ LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_receive: queuelen %"TCPWNDSIZE_F" ... ", (tcpwnd_size_t)pcb->snd_queuelen)); LWIP_ASSERT("pcb->snd_queuelen >= pbuf_clen(next->p)", (pcb->snd_queuelen >= pbuf_clen(next->p))); /* Prevent ACK for FIN to generate a sent event */ if ((pcb->acked != 0) && ((TCPH_FLAGS(next->tcphdr) & TCP_FIN) != 0)) { pcb->acked--; } pcb->snd_queuelen -= pbuf_clen(next->p); tcp_seg_free(next); LWIP_DEBUGF(TCP_QLEN_DEBUG, ("%"TCPWNDSIZE_F" (after freeing unsent)\n", (tcpwnd_size_t)pcb->snd_queuelen)); if (pcb->snd_queuelen != 0) { LWIP_ASSERT("tcp_receive: valid queue length", pcb->unacked != NULL || pcb->unsent != NULL); } } /* End of ACK for new data processing. */ LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_receive: pcb->rttest %"U32_F" rtseq %"U32_F" ackno %"U32_F"\n", pcb->rttest, pcb->rtseq, ackno)); /* RTT estimation calculations. This is done by checking if the incoming segment acknowledges the segment we use to take a round-trip time measurement. */ if (pcb->rttest && TCP_SEQ_LT(pcb->rtseq, ackno)) { /* diff between this shouldn't exceed 32K since this are tcp timer ticks and a round-trip shouldn't be that long... */ m = (s16_t)(tcp_ticks - pcb->rttest); LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_receive: experienced rtt %"U16_F" ticks (%"U16_F" msec).\n", m, m * TCP_SLOW_INTERVAL)); /* This is taken directly from VJs original code in his paper */ m = m - (pcb->sa >> 3); pcb->sa += m; if (m < 0) { m = -m; } m = m - (pcb->sv >> 2); pcb->sv += m; pcb->rto = (pcb->sa >> 3) + pcb->sv; LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_receive: RTO %"U16_F" (%"U16_F" milliseconds)\n", pcb->rto, pcb->rto * TCP_SLOW_INTERVAL)); pcb->rttest = 0; } } /* If the incoming segment contains data, we must process it further unless the pcb already received a FIN. (RFC 793, chapeter 3.9, "SEGMENT ARRIVES" in states CLOSE-WAIT, CLOSING, LAST-ACK and TIME-WAIT: "Ignore the segment text.") */ if ((tcplen > 0) && (pcb->state < CLOSE_WAIT)) { /* This code basically does three things: +) If the incoming segment contains data that is the next in-sequence data, this data is passed to the application. This might involve trimming the first edge of the data. The rcv_nxt variable and the advertised window are adjusted. +) If the incoming segment has data that is above the next sequence number expected (->rcv_nxt), the segment is placed on the ->ooseq queue. This is done by finding the appropriate place in the ->ooseq queue (which is ordered by sequence number) and trim the segment in both ends if needed. An immediate ACK is sent to indicate that we received an out-of-sequence segment. +) Finally, we check if the first segment on the ->ooseq queue now is in sequence (i.e., if rcv_nxt >= ooseq->seqno). If rcv_nxt > ooseq->seqno, we must trim the first edge of the segment on ->ooseq before we adjust rcv_nxt. The data in the segments that are now on sequence are chained onto the incoming segment so that we only need to call the application once. */ /* First, we check if we must trim the first edge. We have to do this if the sequence number of the incoming segment is less than rcv_nxt, and the sequence number plus the length of the segment is larger than rcv_nxt. */ /* if (TCP_SEQ_LT(seqno, pcb->rcv_nxt)){ if (TCP_SEQ_LT(pcb->rcv_nxt, seqno + tcplen)) {*/ if (TCP_SEQ_BETWEEN(pcb->rcv_nxt, seqno + 1, seqno + tcplen - 1)){ /* Trimming the first edge is done by pushing the payload pointer in the pbuf downwards. This is somewhat tricky since we do not want to discard the full contents of the pbuf up to the new starting point of the data since we have to keep the TCP header which is present in the first pbuf in the chain. What is done is really quite a nasty hack: the first pbuf in the pbuf chain is pointed to by inseg.p. Since we need to be able to deallocate the whole pbuf, we cannot change this inseg.p pointer to point to any of the later pbufs in the chain. Instead, we point the ->payload pointer in the first pbuf to data in one of the later pbufs. We also set the inseg.data pointer to point to the right place. This way, the ->p pointer will still point to the first pbuf, but the ->p->payload pointer will point to data in another pbuf. After we are done with adjusting the pbuf pointers we must adjust the ->data pointer in the seg and the segment length.*/ off = pcb->rcv_nxt - seqno; p = inseg.p; LWIP_ASSERT("inseg.p != NULL", inseg.p); LWIP_ASSERT("insane offset!", (off < 0x7fff)); if (inseg.p->len < off) { LWIP_ASSERT("pbuf too short!", (((s32_t)inseg.p->tot_len) >= off)); new_tot_len = (u16_t)(inseg.p->tot_len - off); while (p->len < off) { off -= p->len; /* KJM following line changed (with addition of new_tot_len var) to fix bug #9076 inseg.p->tot_len -= p->len; */ p->tot_len = new_tot_len; p->len = 0; p = p->next; } if(pbuf_header(p, (s16_t)-off)) { /* Do we need to cope with this failing? Assert for now */ LWIP_ASSERT("pbuf_header failed", 0); } } else { if(pbuf_header(inseg.p, (s16_t)-off)) { /* Do we need to cope with this failing? Assert for now */ LWIP_ASSERT("pbuf_header failed", 0); } } inseg.len -= (u16_t)(pcb->rcv_nxt - seqno); inseg.tcphdr->seqno = seqno = pcb->rcv_nxt; } else { if (TCP_SEQ_LT(seqno, pcb->rcv_nxt)){ /* the whole segment is < rcv_nxt */ /* must be a duplicate of a packet that has already been correctly handled */ LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: duplicate seqno %"U32_F"\n", seqno)); tcp_ack_now(pcb); } } /* The sequence number must be within the window (above rcv_nxt and below rcv_nxt + rcv_wnd) in order to be further processed. */ if (TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, pcb->rcv_nxt + pcb->rcv_wnd - 1)){ if (pcb->rcv_nxt == seqno) { /* The incoming segment is the next in sequence. We check if we have to trim the end of the segment and update rcv_nxt and pass the data to the application. */ tcplen = TCP_TCPLEN(&inseg); if (tcplen > pcb->rcv_wnd) { LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: other end overran receive window" "seqno %"U32_F" len %"U16_F" right edge %"U32_F"\n", seqno, tcplen, pcb->rcv_nxt + pcb->rcv_wnd)); if (TCPH_FLAGS(inseg.tcphdr) & TCP_FIN) { /* Must remove the FIN from the header as we're trimming * that byte of sequence-space from the packet */ TCPH_FLAGS_SET(inseg.tcphdr, TCPH_FLAGS(inseg.tcphdr) &~ TCP_FIN); } /* Adjust length of segment to fit in the window. */ inseg.len = pcb->rcv_wnd; if (TCPH_FLAGS(inseg.tcphdr) & TCP_SYN) { inseg.len -= 1; } pbuf_realloc(inseg.p, inseg.len); tcplen = TCP_TCPLEN(&inseg); LWIP_ASSERT("tcp_receive: segment not trimmed correctly to rcv_wnd\n", (seqno + tcplen) == (pcb->rcv_nxt + pcb->rcv_wnd)); } #if TCP_QUEUE_OOSEQ /* Received in-sequence data, adjust ooseq data if: - FIN has been received or - inseq overlaps with ooseq */ if (pcb->ooseq != NULL) { if (TCPH_FLAGS(inseg.tcphdr) & TCP_FIN) { LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: received in-order FIN, binning ooseq queue\n")); /* Received in-order FIN means anything that was received * out of order must now have been received in-order, so * bin the ooseq queue */ while (pcb->ooseq != NULL) { struct tcp_seg *old_ooseq = pcb->ooseq; pcb->ooseq = pcb->ooseq->next; tcp_seg_free(old_ooseq); } } else { next = pcb->ooseq; /* Remove all segments on ooseq that are covered by inseg already. * FIN is copied from ooseq to inseg if present. */ while (next && TCP_SEQ_GEQ(seqno + tcplen, next->tcphdr->seqno + next->len)) { /* inseg cannot have FIN here (already processed above) */ if (TCPH_FLAGS(next->tcphdr) & TCP_FIN && (TCPH_FLAGS(inseg.tcphdr) & TCP_SYN) == 0) { TCPH_SET_FLAG(inseg.tcphdr, TCP_FIN); tcplen = TCP_TCPLEN(&inseg); } prev = next; next = next->next; tcp_seg_free(prev); } /* Now trim right side of inseg if it overlaps with the first * segment on ooseq */ if (next && TCP_SEQ_GT(seqno + tcplen, next->tcphdr->seqno)) { /* inseg cannot have FIN here (already processed above) */ inseg.len = (u16_t)(next->tcphdr->seqno - seqno); if (TCPH_FLAGS(inseg.tcphdr) & TCP_SYN) { inseg.len -= 1; } pbuf_realloc(inseg.p, inseg.len); tcplen = TCP_TCPLEN(&inseg); LWIP_ASSERT("tcp_receive: segment not trimmed correctly to ooseq queue\n", (seqno + tcplen) == next->tcphdr->seqno); } pcb->ooseq = next; } } #endif /* TCP_QUEUE_OOSEQ */ pcb->rcv_nxt = seqno + tcplen; /* Update the receiver's (our) window. */ LWIP_ASSERT("tcp_receive: tcplen > rcv_wnd\n", pcb->rcv_wnd >= tcplen); pcb->rcv_wnd -= tcplen; tcp_update_rcv_ann_wnd(pcb); /* If there is data in the segment, we make preparations to pass this up to the application. The ->recv_data variable is used for holding the pbuf that goes to the application. The code for reassembling out-of-sequence data chains its data on this pbuf as well. If the segment was a FIN, we set the TF_GOT_FIN flag that will be used to indicate to the application that the remote side has closed its end of the connection. */ if (inseg.p->tot_len > 0) { recv_data = inseg.p; /* Since this pbuf now is the responsibility of the application, we delete our reference to it so that we won't (mistakingly) deallocate it. */ inseg.p = NULL; } if (TCPH_FLAGS(inseg.tcphdr) & TCP_FIN) { LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: received FIN.\n")); recv_flags |= TF_GOT_FIN; } #if TCP_QUEUE_OOSEQ /* We now check if we have segments on the ->ooseq queue that are now in sequence. */ while (pcb->ooseq != NULL && pcb->ooseq->tcphdr->seqno == pcb->rcv_nxt) { cseg = pcb->ooseq; seqno = pcb->ooseq->tcphdr->seqno; pcb->rcv_nxt += TCP_TCPLEN(cseg); LWIP_ASSERT("tcp_receive: ooseq tcplen > rcv_wnd\n", pcb->rcv_wnd >= TCP_TCPLEN(cseg)); pcb->rcv_wnd -= TCP_TCPLEN(cseg); tcp_update_rcv_ann_wnd(pcb); if (cseg->p->tot_len > 0) { /* Chain this pbuf onto the pbuf that we will pass to the application. */ /* With window scaling, this can overflow recv_data->tot_len, but that's not a problem since we explicitly fix that before passing recv_data to the application. */ if (recv_data) { pbuf_cat(recv_data, cseg->p); } else { recv_data = cseg->p; } cseg->p = NULL; } if (TCPH_FLAGS(cseg->tcphdr) & TCP_FIN) { LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: dequeued FIN.\n")); recv_flags |= TF_GOT_FIN; if (pcb->state == ESTABLISHED) { /* force passive close or we can move to active close */ pcb->state = CLOSE_WAIT; } } pcb->ooseq = cseg->next; tcp_seg_free(cseg); } #endif /* TCP_QUEUE_OOSEQ */ /* Acknowledge the segment(s). */ tcp_ack(pcb); #if LWIP_IPV6 && LWIP_ND6_TCP_REACHABILITY_HINTS if (PCB_ISIPV6(pcb)) { /* Inform neighbor reachability of forward progress. */ nd6_reachability_hint(ip6_current_src_addr()); } #endif /* LWIP_IPV6 && LWIP_ND6_TCP_REACHABILITY_HINTS*/ } else { /* We get here if the incoming segment is out-of-sequence. */ tcp_send_empty_ack(pcb); #if TCP_QUEUE_OOSEQ /* We queue the segment on the ->ooseq queue. */ if (pcb->ooseq == NULL) { pcb->ooseq = tcp_seg_copy(&inseg); } else { /* If the queue is not empty, we walk through the queue and try to find a place where the sequence number of the incoming segment is between the sequence numbers of the previous and the next segment on the ->ooseq queue. That is the place where we put the incoming segment. If needed, we trim the second edges of the previous and the incoming segment so that it will fit into the sequence. If the incoming segment has the same sequence number as a segment on the ->ooseq queue, we discard the segment that contains less data. */ prev = NULL; for(next = pcb->ooseq; next != NULL; next = next->next) { if (seqno == next->tcphdr->seqno) { /* The sequence number of the incoming segment is the same as the sequence number of the segment on ->ooseq. We check the lengths to see which one to discard. */ if (inseg.len > next->len) { /* The incoming segment is larger than the old segment. We replace some segments with the new one. */ cseg = tcp_seg_copy(&inseg); if (cseg != NULL) { if (prev != NULL) { prev->next = cseg; } else { pcb->ooseq = cseg; } tcp_oos_insert_segment(cseg, next); } break; } else { /* Either the lenghts are the same or the incoming segment was smaller than the old one; in either case, we ditch the incoming segment. */ break; } } else { if (prev == NULL) { if (TCP_SEQ_LT(seqno, next->tcphdr->seqno)) { /* The sequence number of the incoming segment is lower than the sequence number of the first segment on the queue. We put the incoming segment first on the queue. */ cseg = tcp_seg_copy(&inseg); if (cseg != NULL) { pcb->ooseq = cseg; tcp_oos_insert_segment(cseg, next); } break; } } else { /*if (TCP_SEQ_LT(prev->tcphdr->seqno, seqno) && TCP_SEQ_LT(seqno, next->tcphdr->seqno)) {*/ if (TCP_SEQ_BETWEEN(seqno, prev->tcphdr->seqno+1, next->tcphdr->seqno-1)) { /* The sequence number of the incoming segment is in between the sequence numbers of the previous and the next segment on ->ooseq. We trim trim the previous segment, delete next segments that included in received segment and trim received, if needed. */ cseg = tcp_seg_copy(&inseg); if (cseg != NULL) { if (TCP_SEQ_GT(prev->tcphdr->seqno + prev->len, seqno)) { /* We need to trim the prev segment. */ prev->len = (u16_t)(seqno - prev->tcphdr->seqno); pbuf_realloc(prev->p, prev->len); } prev->next = cseg; tcp_oos_insert_segment(cseg, next); } break; } } /* If the "next" segment is the last segment on the ooseq queue, we add the incoming segment to the end of the list. */ if (next->next == NULL && TCP_SEQ_GT(seqno, next->tcphdr->seqno)) { if (TCPH_FLAGS(next->tcphdr) & TCP_FIN) { /* segment "next" already contains all data */ break; } next->next = tcp_seg_copy(&inseg); if (next->next != NULL) { if (TCP_SEQ_GT(next->tcphdr->seqno + next->len, seqno)) { /* We need to trim the last segment. */ next->len = (u16_t)(seqno - next->tcphdr->seqno); pbuf_realloc(next->p, next->len); } /* check if the remote side overruns our receive window */ if ((u32_t)tcplen + seqno > pcb->rcv_nxt + (u32_t)pcb->rcv_wnd) { LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: other end overran receive window" "seqno %"U32_F" len %"U16_F" right edge %"U32_F"\n", seqno, tcplen, pcb->rcv_nxt + pcb->rcv_wnd)); if (TCPH_FLAGS(next->next->tcphdr) & TCP_FIN) { /* Must remove the FIN from the header as we're trimming * that byte of sequence-space from the packet */ TCPH_FLAGS_SET(next->next->tcphdr, TCPH_FLAGS(next->next->tcphdr) &~ TCP_FIN); } /* Adjust length of segment to fit in the window. */ next->next->len = pcb->rcv_nxt + pcb->rcv_wnd - seqno; pbuf_realloc(next->next->p, next->next->len); tcplen = TCP_TCPLEN(next->next); LWIP_ASSERT("tcp_receive: segment not trimmed correctly to rcv_wnd\n", (seqno + tcplen) == (pcb->rcv_nxt + pcb->rcv_wnd)); } } break; } } prev = next; } } #if TCP_OOSEQ_MAX_BYTES || TCP_OOSEQ_MAX_PBUFS /* Check that the data on ooseq doesn't exceed one of the limits and throw away everything above that limit. */ ooseq_blen = 0; ooseq_qlen = 0; prev = NULL; for(next = pcb->ooseq; next != NULL; prev = next, next = next->next) { struct pbuf *p = next->p; ooseq_blen += p->tot_len; ooseq_qlen += pbuf_clen(p); if ((ooseq_blen > TCP_OOSEQ_MAX_BYTES) || (ooseq_qlen > TCP_OOSEQ_MAX_PBUFS)) { /* too much ooseq data, dump this and everything after it */ tcp_segs_free(next); if (prev == NULL) { /* first ooseq segment is too much, dump the whole queue */ pcb->ooseq = NULL; } else { /* just dump 'next' and everything after it */ prev->next = NULL; } break; } } #endif /* TCP_OOSEQ_MAX_BYTES || TCP_OOSEQ_MAX_PBUFS */ #endif /* TCP_QUEUE_OOSEQ */ } } else { /* The incoming segment is not withing the window. */ tcp_send_empty_ack(pcb); } } else { /* Segments with length 0 is taken care of here. Segments that fall out of the window are ACKed. */ /*if (TCP_SEQ_GT(pcb->rcv_nxt, seqno) || TCP_SEQ_GEQ(seqno, pcb->rcv_nxt + pcb->rcv_wnd)) {*/ if(!TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, pcb->rcv_nxt + pcb->rcv_wnd-1)){ tcp_ack_now(pcb); } } } static u8_t tcp_getoptbyte(void) { if ((tcphdr_opt2 == NULL) || (tcp_optidx < tcphdr_opt1len)) { u8_t* opts = (u8_t *)tcphdr + TCP_HLEN; return opts[tcp_optidx++]; } else { u8_t idx = tcp_optidx++ - tcphdr_opt1len; return tcphdr_opt2[idx]; } } /** * Parses the options contained in the incoming segment. * * Called from tcp_listen_input() and tcp_process(). * Currently, only the MSS option is supported! * * @param pcb the tcp_pcb for which a segment arrived */ static void tcp_parseopt(struct tcp_pcb *pcb) { u8_t data; u16_t mss; #if LWIP_TCP_TIMESTAMPS u32_t tsval; #endif /* Parse the TCP MSS option, if present. */ if (TCPH_HDRLEN(tcphdr) > 0x5) { u16_t max_c = (TCPH_HDRLEN(tcphdr) - 5) << 2; for (tcp_optidx = 0; tcp_optidx < max_c; ) { u8_t opt = tcp_getoptbyte(); switch (opt) { case LWIP_TCP_OPT_EOL: /* End of options. */ LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: EOL\n")); return; case LWIP_TCP_OPT_NOP: /* NOP option. */ LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: NOP\n")); break; case LWIP_TCP_OPT_MSS: LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: MSS\n")); if (tcp_getoptbyte() != LWIP_TCP_OPT_LEN_MSS || (tcp_optidx - 2 + LWIP_TCP_OPT_LEN_MSS) > max_c) { /* Bad length */ LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: bad length\n")); return; } /* An MSS option with the right option length. */ mss = (tcp_getoptbyte() << 8); mss |= tcp_getoptbyte(); /* Limit the mss to the configured TCP_MSS and prevent division by zero */ pcb->mss = ((mss > TCP_MSS) || (mss == 0)) ? TCP_MSS : mss; break; #if LWIP_WND_SCALE case LWIP_TCP_OPT_WS: LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: WND_SCALE\n")); if (tcp_getoptbyte() != LWIP_TCP_OPT_LEN_WS || (tcp_optidx - 2 + LWIP_TCP_OPT_LEN_WS) > max_c) { /* Bad length */ LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: bad length\n")); return; } /* If syn was received with wnd scale option, activate wnd scale opt */ data = tcp_getoptbyte(); if (flags & TCP_SYN) { /* An WND_SCALE option with the right option length. */ pcb->snd_scale = data; if (pcb->snd_scale > 14U) { pcb->snd_scale = 14U; } pcb->rcv_scale = TCP_RCV_SCALE; pcb->flags |= TF_WND_SCALE; } break; #endif #if LWIP_TCP_TIMESTAMPS case LWIP_TCP_OPT_TS: LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: TS\n")); if (tcp_getoptbyte() != LWIP_TCP_OPT_LEN_TS || (tcp_optidx - 2 + LWIP_TCP_OPT_LEN_TS) > max_c) { /* Bad length */ LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: bad length\n")); return; } /* TCP timestamp option with valid length */ tsval = tcp_getoptbyte(); tsval |= (tcp_getoptbyte() << 8); tsval |= (tcp_getoptbyte() << 16); tsval |= (tcp_getoptbyte() << 24); if (flags & TCP_SYN) { pcb->ts_recent = ntohl(tsval); /* Enable sending timestamps in every segment now that we know the remote host supports it. */ pcb->flags |= TF_TIMESTAMP; } else if (TCP_SEQ_BETWEEN(pcb->ts_lastacksent, seqno, seqno+tcplen)) { pcb->ts_recent = ntohl(tsval); } /* Advance to next option (6 bytes already read) */ tcp_optidx += LWIP_TCP_OPT_LEN_TS - 6; break; #endif default: LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: other\n")); data = tcp_getoptbyte(); if (data < 2) { LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: bad length\n")); /* If the length field is zero, the options are malformed and we don't process them further. */ return; } /* All other options have a length field, so that we easily can skip past them. */ tcp_optidx += data - 2; } } } } #endif /* LWIP_TCP */ ocproxy-1.60/lwip/src/core/tcp_out.c000066400000000000000000001475421303453231400174710ustar00rootroot00000000000000/** * @file * Transmission Control Protocol, outgoing traffic * * The output functions of TCP. * */ /* * Copyright (c) 2001-2004 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #include "lwip/opt.h" #if LWIP_TCP /* don't build if not configured for use in lwipopts.h */ #include "lwip/tcp_impl.h" #include "lwip/def.h" #include "lwip/mem.h" #include "lwip/memp.h" #include "lwip/ip_addr.h" #include "lwip/netif.h" #include "lwip/inet_chksum.h" #include "lwip/stats.h" #include "lwip/snmp.h" #include "lwip/ip6.h" #include "lwip/ip6_addr.h" #include "lwip/inet_chksum.h" #if LWIP_TCP_TIMESTAMPS #include "lwip/sys.h" #endif #include /* Define some copy-macros for checksum-on-copy so that the code looks nicer by preventing too many ifdef's. */ #if TCP_CHECKSUM_ON_COPY #define TCP_DATA_COPY(dst, src, len, seg) do { \ tcp_seg_add_chksum(LWIP_CHKSUM_COPY(dst, src, len), \ len, &seg->chksum, &seg->chksum_swapped); \ seg->flags |= TF_SEG_DATA_CHECKSUMMED; } while(0) #define TCP_DATA_COPY2(dst, src, len, chksum, chksum_swapped) \ tcp_seg_add_chksum(LWIP_CHKSUM_COPY(dst, src, len), len, chksum, chksum_swapped); #else /* TCP_CHECKSUM_ON_COPY*/ #define TCP_DATA_COPY(dst, src, len, seg) MEMCPY(dst, src, len) #define TCP_DATA_COPY2(dst, src, len, chksum, chksum_swapped) MEMCPY(dst, src, len) #endif /* TCP_CHECKSUM_ON_COPY*/ /** Define this to 1 for an extra check that the output checksum is valid * (usefule when the checksum is generated by the application, not the stack) */ #ifndef TCP_CHECKSUM_ON_COPY_SANITY_CHECK #define TCP_CHECKSUM_ON_COPY_SANITY_CHECK 0 #endif /* Forward declarations.*/ static void tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb); /** Allocate a pbuf and create a tcphdr at p->payload, used for output * functions other than the default tcp_output -> tcp_output_segment * (e.g. tcp_send_empty_ack, etc.) * * @param pcb tcp pcb for which to send a packet (used to initialize tcp_hdr) * @param optlen length of header-options * @param datalen length of tcp data to reserve in pbuf * @param seqno_be seqno in network byte order (big-endian) * @return pbuf with p->payload being the tcp_hdr */ static struct pbuf * tcp_output_alloc_header(struct tcp_pcb *pcb, u16_t optlen, u16_t datalen, u32_t seqno_be /* already in network byte order */) { struct tcp_hdr *tcphdr; struct pbuf *p = pbuf_alloc(PBUF_IP, TCP_HLEN + optlen + datalen, PBUF_RAM); if (p != NULL) { LWIP_ASSERT("check that first pbuf can hold struct tcp_hdr", (p->len >= TCP_HLEN + optlen)); tcphdr = (struct tcp_hdr *)p->payload; tcphdr->src = htons(pcb->local_port); tcphdr->dest = htons(pcb->remote_port); tcphdr->seqno = seqno_be; tcphdr->ackno = htonl(pcb->rcv_nxt); TCPH_HDRLEN_FLAGS_SET(tcphdr, (5 + optlen / 4), TCP_ACK); tcphdr->wnd = htons(RCV_WND_SCALE(pcb, pcb->rcv_ann_wnd)); tcphdr->chksum = 0; tcphdr->urgp = 0; /* If we're sending a packet, update the announced right window edge */ pcb->rcv_ann_right_edge = pcb->rcv_nxt + pcb->rcv_ann_wnd; } return p; } /** * Called by tcp_close() to send a segment including FIN flag but not data. * * @param pcb the tcp_pcb over which to send a segment * @return ERR_OK if sent, another err_t otherwise */ err_t tcp_send_fin(struct tcp_pcb *pcb) { /* first, try to add the fin to the last unsent segment */ if (pcb->unsent != NULL) { struct tcp_seg *last_unsent; for (last_unsent = pcb->unsent; last_unsent->next != NULL; last_unsent = last_unsent->next); if ((TCPH_FLAGS(last_unsent->tcphdr) & (TCP_SYN | TCP_FIN | TCP_RST)) == 0) { /* no SYN/FIN/RST flag in the header, we can add the FIN flag */ TCPH_SET_FLAG(last_unsent->tcphdr, TCP_FIN); pcb->flags |= TF_FIN; return ERR_OK; } } /* no data, no length, flags, copy=1, no optdata */ return tcp_enqueue_flags(pcb, TCP_FIN); } /** * Create a TCP segment with prefilled header. * * Called by tcp_write and tcp_enqueue_flags. * * @param pcb Protocol control block for the TCP connection. * @param p pbuf that is used to hold the TCP header. * @param flags TCP flags for header. * @param seqno TCP sequence number of this packet * @param optflags options to include in TCP header * @return a new tcp_seg pointing to p, or NULL. * The TCP header is filled in except ackno and wnd. * p is freed on failure. */ static struct tcp_seg * tcp_create_segment(struct tcp_pcb *pcb, struct pbuf *p, u8_t flags, u32_t seqno, u8_t optflags) { struct tcp_seg *seg; u8_t optlen = LWIP_TCP_OPT_LENGTH(optflags); if ((seg = (struct tcp_seg *)memp_malloc(MEMP_TCP_SEG)) == NULL) { LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_create_segment: no memory.\n")); pbuf_free(p); return NULL; } seg->flags = optflags; seg->next = NULL; seg->p = p; LWIP_ASSERT("p->tot_len >= optlen", p->tot_len >= optlen); seg->len = p->tot_len - optlen; #if TCP_OVERSIZE_DBGCHECK seg->oversize_left = 0; #endif /* TCP_OVERSIZE_DBGCHECK */ #if TCP_CHECKSUM_ON_COPY seg->chksum = 0; seg->chksum_swapped = 0; /* check optflags */ LWIP_ASSERT("invalid optflags passed: TF_SEG_DATA_CHECKSUMMED", (optflags & TF_SEG_DATA_CHECKSUMMED) == 0); #endif /* TCP_CHECKSUM_ON_COPY */ /* build TCP header */ if (pbuf_header(p, TCP_HLEN)) { LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_create_segment: no room for TCP header in pbuf.\n")); TCP_STATS_INC(tcp.err); tcp_seg_free(seg); return NULL; } seg->tcphdr = (struct tcp_hdr *)seg->p->payload; seg->tcphdr->src = htons(pcb->local_port); seg->tcphdr->dest = htons(pcb->remote_port); seg->tcphdr->seqno = htonl(seqno); /* ackno is set in tcp_output */ TCPH_HDRLEN_FLAGS_SET(seg->tcphdr, (5 + optlen / 4), flags); /* wnd and chksum are set in tcp_output */ seg->tcphdr->urgp = 0; return seg; } /** * Allocate a PBUF_RAM pbuf, perhaps with extra space at the end. * * This function is like pbuf_alloc(layer, length, PBUF_RAM) except * there may be extra bytes available at the end. * * @param layer flag to define header size. * @param length size of the pbuf's payload. * @param max_length maximum usable size of payload+oversize. * @param oversize pointer to a u16_t that will receive the number of usable tail bytes. * @param pcb The TCP connection that willo enqueue the pbuf. * @param apiflags API flags given to tcp_write. * @param first_seg true when this pbuf will be used in the first enqueued segment. * @param */ #if TCP_OVERSIZE static struct pbuf * tcp_pbuf_prealloc(pbuf_layer layer, u16_t length, u16_t max_length, u16_t *oversize, struct tcp_pcb *pcb, u8_t apiflags, u8_t first_seg) { struct pbuf *p; u16_t alloc = length; #if LWIP_NETIF_TX_SINGLE_PBUF LWIP_UNUSED_ARG(max_length); LWIP_UNUSED_ARG(pcb); LWIP_UNUSED_ARG(apiflags); LWIP_UNUSED_ARG(first_seg); /* always create MSS-sized pbufs */ alloc = max_length; #else /* LWIP_NETIF_TX_SINGLE_PBUF */ if (length < max_length) { /* Should we allocate an oversized pbuf, or just the minimum * length required? If tcp_write is going to be called again * before this segment is transmitted, we want the oversized * buffer. If the segment will be transmitted immediately, we can * save memory by allocating only length. We use a simple * heuristic based on the following information: * * Did the user set TCP_WRITE_FLAG_MORE? * * Will the Nagle algorithm defer transmission of this segment? */ if ((apiflags & TCP_WRITE_FLAG_MORE) || (!(pcb->flags & TF_NODELAY) && (!first_seg || pcb->unsent != NULL || pcb->unacked != NULL))) { alloc = LWIP_MIN(max_length, LWIP_MEM_ALIGN_SIZE(length + TCP_OVERSIZE)); } } #endif /* LWIP_NETIF_TX_SINGLE_PBUF */ p = pbuf_alloc(layer, alloc, PBUF_RAM); if (p == NULL) { return NULL; } LWIP_ASSERT("need unchained pbuf", p->next == NULL); *oversize = p->len - length; /* trim p->len to the currently used size */ p->len = p->tot_len = length; return p; } #else /* TCP_OVERSIZE */ #define tcp_pbuf_prealloc(layer, length, mx, os, pcb, api, fst) pbuf_alloc((layer), (length), PBUF_RAM) #endif /* TCP_OVERSIZE */ #if TCP_CHECKSUM_ON_COPY /** Add a checksum of newly added data to the segment */ static void tcp_seg_add_chksum(u16_t chksum, u16_t len, u16_t *seg_chksum, u8_t *seg_chksum_swapped) { u32_t helper; /* add chksum to old chksum and fold to u16_t */ helper = chksum + *seg_chksum; chksum = FOLD_U32T(helper); if ((len & 1) != 0) { *seg_chksum_swapped = 1 - *seg_chksum_swapped; chksum = SWAP_BYTES_IN_WORD(chksum); } *seg_chksum = chksum; } #endif /* TCP_CHECKSUM_ON_COPY */ /** Checks if tcp_write is allowed or not (checks state, snd_buf and snd_queuelen). * * @param pcb the tcp pcb to check for * @param len length of data to send (checked agains snd_buf) * @return ERR_OK if tcp_write is allowed to proceed, another err_t otherwise */ static err_t tcp_write_checks(struct tcp_pcb *pcb, u16_t len) { /* connection is in invalid state for data transmission? */ if ((pcb->state != ESTABLISHED) && (pcb->state != CLOSE_WAIT) && (pcb->state != SYN_SENT) && (pcb->state != SYN_RCVD)) { LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_STATE | LWIP_DBG_LEVEL_SEVERE, ("tcp_write() called in invalid state\n")); return ERR_CONN; } else if (len == 0) { return ERR_OK; } /* fail on too much data */ if (len > pcb->snd_buf) { LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 3, ("tcp_write: too much data (len=%"U16_F" > snd_buf=%"U16_F")\n", len, pcb->snd_buf)); pcb->flags |= TF_NAGLEMEMERR; return ERR_MEM; } LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_write: queuelen: %"TCPWNDSIZE_F"\n", (tcpwnd_size_t)pcb->snd_queuelen)); /* If total number of pbufs on the unsent/unacked queues exceeds the * configured maximum, return an error */ /* check for configured max queuelen and possible overflow */ if ((pcb->snd_queuelen >= TCP_SND_QUEUELEN) || (pcb->snd_queuelen > TCP_SNDQUEUELEN_OVERFLOW)) { LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 3, ("tcp_write: too long queue %"TCPWNDSIZE_F" (max %"TCPWNDSIZE_F")\n", pcb->snd_queuelen, TCP_SND_QUEUELEN)); TCP_STATS_INC(tcp.memerr); pcb->flags |= TF_NAGLEMEMERR; return ERR_MEM; } if (pcb->snd_queuelen != 0) { LWIP_ASSERT("tcp_write: pbufs on queue => at least one queue non-empty", pcb->unacked != NULL || pcb->unsent != NULL); } else { LWIP_ASSERT("tcp_write: no pbufs on queue => both queues empty", pcb->unacked == NULL && pcb->unsent == NULL); } return ERR_OK; } /** * Write data for sending (but does not send it immediately). * * It waits in the expectation of more data being sent soon (as * it can send them more efficiently by combining them together). * To prompt the system to send data now, call tcp_output() after * calling tcp_write(). * * @param pcb Protocol control block for the TCP connection to enqueue data for. * @param arg Pointer to the data to be enqueued for sending. * @param len Data length in bytes * @param apiflags combination of following flags : * - TCP_WRITE_FLAG_COPY (0x01) data will be copied into memory belonging to the stack * - TCP_WRITE_FLAG_MORE (0x02) for TCP connection, PSH flag will be set on last segment sent, * @return ERR_OK if enqueued, another err_t on error */ err_t tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags) { struct pbuf *concat_p = NULL; struct tcp_seg *last_unsent = NULL, *seg = NULL, *prev_seg = NULL, *queue = NULL; u16_t pos = 0; /* position in 'arg' data */ u16_t queuelen; u8_t optlen = 0; u8_t optflags = 0; #if TCP_OVERSIZE u16_t oversize = 0; u16_t oversize_used = 0; #endif /* TCP_OVERSIZE */ #if TCP_CHECKSUM_ON_COPY u16_t concat_chksum = 0; u8_t concat_chksum_swapped = 0; u16_t concat_chksummed = 0; #endif /* TCP_CHECKSUM_ON_COPY */ err_t err; /* don't allocate segments bigger than half the maximum window we ever received */ u16_t mss_local = LWIP_MIN(pcb->mss, pcb->snd_wnd_max/2); mss_local = mss_local ? mss_local : pcb->mss; #if LWIP_NETIF_TX_SINGLE_PBUF /* Always copy to try to create single pbufs for TX */ apiflags |= TCP_WRITE_FLAG_COPY; #endif /* LWIP_NETIF_TX_SINGLE_PBUF */ LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_write(pcb=%p, data=%p, len=%"U16_F", apiflags=%"U16_F")\n", (void *)pcb, arg, len, (u16_t)apiflags)); LWIP_ERROR("tcp_write: arg == NULL (programmer violates API)", arg != NULL, return ERR_ARG;); err = tcp_write_checks(pcb, len); if (err != ERR_OK) { return err; } queuelen = pcb->snd_queuelen; #if LWIP_TCP_TIMESTAMPS if ((pcb->flags & TF_TIMESTAMP)) { /* Make sure the timestamp option is only included in data segments if we agreed about it with the remote host. */ optflags = TF_SEG_OPTS_TS; optlen = LWIP_TCP_OPT_LENGTH(TF_SEG_OPTS_TS); /* ensure that segments can hold at least one data byte... */ mss_local = LWIP_MAX(mss_local, LWIP_TCP_OPT_LEN_TS + 1); } #endif /* LWIP_TCP_TIMESTAMPS */ /* * TCP segmentation is done in three phases with increasing complexity: * * 1. Copy data directly into an oversized pbuf. * 2. Chain a new pbuf to the end of pcb->unsent. * 3. Create new segments. * * We may run out of memory at any point. In that case we must * return ERR_MEM and not change anything in pcb. Therefore, all * changes are recorded in local variables and committed at the end * of the function. Some pcb fields are maintained in local copies: * * queuelen = pcb->snd_queuelen * oversize = pcb->unsent_oversize * * These variables are set consistently by the phases: * * seg points to the last segment tampered with. * * pos records progress as data is segmented. */ /* Find the tail of the unsent queue. */ if (pcb->unsent != NULL) { u16_t space; u16_t unsent_optlen; /* @todo: this could be sped up by keeping last_unsent in the pcb */ for (last_unsent = pcb->unsent; last_unsent->next != NULL; last_unsent = last_unsent->next); /* Usable space at the end of the last unsent segment */ unsent_optlen = LWIP_TCP_OPT_LENGTH(last_unsent->flags); LWIP_ASSERT("mss_local is too small", mss_local >= last_unsent->len + unsent_optlen); space = mss_local - (last_unsent->len + unsent_optlen); /* * Phase 1: Copy data directly into an oversized pbuf. * * The number of bytes copied is recorded in the oversize_used * variable. The actual copying is done at the bottom of the * function. */ #if TCP_OVERSIZE #if TCP_OVERSIZE_DBGCHECK /* check that pcb->unsent_oversize matches last_unsent->unsent_oversize */ LWIP_ASSERT("unsent_oversize mismatch (pcb vs. last_unsent)", pcb->unsent_oversize == last_unsent->oversize_left); #endif /* TCP_OVERSIZE_DBGCHECK */ oversize = pcb->unsent_oversize; if (oversize > 0) { LWIP_ASSERT("inconsistent oversize vs. space", oversize_used <= space); seg = last_unsent; oversize_used = oversize < len ? oversize : len; pos += oversize_used; oversize -= oversize_used; space -= oversize_used; } /* now we are either finished or oversize is zero */ LWIP_ASSERT("inconsistend oversize vs. len", (oversize == 0) || (pos == len)); #endif /* TCP_OVERSIZE */ /* * Phase 2: Chain a new pbuf to the end of pcb->unsent. * * We don't extend segments containing SYN/FIN flags or options * (len==0). The new pbuf is kept in concat_p and pbuf_cat'ed at * the end. */ if ((pos < len) && (space > 0) && (last_unsent->len > 0)) { u16_t seglen = space < len - pos ? space : len - pos; seg = last_unsent; /* Create a pbuf with a copy or reference to seglen bytes. We * can use PBUF_RAW here since the data appears in the middle of * a segment. A header will never be prepended. */ if (apiflags & TCP_WRITE_FLAG_COPY) { /* Data is copied */ if ((concat_p = tcp_pbuf_prealloc(PBUF_RAW, seglen, space, &oversize, pcb, apiflags, 1)) == NULL) { LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_write : could not allocate memory for pbuf copy size %"U16_F"\n", seglen)); goto memerr; } #if TCP_OVERSIZE_DBGCHECK last_unsent->oversize_left += oversize; #endif /* TCP_OVERSIZE_DBGCHECK */ TCP_DATA_COPY2(concat_p->payload, (u8_t*)arg + pos, seglen, &concat_chksum, &concat_chksum_swapped); #if TCP_CHECKSUM_ON_COPY concat_chksummed += seglen; #endif /* TCP_CHECKSUM_ON_COPY */ } else { /* Data is not copied */ if ((concat_p = pbuf_alloc(PBUF_RAW, seglen, PBUF_ROM)) == NULL) { LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_write: could not allocate memory for zero-copy pbuf\n")); goto memerr; } #if TCP_CHECKSUM_ON_COPY /* calculate the checksum of nocopy-data */ tcp_seg_add_chksum(~inet_chksum((u8_t*)arg + pos, seglen), seglen, &concat_chksum, &concat_chksum_swapped); concat_chksummed += seglen; #endif /* TCP_CHECKSUM_ON_COPY */ /* reference the non-volatile payload data */ concat_p->payload = (u8_t*)arg + pos; } pos += seglen; queuelen += pbuf_clen(concat_p); } } else { #if TCP_OVERSIZE LWIP_ASSERT("unsent_oversize mismatch (pcb->unsent is NULL)", pcb->unsent_oversize == 0); #endif /* TCP_OVERSIZE */ } /* * Phase 3: Create new segments. * * The new segments are chained together in the local 'queue' * variable, ready to be appended to pcb->unsent. */ while (pos < len) { struct pbuf *p; u16_t left = len - pos; u16_t max_len = mss_local - optlen; u16_t seglen = left > max_len ? max_len : left; #if TCP_CHECKSUM_ON_COPY u16_t chksum = 0; u8_t chksum_swapped = 0; #endif /* TCP_CHECKSUM_ON_COPY */ if (apiflags & TCP_WRITE_FLAG_COPY) { /* If copy is set, memory should be allocated and data copied * into pbuf */ if ((p = tcp_pbuf_prealloc(PBUF_TRANSPORT, seglen + optlen, mss_local, &oversize, pcb, apiflags, queue == NULL)) == NULL) { LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_write : could not allocate memory for pbuf copy size %"U16_F"\n", seglen)); goto memerr; } LWIP_ASSERT("tcp_write: check that first pbuf can hold the complete seglen", (p->len >= seglen)); TCP_DATA_COPY2((char *)p->payload + optlen, (u8_t*)arg + pos, seglen, &chksum, &chksum_swapped); } else { /* Copy is not set: First allocate a pbuf for holding the data. * Since the referenced data is available at least until it is * sent out on the link (as it has to be ACKed by the remote * party) we can safely use PBUF_ROM instead of PBUF_REF here. */ struct pbuf *p2; #if TCP_OVERSIZE LWIP_ASSERT("oversize == 0", oversize == 0); #endif /* TCP_OVERSIZE */ if ((p2 = pbuf_alloc(PBUF_TRANSPORT, seglen, PBUF_ROM)) == NULL) { LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_write: could not allocate memory for zero-copy pbuf\n")); goto memerr; } #if TCP_CHECKSUM_ON_COPY /* calculate the checksum of nocopy-data */ chksum = ~inet_chksum((u8_t*)arg + pos, seglen); #endif /* TCP_CHECKSUM_ON_COPY */ /* reference the non-volatile payload data */ p2->payload = (u8_t*)arg + pos; /* Second, allocate a pbuf for the headers. */ if ((p = pbuf_alloc(PBUF_TRANSPORT, optlen, PBUF_RAM)) == NULL) { /* If allocation fails, we have to deallocate the data pbuf as * well. */ pbuf_free(p2); LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_write: could not allocate memory for header pbuf\n")); goto memerr; } /* Concatenate the headers and data pbufs together. */ pbuf_cat(p/*header*/, p2/*data*/); } queuelen += pbuf_clen(p); /* Now that there are more segments queued, we check again if the * length of the queue exceeds the configured maximum or * overflows. */ if ((queuelen > TCP_SND_QUEUELEN) || (queuelen > TCP_SNDQUEUELEN_OVERFLOW)) { LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_write: queue too long %"TCPWNDSIZE_F" (%"TCPWNDSIZE_F")\n", queuelen, TCP_SND_QUEUELEN)); pbuf_free(p); goto memerr; } if ((seg = tcp_create_segment(pcb, p, 0, pcb->snd_lbb + pos, optflags)) == NULL) { goto memerr; } #if TCP_OVERSIZE_DBGCHECK seg->oversize_left = oversize; #endif /* TCP_OVERSIZE_DBGCHECK */ #if TCP_CHECKSUM_ON_COPY seg->chksum = chksum; seg->chksum_swapped = chksum_swapped; seg->flags |= TF_SEG_DATA_CHECKSUMMED; #endif /* TCP_CHECKSUM_ON_COPY */ /* first segment of to-be-queued data? */ if (queue == NULL) { queue = seg; } else { /* Attach the segment to the end of the queued segments */ LWIP_ASSERT("prev_seg != NULL", prev_seg != NULL); prev_seg->next = seg; } /* remember last segment of to-be-queued data for next iteration */ prev_seg = seg; LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_TRACE, ("tcp_write: queueing %"U32_F":%"U32_F"\n", ntohl(seg->tcphdr->seqno), ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg))); pos += seglen; } /* * All three segmentation phases were successful. We can commit the * transaction. */ /* * Phase 1: If data has been added to the preallocated tail of * last_unsent, we update the length fields of the pbuf chain. */ #if TCP_OVERSIZE if (oversize_used > 0) { struct pbuf *p; /* Bump tot_len of whole chain, len of tail */ for (p = last_unsent->p; p; p = p->next) { p->tot_len += oversize_used; if (p->next == NULL) { TCP_DATA_COPY((char *)p->payload + p->len, arg, oversize_used, last_unsent); p->len += oversize_used; } } last_unsent->len += oversize_used; #if TCP_OVERSIZE_DBGCHECK LWIP_ASSERT("last_unsent->oversize_left >= oversize_used", last_unsent->oversize_left >= oversize_used); last_unsent->oversize_left -= oversize_used; #endif /* TCP_OVERSIZE_DBGCHECK */ } pcb->unsent_oversize = oversize; #endif /* TCP_OVERSIZE */ /* * Phase 2: concat_p can be concatenated onto last_unsent->p */ if (concat_p != NULL) { LWIP_ASSERT("tcp_write: cannot concatenate when pcb->unsent is empty", (last_unsent != NULL)); pbuf_cat(last_unsent->p, concat_p); last_unsent->len += concat_p->tot_len; #if TCP_CHECKSUM_ON_COPY if (concat_chksummed) { /*if concat checksumm swapped - swap it back */ if (concat_chksum_swapped){ concat_chksum = SWAP_BYTES_IN_WORD(concat_chksum); } tcp_seg_add_chksum(concat_chksum, concat_chksummed, &last_unsent->chksum, &last_unsent->chksum_swapped); last_unsent->flags |= TF_SEG_DATA_CHECKSUMMED; } #endif /* TCP_CHECKSUM_ON_COPY */ } /* * Phase 3: Append queue to pcb->unsent. Queue may be NULL, but that * is harmless */ if (last_unsent == NULL) { pcb->unsent = queue; } else { last_unsent->next = queue; } /* * Finally update the pcb state. */ pcb->snd_lbb += len; pcb->snd_buf -= len; pcb->snd_queuelen = queuelen; LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_write: %"S16_F" (after enqueued)\n", pcb->snd_queuelen)); if (pcb->snd_queuelen != 0) { LWIP_ASSERT("tcp_write: valid queue length", pcb->unacked != NULL || pcb->unsent != NULL); } /* Set the PSH flag in the last segment that we enqueued. */ if (seg != NULL && seg->tcphdr != NULL && ((apiflags & TCP_WRITE_FLAG_MORE)==0)) { TCPH_SET_FLAG(seg->tcphdr, TCP_PSH); } return ERR_OK; memerr: pcb->flags |= TF_NAGLEMEMERR; TCP_STATS_INC(tcp.memerr); if (concat_p != NULL) { pbuf_free(concat_p); } if (queue != NULL) { tcp_segs_free(queue); } if (pcb->snd_queuelen != 0) { LWIP_ASSERT("tcp_write: valid queue length", pcb->unacked != NULL || pcb->unsent != NULL); } LWIP_DEBUGF(TCP_QLEN_DEBUG | LWIP_DBG_STATE, ("tcp_write: %"S16_F" (with mem err)\n", pcb->snd_queuelen)); return ERR_MEM; } /** * Enqueue TCP options for transmission. * * Called by tcp_connect(), tcp_listen_input(), and tcp_send_ctrl(). * * @param pcb Protocol control block for the TCP connection. * @param flags TCP header flags to set in the outgoing segment. * @param optdata pointer to TCP options, or NULL. * @param optlen length of TCP options in bytes. */ err_t tcp_enqueue_flags(struct tcp_pcb *pcb, u8_t flags) { struct pbuf *p; struct tcp_seg *seg; u8_t optflags = 0; u8_t optlen = 0; LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_enqueue_flags: queuelen: %"U16_F"\n", (u16_t)pcb->snd_queuelen)); LWIP_ASSERT("tcp_enqueue_flags: need either TCP_SYN or TCP_FIN in flags (programmer violates API)", (flags & (TCP_SYN | TCP_FIN)) != 0); /* check for configured max queuelen and possible overflow */ if ((pcb->snd_queuelen >= TCP_SND_QUEUELEN) || (pcb->snd_queuelen > TCP_SNDQUEUELEN_OVERFLOW)) { LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 3, ("tcp_enqueue_flags: too long queue %"U16_F" (max %"U16_F")\n", pcb->snd_queuelen, TCP_SND_QUEUELEN)); TCP_STATS_INC(tcp.memerr); pcb->flags |= TF_NAGLEMEMERR; return ERR_MEM; } if (flags & TCP_SYN) { optflags = TF_SEG_OPTS_MSS; #if LWIP_WND_SCALE if ((pcb->state != SYN_RCVD) || (pcb->flags & TF_WND_SCALE)) { /* In a (sent in state SYN_RCVD), the window scale option may only be sent if we received a window scale option from the remote host. */ optflags |= TF_SEG_OPTS_WND_SCALE; } #endif /* LWIP_WND_SCALE */ } #if LWIP_TCP_TIMESTAMPS if ((pcb->flags & TF_TIMESTAMP)) { /* Make sure the timestamp option is only included in data segments if we agreed about it with the remote host. */ optflags |= TF_SEG_OPTS_TS; } #endif /* LWIP_TCP_TIMESTAMPS */ optlen = LWIP_TCP_OPT_LENGTH(optflags); /* tcp_enqueue_flags is always called with either SYN or FIN in flags. * We need one available snd_buf byte to do that. * This means we can't send FIN while snd_buf==0. A better fix would be to * not include SYN and FIN sequence numbers in the snd_buf count. */ if (pcb->snd_buf == 0) { LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 3, ("tcp_enqueue_flags: no send buffer available\n")); TCP_STATS_INC(tcp.memerr); return ERR_MEM; } /* Allocate pbuf with room for TCP header + options */ if ((p = pbuf_alloc(PBUF_TRANSPORT, optlen, PBUF_RAM)) == NULL) { pcb->flags |= TF_NAGLEMEMERR; TCP_STATS_INC(tcp.memerr); return ERR_MEM; } LWIP_ASSERT("tcp_enqueue_flags: check that first pbuf can hold optlen", (p->len >= optlen)); /* Allocate memory for tcp_seg, and fill in fields. */ if ((seg = tcp_create_segment(pcb, p, flags, pcb->snd_lbb, optflags)) == NULL) { pcb->flags |= TF_NAGLEMEMERR; TCP_STATS_INC(tcp.memerr); return ERR_MEM; } LWIP_ASSERT("seg->tcphdr not aligned", ((mem_ptr_t)seg->tcphdr % 4) == 0); LWIP_ASSERT("tcp_enqueue_flags: invalid segment length", seg->len == 0); LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_TRACE, ("tcp_enqueue_flags: queueing %"U32_F":%"U32_F" (0x%"X16_F")\n", ntohl(seg->tcphdr->seqno), ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg), (u16_t)flags)); /* Now append seg to pcb->unsent queue */ if (pcb->unsent == NULL) { pcb->unsent = seg; } else { struct tcp_seg *useg; for (useg = pcb->unsent; useg->next != NULL; useg = useg->next); useg->next = seg; } #if TCP_OVERSIZE /* The new unsent tail has no space */ pcb->unsent_oversize = 0; #endif /* TCP_OVERSIZE */ /* SYN and FIN bump the sequence number */ if ((flags & TCP_SYN) || (flags & TCP_FIN)) { pcb->snd_lbb++; /* optlen does not influence snd_buf */ pcb->snd_buf--; } if (flags & TCP_FIN) { pcb->flags |= TF_FIN; } /* update number of segments on the queues */ pcb->snd_queuelen += pbuf_clen(seg->p); LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_enqueue_flags: %"S16_F" (after enqueued)\n", pcb->snd_queuelen)); if (pcb->snd_queuelen != 0) { LWIP_ASSERT("tcp_enqueue_flags: invalid queue length", pcb->unacked != NULL || pcb->unsent != NULL); } return ERR_OK; } #if LWIP_TCP_TIMESTAMPS /* Build a timestamp option (12 bytes long) at the specified options pointer) * * @param pcb tcp_pcb * @param opts option pointer where to store the timestamp option */ static void tcp_build_timestamp_option(struct tcp_pcb *pcb, u32_t *opts) { /* Pad with two NOP options to make everything nicely aligned */ opts[0] = PP_HTONL(0x0101080A); opts[1] = htonl(sys_now()); opts[2] = htonl(pcb->ts_recent); } #endif #if LWIP_WND_SCALE /** Build a window scale option (3 bytes long) at the specified options pointer) * * @param opts option pointer where to store the window scale option */ static void tcp_build_wnd_scale_option(u32_t *opts) { /* Pad with one NOP option to make everything nicely aligned */ opts[0] = PP_HTONL(0x01030300 | TCP_RCV_SCALE); } #endif /** Send an ACK without data. * * @param pcb Protocol control block for the TCP connection to send the ACK */ err_t tcp_send_empty_ack(struct tcp_pcb *pcb) { struct pbuf *p; u8_t optlen = 0; #if LWIP_TCP_TIMESTAMPS || CHECKSUM_GEN_TCP struct tcp_hdr *tcphdr; #endif /* LWIP_TCP_TIMESTAMPS || CHECKSUM_GEN_TCP */ #if LWIP_TCP_TIMESTAMPS if (pcb->flags & TF_TIMESTAMP) { optlen = LWIP_TCP_OPT_LENGTH(TF_SEG_OPTS_TS); } #endif p = tcp_output_alloc_header(pcb, optlen, 0, htonl(pcb->snd_nxt)); if (p == NULL) { LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output: (ACK) could not allocate pbuf\n")); return ERR_BUF; } #if LWIP_TCP_TIMESTAMPS || CHECKSUM_GEN_TCP tcphdr = (struct tcp_hdr *)p->payload; #endif /* LWIP_TCP_TIMESTAMPS || CHECKSUM_GEN_TCP */ LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output: sending ACK for %"U32_F"\n", pcb->rcv_nxt)); /* remove ACK flags from the PCB, as we send an empty ACK now */ pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW); /* NB. MSS and window scale options are only sent on SYNs, so ignore them here */ #if LWIP_TCP_TIMESTAMPS pcb->ts_lastacksent = pcb->rcv_nxt; if (pcb->flags & TF_TIMESTAMP) { tcp_build_timestamp_option(pcb, (u32_t *)(tcphdr + 1)); } #endif #if CHECKSUM_GEN_TCP tcphdr->chksum = ipX_chksum_pseudo(PCB_ISIPV6(pcb), p, IP_PROTO_TCP, p->tot_len, &pcb->local_ip, &pcb->remote_ip); #endif #if LWIP_NETIF_HWADDRHINT ipX_output_hinted(PCB_ISIPV6(pcb), p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, pcb->tos, IP_PROTO_TCP, &pcb->addr_hint); #else /* LWIP_NETIF_HWADDRHINT*/ ipX_output(PCB_ISIPV6(pcb), p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, pcb->tos, IP_PROTO_TCP); #endif /* LWIP_NETIF_HWADDRHINT*/ pbuf_free(p); return ERR_OK; } /** * Find out what we can send and send it * * @param pcb Protocol control block for the TCP connection to send data * @return ERR_OK if data has been sent or nothing to send * another err_t on error */ err_t tcp_output(struct tcp_pcb *pcb) { struct tcp_seg *seg, *useg; u32_t wnd, snd_nxt; #if TCP_CWND_DEBUG s16_t i = 0; #endif /* TCP_CWND_DEBUG */ /* pcb->state LISTEN not allowed here */ LWIP_ASSERT("don't call tcp_output for listen-pcbs", pcb->state != LISTEN); /* First, check if we are invoked by the TCP input processing code. If so, we do not output anything. Instead, we rely on the input processing code to call us when input processing is done with. */ if (tcp_input_pcb == pcb) { return ERR_OK; } wnd = LWIP_MIN(pcb->snd_wnd, pcb->cwnd); seg = pcb->unsent; /* If the TF_ACK_NOW flag is set and no data will be sent (either * because the ->unsent queue is empty or because the window does * not allow it), construct an empty ACK segment and send it. * * If data is to be sent, we will just piggyback the ACK (see below). */ if (pcb->flags & TF_ACK_NOW && (seg == NULL || ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len > wnd)) { return tcp_send_empty_ack(pcb); } /* useg should point to last segment on unacked queue */ useg = pcb->unacked; if (useg != NULL) { for (; useg->next != NULL; useg = useg->next); } #if TCP_OUTPUT_DEBUG if (seg == NULL) { LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output: nothing to send (%p)\n", (void*)pcb->unsent)); } #endif /* TCP_OUTPUT_DEBUG */ #if TCP_CWND_DEBUG if (seg == NULL) { LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_output: snd_wnd %"TCPWNDSIZE_F ", cwnd %"TCPWNDSIZE_F", wnd %"U32_F ", seg == NULL, ack %"U32_F"\n", pcb->snd_wnd, pcb->cwnd, wnd, pcb->lastack)); } else { LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_output: snd_wnd %"TCPWNDSIZE_F", cwnd %"TCPWNDSIZE_F", wnd %"U32_F ", effwnd %"U32_F", seq %"U32_F", ack %"U32_F"\n", pcb->snd_wnd, pcb->cwnd, wnd, ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len, ntohl(seg->tcphdr->seqno), pcb->lastack)); } #endif /* TCP_CWND_DEBUG */ /* data available and window allows it to be sent? */ while (seg != NULL && ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len <= wnd) { LWIP_ASSERT("RST not expected here!", (TCPH_FLAGS(seg->tcphdr) & TCP_RST) == 0); /* Stop sending if the nagle algorithm would prevent it * Don't stop: * - if tcp_write had a memory error before (prevent delayed ACK timeout) or * - if FIN was already enqueued for this PCB (SYN is always alone in a segment - * either seg->next != NULL or pcb->unacked == NULL; * RST is no sent using tcp_write/tcp_output. */ if((tcp_do_output_nagle(pcb) == 0) && ((pcb->flags & (TF_NAGLEMEMERR | TF_FIN)) == 0)){ break; } #if TCP_CWND_DEBUG LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_output: snd_wnd %"TCPWNDSIZE_F", cwnd %"TCPWNDSIZE_F", wnd %"U32_F", effwnd %"U32_F", seq %"U32_F", ack %"U32_F", i %"S16_F"\n", pcb->snd_wnd, pcb->cwnd, wnd, ntohl(seg->tcphdr->seqno) + seg->len - pcb->lastack, ntohl(seg->tcphdr->seqno), pcb->lastack, i)); ++i; #endif /* TCP_CWND_DEBUG */ pcb->unsent = seg->next; if (pcb->state != SYN_SENT) { TCPH_SET_FLAG(seg->tcphdr, TCP_ACK); pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW); } #if TCP_OVERSIZE_DBGCHECK seg->oversize_left = 0; #endif /* TCP_OVERSIZE_DBGCHECK */ tcp_output_segment(seg, pcb); snd_nxt = ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg); if (TCP_SEQ_LT(pcb->snd_nxt, snd_nxt)) { pcb->snd_nxt = snd_nxt; } /* put segment on unacknowledged list if length > 0 */ if (TCP_TCPLEN(seg) > 0) { seg->next = NULL; /* unacked list is empty? */ if (pcb->unacked == NULL) { pcb->unacked = seg; useg = seg; /* unacked list is not empty? */ } else { /* In the case of fast retransmit, the packet should not go to the tail * of the unacked queue, but rather somewhere before it. We need to check for * this case. -STJ Jul 27, 2004 */ if (TCP_SEQ_LT(ntohl(seg->tcphdr->seqno), ntohl(useg->tcphdr->seqno))) { /* add segment to before tail of unacked list, keeping the list sorted */ struct tcp_seg **cur_seg = &(pcb->unacked); while (*cur_seg && TCP_SEQ_LT(ntohl((*cur_seg)->tcphdr->seqno), ntohl(seg->tcphdr->seqno))) { cur_seg = &((*cur_seg)->next ); } seg->next = (*cur_seg); (*cur_seg) = seg; } else { /* add segment to tail of unacked list */ useg->next = seg; useg = useg->next; } } /* do not queue empty segments on the unacked list */ } else { tcp_seg_free(seg); } seg = pcb->unsent; } #if TCP_OVERSIZE if (pcb->unsent == NULL) { /* last unsent has been removed, reset unsent_oversize */ pcb->unsent_oversize = 0; } #endif /* TCP_OVERSIZE */ pcb->flags &= ~TF_NAGLEMEMERR; return ERR_OK; } /** * Called by tcp_output() to actually send a TCP segment over IP. * * @param seg the tcp_seg to send * @param pcb the tcp_pcb for the TCP connection used to send the segment */ static void tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb) { u16_t len; u32_t *opts; /** @bug Exclude retransmitted segments from this count. */ snmp_inc_tcpoutsegs(); /* The TCP header has already been constructed, but the ackno and wnd fields remain. */ seg->tcphdr->ackno = htonl(pcb->rcv_nxt); /* advertise our receive window size in this TCP segment */ #if LWIP_WND_SCALE if (seg->flags & TF_SEG_OPTS_WND_SCALE) { /* The Window field in a SYN segment itself (the only type where we send the window scale option) is never scaled. */ seg->tcphdr->wnd = htons(pcb->rcv_ann_wnd); } else #endif /* LWIP_WND_SCALE */ { seg->tcphdr->wnd = htons(RCV_WND_SCALE(pcb, pcb->rcv_ann_wnd)); } pcb->rcv_ann_right_edge = pcb->rcv_nxt + pcb->rcv_ann_wnd; /* Add any requested options. NB MSS option is only set on SYN packets, so ignore it here */ opts = (u32_t *)(void *)(seg->tcphdr + 1); if (seg->flags & TF_SEG_OPTS_MSS) { u16_t mss; #if TCP_CALCULATE_EFF_SEND_MSS mss = tcp_eff_send_mss(TCP_MSS, &pcb->local_ip, &pcb->remote_ip, PCB_ISIPV6(pcb)); #else /* TCP_CALCULATE_EFF_SEND_MSS */ mss = TCP_MSS; #endif /* TCP_CALCULATE_EFF_SEND_MSS */ *opts = TCP_BUILD_MSS_OPTION(mss); opts += 1; } #if LWIP_TCP_TIMESTAMPS pcb->ts_lastacksent = pcb->rcv_nxt; if (seg->flags & TF_SEG_OPTS_TS) { tcp_build_timestamp_option(pcb, opts); opts += 3; } #endif #if LWIP_WND_SCALE if (seg->flags & TF_SEG_OPTS_WND_SCALE) { tcp_build_wnd_scale_option(opts); opts += 1; } #endif /* Set retransmission timer running if it is not currently enabled This must be set before checking the route. */ if (pcb->rtime == -1) { pcb->rtime = 0; } /* If we don't have a local IP address, we get one by calling ip_route(). */ if (ipX_addr_isany(PCB_ISIPV6(pcb), &pcb->local_ip)) { struct netif *netif; ipX_addr_t *local_ip; ipX_route_get_local_ipX(PCB_ISIPV6(pcb), &pcb->local_ip, &pcb->remote_ip, netif, local_ip); if ((netif == NULL) || (local_ip == NULL)) { return; } ipX_addr_copy(PCB_ISIPV6(pcb), pcb->local_ip, *local_ip); } if (pcb->rttest == 0) { pcb->rttest = tcp_ticks; pcb->rtseq = ntohl(seg->tcphdr->seqno); LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_output_segment: rtseq %"U32_F"\n", pcb->rtseq)); } LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output_segment: %"U32_F":%"U32_F"\n", htonl(seg->tcphdr->seqno), htonl(seg->tcphdr->seqno) + seg->len)); len = (u16_t)((u8_t *)seg->tcphdr - (u8_t *)seg->p->payload); seg->p->len -= len; seg->p->tot_len -= len; seg->p->payload = seg->tcphdr; seg->tcphdr->chksum = 0; #if TCP_CHECKSUM_ON_COPY { u32_t acc; #if TCP_CHECKSUM_ON_COPY_SANITY_CHECK u16_t chksum_slow = ipX_chksum_pseudo(PCB_ISIPV6(pcb), seg->p, IP_PROTO_TCP, seg->p->tot_len, &pcb->local_ip, &pcb->remote_ip); #endif /* TCP_CHECKSUM_ON_COPY_SANITY_CHECK */ if ((seg->flags & TF_SEG_DATA_CHECKSUMMED) == 0) { LWIP_ASSERT("data included but not checksummed", seg->p->tot_len == (TCPH_HDRLEN(seg->tcphdr) * 4)); } /* rebuild TCP header checksum (TCP header changes for retransmissions!) */ acc = ipX_chksum_pseudo_partial(PCB_ISIPV6(pcb), seg->p, IP_PROTO_TCP, seg->p->tot_len, TCPH_HDRLEN(seg->tcphdr) * 4, &pcb->local_ip, &pcb->remote_ip); /* add payload checksum */ if (seg->chksum_swapped) { seg->chksum = SWAP_BYTES_IN_WORD(seg->chksum); seg->chksum_swapped = 0; } acc += (u16_t)~(seg->chksum); seg->tcphdr->chksum = FOLD_U32T(acc); #if TCP_CHECKSUM_ON_COPY_SANITY_CHECK if (chksum_slow != seg->tcphdr->chksum) { LWIP_DEBUGF(TCP_DEBUG | LWIP_DBG_LEVEL_WARNING, ("tcp_output_segment: calculated checksum is %"X16_F" instead of %"X16_F"\n", seg->tcphdr->chksum, chksum_slow)); seg->tcphdr->chksum = chksum_slow; } #endif /* TCP_CHECKSUM_ON_COPY_SANITY_CHECK */ } #else /* TCP_CHECKSUM_ON_COPY */ #if CHECKSUM_GEN_TCP seg->tcphdr->chksum = ipX_chksum_pseudo(PCB_ISIPV6(pcb), seg->p, IP_PROTO_TCP, seg->p->tot_len, &pcb->local_ip, &pcb->remote_ip); #endif /* CHECKSUM_GEN_TCP */ #endif /* TCP_CHECKSUM_ON_COPY */ TCP_STATS_INC(tcp.xmit); #if LWIP_NETIF_HWADDRHINT ipX_output_hinted(PCB_ISIPV6(pcb), seg->p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, pcb->tos, IP_PROTO_TCP, &pcb->addr_hint); #else /* LWIP_NETIF_HWADDRHINT*/ ipX_output(PCB_ISIPV6(pcb), seg->p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, pcb->tos, IP_PROTO_TCP); #endif /* LWIP_NETIF_HWADDRHINT*/ } /** * Send a TCP RESET packet (empty segment with RST flag set) either to * abort a connection or to show that there is no matching local connection * for a received segment. * * Called by tcp_abort() (to abort a local connection), tcp_input() (if no * matching local pcb was found), tcp_listen_input() (if incoming segment * has ACK flag set) and tcp_process() (received segment in the wrong state) * * Since a RST segment is in most cases not sent for an active connection, * tcp_rst() has a number of arguments that are taken from a tcp_pcb for * most other segment output functions. * * @param seqno the sequence number to use for the outgoing segment * @param ackno the acknowledge number to use for the outgoing segment * @param local_ip the local IP address to send the segment from * @param remote_ip the remote IP address to send the segment to * @param local_port the local TCP port to send the segment from * @param remote_port the remote TCP port to send the segment to */ void tcp_rst_impl(u32_t seqno, u32_t ackno, ipX_addr_t *local_ip, ipX_addr_t *remote_ip, u16_t local_port, u16_t remote_port #if LWIP_IPV6 , u8_t isipv6 #endif /* LWIP_IPV6 */ ) { struct pbuf *p; struct tcp_hdr *tcphdr; p = pbuf_alloc(PBUF_IP, TCP_HLEN, PBUF_RAM); if (p == NULL) { LWIP_DEBUGF(TCP_DEBUG, ("tcp_rst: could not allocate memory for pbuf\n")); return; } LWIP_ASSERT("check that first pbuf can hold struct tcp_hdr", (p->len >= sizeof(struct tcp_hdr))); tcphdr = (struct tcp_hdr *)p->payload; tcphdr->src = htons(local_port); tcphdr->dest = htons(remote_port); tcphdr->seqno = htonl(seqno); tcphdr->ackno = htonl(ackno); TCPH_HDRLEN_FLAGS_SET(tcphdr, TCP_HLEN/4, TCP_RST | TCP_ACK); #if LWIP_WND_SCALE tcphdr->wnd = PP_HTONS(((TCP_WND >> TCP_RCV_SCALE) & 0xFFFF)); #else tcphdr->wnd = PP_HTONS(TCP_WND); #endif tcphdr->chksum = 0; tcphdr->urgp = 0; TCP_STATS_INC(tcp.xmit); snmp_inc_tcpoutrsts(); #if CHECKSUM_GEN_TCP tcphdr->chksum = ipX_chksum_pseudo(isipv6, p, IP_PROTO_TCP, p->tot_len, local_ip, remote_ip); #endif /* Send output with hardcoded TTL/HL since we have no access to the pcb */ ipX_output(isipv6, p, local_ip, remote_ip, TCP_TTL, 0, IP_PROTO_TCP); pbuf_free(p); LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_rst: seqno %"U32_F" ackno %"U32_F".\n", seqno, ackno)); } /** * Requeue all unacked segments for retransmission * * Called by tcp_slowtmr() for slow retransmission. * * @param pcb the tcp_pcb for which to re-enqueue all unacked segments */ void tcp_rexmit_rto(struct tcp_pcb *pcb) { struct tcp_seg *seg; if (pcb->unacked == NULL) { return; } /* Move all unacked segments to the head of the unsent queue */ for (seg = pcb->unacked; seg->next != NULL; seg = seg->next); /* concatenate unsent queue after unacked queue */ seg->next = pcb->unsent; #if TCP_OVERSIZE && TCP_OVERSIZE_DBGCHECK /* if last unsent changed, we need to update unsent_oversize */ if (pcb->unsent == NULL) { pcb->unsent_oversize = seg->oversize_left; } #endif /* TCP_OVERSIZE && TCP_OVERSIZE_DBGCHECK*/ /* unsent queue is the concatenated queue (of unacked, unsent) */ pcb->unsent = pcb->unacked; /* unacked queue is now empty */ pcb->unacked = NULL; /* increment number of retransmissions */ ++pcb->nrtx; /* Don't take any RTT measurements after retransmitting. */ pcb->rttest = 0; /* Do the actual retransmission */ tcp_output(pcb); } /** * Requeue the first unacked segment for retransmission * * Called by tcp_receive() for fast retramsmit. * * @param pcb the tcp_pcb for which to retransmit the first unacked segment */ void tcp_rexmit(struct tcp_pcb *pcb) { struct tcp_seg *seg; struct tcp_seg **cur_seg; if (pcb->unacked == NULL) { return; } /* Move the first unacked segment to the unsent queue */ /* Keep the unsent queue sorted. */ seg = pcb->unacked; pcb->unacked = seg->next; cur_seg = &(pcb->unsent); while (*cur_seg && TCP_SEQ_LT(ntohl((*cur_seg)->tcphdr->seqno), ntohl(seg->tcphdr->seqno))) { cur_seg = &((*cur_seg)->next ); } seg->next = *cur_seg; *cur_seg = seg; #if TCP_OVERSIZE if (seg->next == NULL) { /* the retransmitted segment is last in unsent, so reset unsent_oversize */ pcb->unsent_oversize = 0; } #endif /* TCP_OVERSIZE */ ++pcb->nrtx; /* Don't take any rtt measurements after retransmitting. */ pcb->rttest = 0; /* Do the actual retransmission. */ snmp_inc_tcpretranssegs(); /* No need to call tcp_output: we are always called from tcp_input() and thus tcp_output directly returns. */ } /** * Handle retransmission after three dupacks received * * @param pcb the tcp_pcb for which to retransmit the first unacked segment */ void tcp_rexmit_fast(struct tcp_pcb *pcb) { if (pcb->unacked != NULL && !(pcb->flags & TF_INFR)) { /* This is fast retransmit. Retransmit the first unacked segment. */ LWIP_DEBUGF(TCP_FR_DEBUG, ("tcp_receive: dupacks %"U16_F" (%"U32_F "), fast retransmit %"U32_F"\n", (u16_t)pcb->dupacks, pcb->lastack, ntohl(pcb->unacked->tcphdr->seqno))); tcp_rexmit(pcb); /* Set ssthresh to half of the minimum of the current * cwnd and the advertised window */ if (pcb->cwnd > pcb->snd_wnd) { pcb->ssthresh = pcb->snd_wnd / 2; } else { pcb->ssthresh = pcb->cwnd / 2; } /* The minimum value for ssthresh should be 2 MSS */ if (pcb->ssthresh < (2U * pcb->mss)) { LWIP_DEBUGF(TCP_FR_DEBUG, ("tcp_receive: The minimum value for ssthresh %"U16_F " should be min 2 mss %"U16_F"...\n", pcb->ssthresh, 2*pcb->mss)); pcb->ssthresh = 2*pcb->mss; } pcb->cwnd = pcb->ssthresh + 3 * pcb->mss; pcb->flags |= TF_INFR; } } /** * Send keepalive packets to keep a connection active although * no data is sent over it. * * Called by tcp_slowtmr() * * @param pcb the tcp_pcb for which to send a keepalive packet */ void tcp_keepalive(struct tcp_pcb *pcb) { struct pbuf *p; #if CHECKSUM_GEN_TCP struct tcp_hdr *tcphdr; #endif /* CHECKSUM_GEN_TCP */ LWIP_DEBUGF(TCP_DEBUG, ("tcp_keepalive: sending KEEPALIVE probe to ")); ipX_addr_debug_print(PCB_ISIPV6(pcb), TCP_DEBUG, &pcb->remote_ip); LWIP_DEBUGF(TCP_DEBUG, ("\n")); LWIP_DEBUGF(TCP_DEBUG, ("tcp_keepalive: tcp_ticks %"U32_F" pcb->tmr %"U32_F" pcb->keep_cnt_sent %"U16_F"\n", tcp_ticks, pcb->tmr, pcb->keep_cnt_sent)); p = tcp_output_alloc_header(pcb, 0, 0, htonl(pcb->snd_nxt - 1)); if(p == NULL) { LWIP_DEBUGF(TCP_DEBUG, ("tcp_keepalive: could not allocate memory for pbuf\n")); return; } #if CHECKSUM_GEN_TCP tcphdr = (struct tcp_hdr *)p->payload; tcphdr->chksum = ipX_chksum_pseudo(PCB_ISIPV6(pcb), p, IP_PROTO_TCP, p->tot_len, &pcb->local_ip, &pcb->remote_ip); #endif /* CHECKSUM_GEN_TCP */ TCP_STATS_INC(tcp.xmit); /* Send output to IP */ #if LWIP_NETIF_HWADDRHINT ipX_output_hinted(PCB_ISIPV6(pcb), p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP, &pcb->addr_hint); #else /* LWIP_NETIF_HWADDRHINT*/ ipX_output(PCB_ISIPV6(pcb), p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP); #endif /* LWIP_NETIF_HWADDRHINT*/ pbuf_free(p); LWIP_DEBUGF(TCP_DEBUG, ("tcp_keepalive: seqno %"U32_F" ackno %"U32_F".\n", pcb->snd_nxt - 1, pcb->rcv_nxt)); } /** * Send persist timer zero-window probes to keep a connection active * when a window update is lost. * * Called by tcp_slowtmr() * * @param pcb the tcp_pcb for which to send a zero-window probe packet */ void tcp_zero_window_probe(struct tcp_pcb *pcb) { struct pbuf *p; struct tcp_hdr *tcphdr; struct tcp_seg *seg; u16_t len; u8_t is_fin; LWIP_DEBUGF(TCP_DEBUG, ("tcp_zero_window_probe: sending ZERO WINDOW probe to ")); ipX_addr_debug_print(PCB_ISIPV6(pcb), TCP_DEBUG, &pcb->remote_ip); LWIP_DEBUGF(TCP_DEBUG, ("\n")); LWIP_DEBUGF(TCP_DEBUG, ("tcp_zero_window_probe: tcp_ticks %"U32_F " pcb->tmr %"U32_F" pcb->keep_cnt_sent %"U16_F"\n", tcp_ticks, pcb->tmr, pcb->keep_cnt_sent)); seg = pcb->unacked; if(seg == NULL) { seg = pcb->unsent; } if(seg == NULL) { return; } is_fin = ((TCPH_FLAGS(seg->tcphdr) & TCP_FIN) != 0) && (seg->len == 0); /* we want to send one seqno: either FIN or data (no options) */ len = is_fin ? 0 : 1; p = tcp_output_alloc_header(pcb, 0, len, seg->tcphdr->seqno); if(p == NULL) { LWIP_DEBUGF(TCP_DEBUG, ("tcp_zero_window_probe: no memory for pbuf\n")); return; } tcphdr = (struct tcp_hdr *)p->payload; if (is_fin) { /* FIN segment, no data */ TCPH_FLAGS_SET(tcphdr, TCP_ACK | TCP_FIN); } else { /* Data segment, copy in one byte from the head of the unacked queue */ char *d = ((char *)p->payload + TCP_HLEN); /* Depending on whether the segment has already been sent (unacked) or not (unsent), seg->p->payload points to the IP header or TCP header. Ensure we copy the first TCP data byte: */ pbuf_copy_partial(seg->p, d, 1, seg->p->tot_len - seg->len); } #if CHECKSUM_GEN_TCP tcphdr->chksum = ipX_chksum_pseudo(PCB_ISIPV6(pcb), p, IP_PROTO_TCP, p->tot_len, &pcb->local_ip, &pcb->remote_ip); #endif TCP_STATS_INC(tcp.xmit); /* Send output to IP */ #if LWIP_NETIF_HWADDRHINT ipX_output_hinted(PCB_ISIPV6(pcb), p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP, &pcb->addr_hint); #else /* LWIP_NETIF_HWADDRHINT*/ ipX_output(PCB_ISIPV6(pcb), p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP); #endif /* LWIP_NETIF_HWADDRHINT*/ pbuf_free(p); LWIP_DEBUGF(TCP_DEBUG, ("tcp_zero_window_probe: seqno %"U32_F " ackno %"U32_F".\n", pcb->snd_nxt - 1, pcb->rcv_nxt)); } #endif /* LWIP_TCP */ ocproxy-1.60/lwip/src/core/timers.c000066400000000000000000000347701303453231400173150ustar00rootroot00000000000000/** * @file * Stack-internal timers implementation. * This file includes timer callbacks for stack-internal timers as well as * functions to set up or stop timers and check for expired timers. * */ /* * Copyright (c) 2001-2004 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * Simon Goldschmidt * */ #include "lwip/opt.h" #include "lwip/timers.h" #include "lwip/tcp_impl.h" #if LWIP_TIMERS #include "lwip/def.h" #include "lwip/memp.h" #include "lwip/tcpip.h" #include "lwip/ip_frag.h" #include "netif/etharp.h" #include "lwip/dhcp.h" #include "lwip/autoip.h" #include "lwip/igmp.h" #include "lwip/dns.h" #include "lwip/nd6.h" #include "lwip/ip6_frag.h" #include "lwip/mld6.h" #include "lwip/sys.h" #include "lwip/pbuf.h" /** The one and only timeout list */ static struct sys_timeo *next_timeout; #if NO_SYS static u32_t timeouts_last_time; #endif /* NO_SYS */ #if LWIP_TCP /** global variable that shows if the tcp timer is currently scheduled or not */ static int tcpip_tcp_timer_active; /** * Timer callback function that calls tcp_tmr() and reschedules itself. * * @param arg unused argument */ static void tcpip_tcp_timer(void *arg) { LWIP_UNUSED_ARG(arg); /* call TCP timer handler */ tcp_tmr(); /* timer still needed? */ if (tcp_active_pcbs || tcp_tw_pcbs) { /* restart timer */ sys_timeout(TCP_TMR_INTERVAL, tcpip_tcp_timer, NULL); } else { /* disable timer */ tcpip_tcp_timer_active = 0; } } /** * Called from TCP_REG when registering a new PCB: * the reason is to have the TCP timer only running when * there are active (or time-wait) PCBs. */ void tcp_timer_needed(void) { /* timer is off but needed again? */ if (!tcpip_tcp_timer_active && (tcp_active_pcbs || tcp_tw_pcbs)) { /* enable and start timer */ tcpip_tcp_timer_active = 1; sys_timeout(TCP_TMR_INTERVAL, tcpip_tcp_timer, NULL); } } #endif /* LWIP_TCP */ #if IP_REASSEMBLY /** * Timer callback function that calls ip_reass_tmr() and reschedules itself. * * @param arg unused argument */ static void ip_reass_timer(void *arg) { LWIP_UNUSED_ARG(arg); LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: ip_reass_tmr()\n")); ip_reass_tmr(); sys_timeout(IP_TMR_INTERVAL, ip_reass_timer, NULL); } #endif /* IP_REASSEMBLY */ #if LWIP_ARP /** * Timer callback function that calls etharp_tmr() and reschedules itself. * * @param arg unused argument */ static void arp_timer(void *arg) { LWIP_UNUSED_ARG(arg); LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: etharp_tmr()\n")); etharp_tmr(); sys_timeout(ARP_TMR_INTERVAL, arp_timer, NULL); } #endif /* LWIP_ARP */ #if LWIP_DHCP /** * Timer callback function that calls dhcp_coarse_tmr() and reschedules itself. * * @param arg unused argument */ static void dhcp_timer_coarse(void *arg) { LWIP_UNUSED_ARG(arg); LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: dhcp_coarse_tmr()\n")); dhcp_coarse_tmr(); sys_timeout(DHCP_COARSE_TIMER_MSECS, dhcp_timer_coarse, NULL); } /** * Timer callback function that calls dhcp_fine_tmr() and reschedules itself. * * @param arg unused argument */ static void dhcp_timer_fine(void *arg) { LWIP_UNUSED_ARG(arg); LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: dhcp_fine_tmr()\n")); dhcp_fine_tmr(); sys_timeout(DHCP_FINE_TIMER_MSECS, dhcp_timer_fine, NULL); } #endif /* LWIP_DHCP */ #if LWIP_AUTOIP /** * Timer callback function that calls autoip_tmr() and reschedules itself. * * @param arg unused argument */ static void autoip_timer(void *arg) { LWIP_UNUSED_ARG(arg); LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: autoip_tmr()\n")); autoip_tmr(); sys_timeout(AUTOIP_TMR_INTERVAL, autoip_timer, NULL); } #endif /* LWIP_AUTOIP */ #if LWIP_IGMP /** * Timer callback function that calls igmp_tmr() and reschedules itself. * * @param arg unused argument */ static void igmp_timer(void *arg) { LWIP_UNUSED_ARG(arg); LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: igmp_tmr()\n")); igmp_tmr(); sys_timeout(IGMP_TMR_INTERVAL, igmp_timer, NULL); } #endif /* LWIP_IGMP */ #if LWIP_DNS /** * Timer callback function that calls dns_tmr() and reschedules itself. * * @param arg unused argument */ static void dns_timer(void *arg) { LWIP_UNUSED_ARG(arg); LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: dns_tmr()\n")); dns_tmr(); sys_timeout(DNS_TMR_INTERVAL, dns_timer, NULL); } #endif /* LWIP_DNS */ #if LWIP_IPV6 /** * Timer callback function that calls nd6_tmr() and reschedules itself. * * @param arg unused argument */ static void nd6_timer(void *arg) { LWIP_UNUSED_ARG(arg); LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: nd6_tmr()\n")); nd6_tmr(); sys_timeout(ND6_TMR_INTERVAL, nd6_timer, NULL); } #if LWIP_IPV6_REASS /** * Timer callback function that calls ip6_reass_tmr() and reschedules itself. * * @param arg unused argument */ static void ip6_reass_timer(void *arg) { LWIP_UNUSED_ARG(arg); LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: ip6_reass_tmr()\n")); ip6_reass_tmr(); sys_timeout(IP6_REASS_TMR_INTERVAL, ip6_reass_timer, NULL); } #endif /* LWIP_IPV6_REASS */ #if LWIP_IPV6_MLD /** * Timer callback function that calls mld6_tmr() and reschedules itself. * * @param arg unused argument */ static void mld6_timer(void *arg) { LWIP_UNUSED_ARG(arg); LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: mld6_tmr()\n")); mld6_tmr(); sys_timeout(MLD6_TMR_INTERVAL, mld6_timer, NULL); } #endif /* LWIP_IPV6_MLD */ #endif /* LWIP_IPV6 */ /** Initialize this module */ void sys_timeouts_init(void) { #if IP_REASSEMBLY sys_timeout(IP_TMR_INTERVAL, ip_reass_timer, NULL); #endif /* IP_REASSEMBLY */ #if LWIP_ARP sys_timeout(ARP_TMR_INTERVAL, arp_timer, NULL); #endif /* LWIP_ARP */ #if LWIP_DHCP sys_timeout(DHCP_COARSE_TIMER_MSECS, dhcp_timer_coarse, NULL); sys_timeout(DHCP_FINE_TIMER_MSECS, dhcp_timer_fine, NULL); #endif /* LWIP_DHCP */ #if LWIP_AUTOIP sys_timeout(AUTOIP_TMR_INTERVAL, autoip_timer, NULL); #endif /* LWIP_AUTOIP */ #if LWIP_IGMP sys_timeout(IGMP_TMR_INTERVAL, igmp_timer, NULL); #endif /* LWIP_IGMP */ #if LWIP_DNS sys_timeout(DNS_TMR_INTERVAL, dns_timer, NULL); #endif /* LWIP_DNS */ #if LWIP_IPV6 sys_timeout(ND6_TMR_INTERVAL, nd6_timer, NULL); #if LWIP_IPV6_REASS sys_timeout(IP6_REASS_TMR_INTERVAL, ip6_reass_timer, NULL); #endif /* LWIP_IPV6_REASS */ #if LWIP_IPV6_MLD sys_timeout(MLD6_TMR_INTERVAL, mld6_timer, NULL); #endif /* LWIP_IPV6_MLD */ #endif /* LWIP_IPV6 */ #if NO_SYS /* Initialise timestamp for sys_check_timeouts */ timeouts_last_time = sys_now(); #endif } /** * Create a one-shot timer (aka timeout). Timeouts are processed in the * following cases: * - while waiting for a message using sys_timeouts_mbox_fetch() * - by calling sys_check_timeouts() (NO_SYS==1 only) * * @param msecs time in milliseconds after that the timer should expire * @param handler callback function to call when msecs have elapsed * @param arg argument to pass to the callback function */ #if LWIP_DEBUG_TIMERNAMES void sys_timeout_debug(u32_t msecs, sys_timeout_handler handler, void *arg, const char* handler_name) #else /* LWIP_DEBUG_TIMERNAMES */ void sys_timeout(u32_t msecs, sys_timeout_handler handler, void *arg) #endif /* LWIP_DEBUG_TIMERNAMES */ { struct sys_timeo *timeout, *t; #if NO_SYS u32_t now, diff; #endif timeout = (struct sys_timeo *)memp_malloc(MEMP_SYS_TIMEOUT); if (timeout == NULL) { LWIP_ASSERT("sys_timeout: timeout != NULL, pool MEMP_SYS_TIMEOUT is empty", timeout != NULL); return; } #if NO_SYS now = sys_now(); if (next_timeout == NULL) { diff = 0; timeouts_last_time = now; } else { diff = now - timeouts_last_time; } #endif timeout->next = NULL; timeout->h = handler; timeout->arg = arg; #if NO_SYS timeout->time = msecs + diff; #else timeout->time = msecs; #endif #if LWIP_DEBUG_TIMERNAMES timeout->handler_name = handler_name; LWIP_DEBUGF(TIMERS_DEBUG, ("sys_timeout: %p msecs=%"U32_F" handler=%s arg=%p\n", (void *)timeout, msecs, handler_name, (void *)arg)); #endif /* LWIP_DEBUG_TIMERNAMES */ if (next_timeout == NULL) { next_timeout = timeout; return; } if (next_timeout->time > msecs) { next_timeout->time -= msecs; timeout->next = next_timeout; next_timeout = timeout; } else { for(t = next_timeout; t != NULL; t = t->next) { timeout->time -= t->time; if (t->next == NULL || t->next->time > timeout->time) { if (t->next != NULL) { t->next->time -= timeout->time; } timeout->next = t->next; t->next = timeout; break; } } } } /** * Go through timeout list (for this task only) and remove the first matching * entry (subsequent entries remain untouched), even though the timeout has not * triggered yet. * * @param handler callback function that would be called by the timeout * @param arg callback argument that would be passed to handler */ void sys_untimeout(sys_timeout_handler handler, void *arg) { struct sys_timeo *prev_t, *t; if (next_timeout == NULL) { return; } for (t = next_timeout, prev_t = NULL; t != NULL; prev_t = t, t = t->next) { if ((t->h == handler) && (t->arg == arg)) { /* We have a match */ /* Unlink from previous in list */ if (prev_t == NULL) { next_timeout = t->next; } else { prev_t->next = t->next; } /* If not the last one, add time of this one back to next */ if (t->next != NULL) { t->next->time += t->time; } memp_free(MEMP_SYS_TIMEOUT, t); return; } } return; } #if NO_SYS /** Handle timeouts for NO_SYS==1 (i.e. without using * tcpip_thread/sys_timeouts_mbox_fetch(). Uses sys_now() to call timeout * handler functions when timeouts expire. * * Must be called periodically from your main loop. */ void sys_check_timeouts(void) { if (next_timeout) { struct sys_timeo *tmptimeout; u32_t diff; sys_timeout_handler handler; void *arg; u8_t had_one; u32_t now; now = sys_now(); /* this cares for wraparounds */ diff = now - timeouts_last_time; do { #if PBUF_POOL_FREE_OOSEQ PBUF_CHECK_FREE_OOSEQ(); #endif /* PBUF_POOL_FREE_OOSEQ */ had_one = 0; tmptimeout = next_timeout; if (tmptimeout && (tmptimeout->time <= diff)) { /* timeout has expired */ had_one = 1; timeouts_last_time += tmptimeout->time; diff -= tmptimeout->time; next_timeout = tmptimeout->next; handler = tmptimeout->h; arg = tmptimeout->arg; #if LWIP_DEBUG_TIMERNAMES if (handler != NULL) { LWIP_DEBUGF(TIMERS_DEBUG, ("sct calling h=%s arg=%p\n", tmptimeout->handler_name, arg)); } #endif /* LWIP_DEBUG_TIMERNAMES */ memp_free(MEMP_SYS_TIMEOUT, tmptimeout); if (handler != NULL) { handler(arg); } } /* repeat until all expired timers have been called */ }while(had_one); } } /** Set back the timestamp of the last call to sys_check_timeouts() * This is necessary if sys_check_timeouts() hasn't been called for a long * time (e.g. while saving energy) to prevent all timer functions of that * period being called. */ void sys_restart_timeouts(void) { timeouts_last_time = sys_now(); } #else /* NO_SYS */ /** * Wait (forever) for a message to arrive in an mbox. * While waiting, timeouts are processed. * * @param mbox the mbox to fetch the message from * @param msg the place to store the message */ void sys_timeouts_mbox_fetch(sys_mbox_t *mbox, void **msg) { u32_t time_needed; struct sys_timeo *tmptimeout; sys_timeout_handler handler; void *arg; again: if (!next_timeout) { time_needed = sys_arch_mbox_fetch(mbox, msg, 0); } else { if (next_timeout->time > 0) { time_needed = sys_arch_mbox_fetch(mbox, msg, next_timeout->time); } else { time_needed = SYS_ARCH_TIMEOUT; } if (time_needed == SYS_ARCH_TIMEOUT) { /* If time == SYS_ARCH_TIMEOUT, a timeout occured before a message could be fetched. We should now call the timeout handler and deallocate the memory allocated for the timeout. */ tmptimeout = next_timeout; next_timeout = tmptimeout->next; handler = tmptimeout->h; arg = tmptimeout->arg; #if LWIP_DEBUG_TIMERNAMES if (handler != NULL) { LWIP_DEBUGF(TIMERS_DEBUG, ("stmf calling h=%s arg=%p\n", tmptimeout->handler_name, arg)); } #endif /* LWIP_DEBUG_TIMERNAMES */ memp_free(MEMP_SYS_TIMEOUT, tmptimeout); if (handler != NULL) { /* For LWIP_TCPIP_CORE_LOCKING, lock the core before calling the timeout handler function. */ LOCK_TCPIP_CORE(); handler(arg); UNLOCK_TCPIP_CORE(); } LWIP_TCPIP_THREAD_ALIVE(); /* We try again to fetch a message from the mbox. */ goto again; } else { /* If time != SYS_ARCH_TIMEOUT, a message was received before the timeout occured. The time variable is set to the number of milliseconds we waited for the message. */ if (time_needed < next_timeout->time) { next_timeout->time -= time_needed; } else { next_timeout->time = 0; } } } } #endif /* NO_SYS */ #else /* LWIP_TIMERS */ /* Satisfy the TCP code which calls this function */ void tcp_timer_needed(void) { } #endif /* LWIP_TIMERS */ ocproxy-1.60/lwip/src/core/udp.c000066400000000000000000001130301303453231400165650ustar00rootroot00000000000000/** * @file * User Datagram Protocol module * */ /* * Copyright (c) 2001-2004 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ /* udp.c * * The code for the User Datagram Protocol UDP & UDPLite (RFC 3828). * */ /* @todo Check the use of '(struct udp_pcb).chksum_len_rx'! */ #include "lwip/opt.h" #if LWIP_UDP /* don't build if not configured for use in lwipopts.h */ #include "lwip/udp.h" #include "lwip/def.h" #include "lwip/memp.h" #include "lwip/inet_chksum.h" #include "lwip/ip_addr.h" #include "lwip/ip6.h" #include "lwip/ip6_addr.h" #include "lwip/inet_chksum.h" #include "lwip/netif.h" #include "lwip/icmp.h" #include "lwip/icmp6.h" #include "lwip/stats.h" #include "lwip/snmp.h" #include "arch/perf.h" #include "lwip/dhcp.h" #include #ifndef UDP_LOCAL_PORT_RANGE_START /* From http://www.iana.org/assignments/port-numbers: "The Dynamic and/or Private Ports are those from 49152 through 65535" */ #define UDP_LOCAL_PORT_RANGE_START 0xc000 #define UDP_LOCAL_PORT_RANGE_END 0xffff #define UDP_ENSURE_LOCAL_PORT_RANGE(port) (((port) & ~UDP_LOCAL_PORT_RANGE_START) + UDP_LOCAL_PORT_RANGE_START) #endif /* last local UDP port */ static u16_t udp_port = UDP_LOCAL_PORT_RANGE_START; /* The list of UDP PCBs */ /* exported in udp.h (was static) */ struct udp_pcb *udp_pcbs; /** * Initialize this module. */ void udp_init(void) { #if LWIP_RANDOMIZE_INITIAL_LOCAL_PORTS && defined(LWIP_RAND) udp_port = UDP_ENSURE_LOCAL_PORT_RANGE(LWIP_RAND()); #endif /* LWIP_RANDOMIZE_INITIAL_LOCAL_PORTS && defined(LWIP_RAND) */ } /** * Allocate a new local UDP port. * * @return a new (free) local UDP port number */ static u16_t udp_new_port(void) { u16_t n = 0; struct udp_pcb *pcb; again: if (udp_port++ == UDP_LOCAL_PORT_RANGE_END) { udp_port = UDP_LOCAL_PORT_RANGE_START; } /* Check all PCBs. */ for(pcb = udp_pcbs; pcb != NULL; pcb = pcb->next) { if (pcb->local_port == udp_port) { if (++n > (UDP_LOCAL_PORT_RANGE_END - UDP_LOCAL_PORT_RANGE_START)) { return 0; } goto again; } } return udp_port; #if 0 struct udp_pcb *ipcb = udp_pcbs; while ((ipcb != NULL) && (udp_port != UDP_LOCAL_PORT_RANGE_END)) { if (ipcb->local_port == udp_port) { /* port is already used by another udp_pcb */ udp_port++; /* restart scanning all udp pcbs */ ipcb = udp_pcbs; } else { /* go on with next udp pcb */ ipcb = ipcb->next; } } if (ipcb != NULL) { return 0; } return udp_port; #endif } /** * Process an incoming UDP datagram. * * Given an incoming UDP datagram (as a chain of pbufs) this function * finds a corresponding UDP PCB and hands over the pbuf to the pcbs * recv function. If no pcb is found or the datagram is incorrect, the * pbuf is freed. * * @param p pbuf to be demultiplexed to a UDP PCB (p->payload pointing to the UDP header) * @param inp network interface on which the datagram was received. * */ void udp_input(struct pbuf *p, struct netif *inp) { struct udp_hdr *udphdr; struct udp_pcb *pcb, *prev; struct udp_pcb *uncon_pcb; u16_t src, dest; u8_t local_match; u8_t broadcast; u8_t for_us; PERF_START; UDP_STATS_INC(udp.recv); /* Check minimum length (UDP header) */ if (p->len < UDP_HLEN) { /* drop short packets */ LWIP_DEBUGF(UDP_DEBUG, ("udp_input: short UDP datagram (%"U16_F" bytes) discarded\n", p->tot_len)); UDP_STATS_INC(udp.lenerr); UDP_STATS_INC(udp.drop); snmp_inc_udpinerrors(); pbuf_free(p); goto end; } udphdr = (struct udp_hdr *)p->payload; /* is broadcast packet ? */ #if LWIP_IPV6 broadcast = !ip_current_is_v6() && ip_addr_isbroadcast(ip_current_dest_addr(), inp); #else /* LWIP_IPV6 */ broadcast = ip_addr_isbroadcast(ip_current_dest_addr(), inp); #endif /* LWIP_IPV6 */ LWIP_DEBUGF(UDP_DEBUG, ("udp_input: received datagram of length %"U16_F"\n", p->tot_len)); /* convert src and dest ports to host byte order */ src = ntohs(udphdr->src); dest = ntohs(udphdr->dest); udp_debug_print(udphdr); /* print the UDP source and destination */ LWIP_DEBUGF(UDP_DEBUG, ("udp (")); ipX_addr_debug_print(ip_current_is_v6(), UDP_DEBUG, ipX_current_dest_addr()); LWIP_DEBUGF(UDP_DEBUG, (", %"U16_F") <-- (", ntohs(udphdr->dest))); ipX_addr_debug_print(ip_current_is_v6(), UDP_DEBUG, ipX_current_src_addr()); LWIP_DEBUGF(UDP_DEBUG, (", %"U16_F")\n", ntohs(udphdr->src))); #if LWIP_DHCP pcb = NULL; /* when LWIP_DHCP is active, packets to DHCP_CLIENT_PORT may only be processed by the dhcp module, no other UDP pcb may use the local UDP port DHCP_CLIENT_PORT */ if (dest == DHCP_CLIENT_PORT) { /* all packets for DHCP_CLIENT_PORT not coming from DHCP_SERVER_PORT are dropped! */ if (src == DHCP_SERVER_PORT) { if ((inp->dhcp != NULL) && (inp->dhcp->pcb != NULL)) { /* accept the packe if (- broadcast or directed to us) -> DHCP is link-layer-addressed, local ip is always ANY! - inp->dhcp->pcb->remote == ANY or iphdr->src (no need to check for IPv6 since the dhcp struct always uses IPv4) */ if (ipX_addr_isany(0, &inp->dhcp->pcb->remote_ip) || ip_addr_cmp(ipX_2_ip(&(inp->dhcp->pcb->remote_ip)), ip_current_src_addr())) { pcb = inp->dhcp->pcb; } } } } else #endif /* LWIP_DHCP */ { prev = NULL; local_match = 0; uncon_pcb = NULL; /* Iterate through the UDP pcb list for a matching pcb. * 'Perfect match' pcbs (connected to the remote port & ip address) are * preferred. If no perfect match is found, the first unconnected pcb that * matches the local port and ip address gets the datagram. */ for (pcb = udp_pcbs; pcb != NULL; pcb = pcb->next) { local_match = 0; /* print the PCB local and remote address */ LWIP_DEBUGF(UDP_DEBUG, ("pcb (")); ipX_addr_debug_print(PCB_ISIPV6(pcb), UDP_DEBUG, &pcb->local_ip); LWIP_DEBUGF(UDP_DEBUG, (", %"U16_F") <-- (", pcb->local_port)); ipX_addr_debug_print(PCB_ISIPV6(pcb), UDP_DEBUG, &pcb->remote_ip); LWIP_DEBUGF(UDP_DEBUG, (", %"U16_F")\n", pcb->remote_port)); /* compare PCB local addr+port to UDP destination addr+port */ if (pcb->local_port == dest) { if ( #if LWIP_IPV6 ((PCB_ISIPV6(pcb) && (ip_current_is_v6()) && (ip6_addr_isany(ipX_2_ip6(&pcb->local_ip)) || #if LWIP_IPV6_MLD ip6_addr_ismulticast(ip6_current_dest_addr()) || #endif /* LWIP_IPV6_MLD */ ip6_addr_cmp(ipX_2_ip6(&pcb->local_ip), ip6_current_dest_addr()))) || (!PCB_ISIPV6(pcb) && (ip_current_header() != NULL) && #else /* LWIP_IPV6 */ (( #endif /* LWIP_IPV6 */ ((!broadcast && ipX_addr_isany(0, &pcb->local_ip)) || ip_addr_cmp(ipX_2_ip(&pcb->local_ip), ip_current_dest_addr()) || #if LWIP_IGMP ip_addr_ismulticast(ip_current_dest_addr()) || #endif /* LWIP_IGMP */ #if IP_SOF_BROADCAST_RECV (broadcast && ip_get_option(pcb, SOF_BROADCAST) && (ipX_addr_isany(0, &pcb->local_ip) || ip_addr_netcmp(ipX_2_ip(&pcb->local_ip), ip_current_dest_addr(), &inp->netmask))))))) { #else /* IP_SOF_BROADCAST_RECV */ (broadcast && (ipX_addr_isany(0, &pcb->local_ip) || ip_addr_netcmp(ipX_2_ip(&pcb->local_ip), ip_current_dest_addr(), &inp->netmask))))))) { #endif /* IP_SOF_BROADCAST_RECV */ local_match = 1; if ((uncon_pcb == NULL) && ((pcb->flags & UDP_FLAGS_CONNECTED) == 0)) { /* the first unconnected matching PCB */ uncon_pcb = pcb; } } } /* compare PCB remote addr+port to UDP source addr+port */ if ((local_match != 0) && (pcb->remote_port == src) && IP_PCB_IPVER_INPUT_MATCH(pcb) && (ipX_addr_isany(PCB_ISIPV6(pcb), &pcb->remote_ip) || ipX_addr_cmp(PCB_ISIPV6(pcb), &pcb->remote_ip, ipX_current_src_addr()))) { /* the first fully matching PCB */ if (prev != NULL) { /* move the pcb to the front of udp_pcbs so that is found faster next time */ prev->next = pcb->next; pcb->next = udp_pcbs; udp_pcbs = pcb; } else { UDP_STATS_INC(udp.cachehit); } break; } prev = pcb; } /* no fully matching pcb found? then look for an unconnected pcb */ if (pcb == NULL) { pcb = uncon_pcb; } } /* Check checksum if this is a match or if it was directed at us. */ if (pcb != NULL) { for_us = 1; } else { #if LWIP_IPV6 if (ip_current_is_v6()) { for_us = netif_get_ip6_addr_match(inp, ip6_current_dest_addr()) >= 0; } else #endif /* LWIP_IPV6 */ { for_us = ip_addr_cmp(&inp->ip_addr, ip_current_dest_addr()); } } if (for_us) { LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_input: calculating checksum\n")); #if CHECKSUM_CHECK_UDP #if LWIP_UDPLITE if (ip_current_header_proto() == IP_PROTO_UDPLITE) { /* Do the UDP Lite checksum */ u16_t chklen = ntohs(udphdr->len); if (chklen < sizeof(struct udp_hdr)) { if (chklen == 0) { /* For UDP-Lite, checksum length of 0 means checksum over the complete packet (See RFC 3828 chap. 3.1) */ chklen = p->tot_len; } else { /* At least the UDP-Lite header must be covered by the checksum! (Again, see RFC 3828 chap. 3.1) */ goto chkerr; } } if (ipX_chksum_pseudo_partial(ip_current_is_v6(), p, IP_PROTO_UDPLITE, p->tot_len, chklen, ipX_current_src_addr(), ipX_current_dest_addr()) != 0) { goto chkerr; } } else #endif /* LWIP_UDPLITE */ { if (udphdr->chksum != 0) { if (ipX_chksum_pseudo(ip_current_is_v6(), p, IP_PROTO_UDP, p->tot_len, ipX_current_src_addr(), ipX_current_dest_addr()) != 0) { goto chkerr; } } } #endif /* CHECKSUM_CHECK_UDP */ if(pbuf_header(p, -UDP_HLEN)) { /* Can we cope with this failing? Just assert for now */ LWIP_ASSERT("pbuf_header failed\n", 0); UDP_STATS_INC(udp.drop); snmp_inc_udpinerrors(); pbuf_free(p); goto end; } if (pcb != NULL) { snmp_inc_udpindatagrams(); #if SO_REUSE && SO_REUSE_RXTOALL if ((broadcast || #if LWIP_IPV6 ip6_addr_ismulticast(ip6_current_dest_addr()) || #endif /* LWIP_IPV6 */ ip_addr_ismulticast(ip_current_dest_addr())) && ip_get_option(pcb, SOF_REUSEADDR)) { /* pass broadcast- or multicast packets to all multicast pcbs if SOF_REUSEADDR is set on the first match */ struct udp_pcb *mpcb; u8_t p_header_changed = 0; s16_t hdrs_len = (s16_t)(ip_current_header_tot_len() + UDP_HLEN); for (mpcb = udp_pcbs; mpcb != NULL; mpcb = mpcb->next) { if (mpcb != pcb) { /* compare PCB local addr+port to UDP destination addr+port */ if ((mpcb->local_port == dest) && #if LWIP_IPV6 ((PCB_ISIPV6(mpcb) && (ip6_addr_ismulticast(ip6_current_dest_addr()) || ip6_addr_cmp(ipX_2_ip6(&mpcb->local_ip), ip6_current_dest_addr()))) || (!PCB_ISIPV6(mpcb) && #else /* LWIP_IPV6 */ (( #endif /* LWIP_IPV6 */ ((!broadcast && ipX_addr_isany(0, &mpcb->local_ip)) || ip_addr_cmp(ipX_2_ip(&mpcb->local_ip), ip_current_dest_addr()) || #if LWIP_IGMP ip_addr_ismulticast(ip_current_dest_addr()) || #endif /* LWIP_IGMP */ #if IP_SOF_BROADCAST_RECV (broadcast && ip_get_option(mpcb, SOF_BROADCAST)))))) { #else /* IP_SOF_BROADCAST_RECV */ (broadcast))))) { #endif /* IP_SOF_BROADCAST_RECV */ /* pass a copy of the packet to all local matches */ if (mpcb->recv.ip4 != NULL) { struct pbuf *q; /* for that, move payload to IP header again */ if (p_header_changed == 0) { pbuf_header(p, hdrs_len); p_header_changed = 1; } q = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM); if (q != NULL) { err_t err = pbuf_copy(q, p); if (err == ERR_OK) { /* move payload to UDP data */ pbuf_header(q, -hdrs_len); #if LWIP_IPV6 if (PCB_ISIPV6(mpcb)) { mpcb->recv.ip6(mpcb->recv_arg, mpcb, q, ip6_current_src_addr(), src); } else #endif /* LWIP_IPV6 */ { mpcb->recv.ip4(mpcb->recv_arg, mpcb, q, ip_current_src_addr(), src); } } } } } } } if (p_header_changed) { /* and move payload to UDP data again */ pbuf_header(p, -hdrs_len); } } #endif /* SO_REUSE && SO_REUSE_RXTOALL */ /* callback */ if (pcb->recv.ip4 != NULL) { /* now the recv function is responsible for freeing p */ #if LWIP_IPV6 if (PCB_ISIPV6(pcb)) { pcb->recv.ip6(pcb->recv_arg, pcb, p, ip6_current_src_addr(), src); } else #endif /* LWIP_IPV6 */ { pcb->recv.ip4(pcb->recv_arg, pcb, p, ip_current_src_addr(), src); } } else { /* no recv function registered? then we have to free the pbuf! */ pbuf_free(p); goto end; } } else { LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_input: not for us.\n")); #if LWIP_ICMP || LWIP_ICMP6 /* No match was found, send ICMP destination port unreachable unless destination address was broadcast/multicast. */ if (!broadcast && #if LWIP_IPV6 !ip6_addr_ismulticast(ip6_current_dest_addr()) && #endif /* LWIP_IPV6 */ !ip_addr_ismulticast(ip_current_dest_addr())) { /* move payload pointer back to ip header */ pbuf_header(p, ip_current_header_tot_len() + UDP_HLEN); icmp_port_unreach(ip_current_is_v6(), p); } #endif /* LWIP_ICMP || LWIP_ICMP6 */ UDP_STATS_INC(udp.proterr); UDP_STATS_INC(udp.drop); snmp_inc_udpnoports(); pbuf_free(p); } } else { pbuf_free(p); } end: PERF_STOP("udp_input"); return; #if CHECKSUM_CHECK_UDP chkerr: LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("udp_input: UDP (or UDP Lite) datagram discarded due to failing checksum\n")); UDP_STATS_INC(udp.chkerr); UDP_STATS_INC(udp.drop); snmp_inc_udpinerrors(); pbuf_free(p); PERF_STOP("udp_input"); #endif /* CHECKSUM_CHECK_UDP */ } /** * Send data using UDP. * * @param pcb UDP PCB used to send the data. * @param p chain of pbuf's to be sent. * * The datagram will be sent to the current remote_ip & remote_port * stored in pcb. If the pcb is not bound to a port, it will * automatically be bound to a random port. * * @return lwIP error code. * - ERR_OK. Successful. No error occured. * - ERR_MEM. Out of memory. * - ERR_RTE. Could not find route to destination address. * - More errors could be returned by lower protocol layers. * * @see udp_disconnect() udp_sendto() */ err_t udp_send(struct udp_pcb *pcb, struct pbuf *p) { /* send to the packet using remote ip and port stored in the pcb */ return udp_sendto(pcb, p, ipX_2_ip(&pcb->remote_ip), pcb->remote_port); } #if LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP /** Same as udp_send() but with checksum */ err_t udp_send_chksum(struct udp_pcb *pcb, struct pbuf *p, u8_t have_chksum, u16_t chksum) { /* send to the packet using remote ip and port stored in the pcb */ return udp_sendto_chksum(pcb, p, ipX_2_ip(&pcb->remote_ip), pcb->remote_port, have_chksum, chksum); } #endif /* LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP */ /** * Send data to a specified address using UDP. * * @param pcb UDP PCB used to send the data. * @param p chain of pbuf's to be sent. * @param dst_ip Destination IP address. * @param dst_port Destination UDP port. * * dst_ip & dst_port are expected to be in the same byte order as in the pcb. * * If the PCB already has a remote address association, it will * be restored after the data is sent. * * @return lwIP error code (@see udp_send for possible error codes) * * @see udp_disconnect() udp_send() */ err_t udp_sendto(struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip, u16_t dst_port) { #if LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP return udp_sendto_chksum(pcb, p, dst_ip, dst_port, 0, 0); } /** Same as udp_sendto(), but with checksum */ err_t udp_sendto_chksum(struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip, u16_t dst_port, u8_t have_chksum, u16_t chksum) { #endif /* LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP */ struct netif *netif; ipX_addr_t *dst_ip_route = ip_2_ipX(dst_ip); LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_send\n")); #if LWIP_IPV6 || LWIP_IGMP if (ipX_addr_ismulticast(PCB_ISIPV6(pcb), dst_ip_route)) { /* For multicast, find a netif based on source address. */ #if LWIP_IPV6 if (PCB_ISIPV6(pcb)) { dst_ip_route = &pcb->local_ip; } else #endif /* LWIP_IPV6 */ { #if LWIP_IGMP dst_ip_route = ip_2_ipX(&pcb->multicast_ip); #endif /* LWIP_IGMP */ } } #endif /* LWIP_IPV6 || LWIP_IGMP */ /* find the outgoing network interface for this packet */ netif = ipX_route(PCB_ISIPV6(pcb), &pcb->local_ip, dst_ip_route); /* no outgoing network interface could be found? */ if (netif == NULL) { LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("udp_send: No route to ")); ipX_addr_debug_print(PCB_ISIPV6(pcb), UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ip_2_ipX(dst_ip)); LWIP_DEBUGF(UDP_DEBUG, ("\n")); UDP_STATS_INC(udp.rterr); return ERR_RTE; } #if LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP return udp_sendto_if_chksum(pcb, p, dst_ip, dst_port, netif, have_chksum, chksum); #else /* LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP */ return udp_sendto_if(pcb, p, dst_ip, dst_port, netif); #endif /* LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP */ } /** * Send data to a specified address using UDP. * The netif used for sending can be specified. * * This function exists mainly for DHCP, to be able to send UDP packets * on a netif that is still down. * * @param pcb UDP PCB used to send the data. * @param p chain of pbuf's to be sent. * @param dst_ip Destination IP address. * @param dst_port Destination UDP port. * @param netif the netif used for sending. * * dst_ip & dst_port are expected to be in the same byte order as in the pcb. * * @return lwIP error code (@see udp_send for possible error codes) * * @see udp_disconnect() udp_send() */ err_t udp_sendto_if(struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip, u16_t dst_port, struct netif *netif) { #if LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP return udp_sendto_if_chksum(pcb, p, dst_ip, dst_port, netif, 0, 0); } /** Same as udp_sendto_if(), but with checksum */ err_t udp_sendto_if_chksum(struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip, u16_t dst_port, struct netif *netif, u8_t have_chksum, u16_t chksum) { #endif /* LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP */ ip_addr_t *src_ip; /* PCB local address is IP_ANY_ADDR? */ #if LWIP_IPV6 if (PCB_ISIPV6(pcb)) { if (ip6_addr_isany(ipX_2_ip6(&pcb->local_ip))) { src_ip = ip6_2_ip(ip6_select_source_address(netif, ip_2_ip6(dst_ip))); if (src_ip == NULL) { /* No suitable source address was found. */ return ERR_RTE; } } else { /* use UDP PCB local IPv6 address as source address, if still valid. */ if (netif_get_ip6_addr_match(netif, ipX_2_ip6(&pcb->local_ip)) < 0) { /* Address isn't valid anymore. */ return ERR_RTE; } src_ip = ipX_2_ip(&pcb->local_ip); } } else #endif /* LWIP_IPV6 */ if (ip_addr_isany(ipX_2_ip(&pcb->local_ip))) { /* use outgoing network interface IP address as source address */ src_ip = &(netif->ip_addr); } else { /* check if UDP PCB local IP address is correct * this could be an old address if netif->ip_addr has changed */ if (!ip_addr_cmp(ipX_2_ip(&(pcb->local_ip)), &(netif->ip_addr))) { /* local_ip doesn't match, drop the packet */ return ERR_VAL; } /* use UDP PCB local IP address as source address */ src_ip = ipX_2_ip(&(pcb->local_ip)); } #if LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP return udp_sendto_if_src_chksum(pcb, p, dst_ip, dst_port, netif, have_chksum, chksum, src_ip); #else /* LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP */ return udp_sendto_if_src(pcb, p, dst_ip, dst_port, netif, src_ip); #endif /* LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP */ } /** Same as udp_sendto_if(), but with source address */ err_t udp_sendto_if_src(struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip, u16_t dst_port, struct netif *netif, ip_addr_t *src_ip) { #if LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP return udp_sendto_if_src_chksum(pcb, p, dst_ip, dst_port, netif, 0, 0, src_ip); } /** Same as udp_sendto_if_src(), but with checksum */ err_t udp_sendto_if_src_chksum(struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip, u16_t dst_port, struct netif *netif, u8_t have_chksum, u16_t chksum, ip_addr_t *src_ip) { #endif /* LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP */ struct udp_hdr *udphdr; err_t err; struct pbuf *q; /* q will be sent down the stack */ u8_t ip_proto; #if IP_SOF_BROADCAST /* broadcast filter? */ if (!ip_get_option(pcb, SOF_BROADCAST) && #if LWIP_IPV6 !PCB_ISIPV6(pcb) && #endif /* LWIP_IPV6 */ ip_addr_isbroadcast(dst_ip, netif) ) { LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("udp_sendto_if: SOF_BROADCAST not enabled on pcb %p\n", (void *)pcb)); return ERR_VAL; } #endif /* IP_SOF_BROADCAST */ /* if the PCB is not yet bound to a port, bind it here */ if (pcb->local_port == 0) { LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_send: not yet bound to a port, binding now\n")); err = udp_bind(pcb, ipX_2_ip(&pcb->local_ip), pcb->local_port); if (err != ERR_OK) { LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("udp_send: forced port bind failed\n")); return err; } } /* not enough space to add an UDP header to first pbuf in given p chain? */ if (pbuf_header(p, UDP_HLEN)) { /* allocate header in a separate new pbuf */ q = pbuf_alloc(PBUF_IP, UDP_HLEN, PBUF_RAM); /* new header pbuf could not be allocated? */ if (q == NULL) { LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("udp_send: could not allocate header\n")); return ERR_MEM; } if (p->tot_len != 0) { /* chain header q in front of given pbuf p (only if p contains data) */ pbuf_chain(q, p); } /* first pbuf q points to header pbuf */ LWIP_DEBUGF(UDP_DEBUG, ("udp_send: added header pbuf %p before given pbuf %p\n", (void *)q, (void *)p)); } else { /* adding space for header within p succeeded */ /* first pbuf q equals given pbuf */ q = p; LWIP_DEBUGF(UDP_DEBUG, ("udp_send: added header in given pbuf %p\n", (void *)p)); } LWIP_ASSERT("check that first pbuf can hold struct udp_hdr", (q->len >= sizeof(struct udp_hdr))); /* q now represents the packet to be sent */ udphdr = (struct udp_hdr *)q->payload; udphdr->src = htons(pcb->local_port); udphdr->dest = htons(dst_port); /* in UDP, 0 checksum means 'no checksum' */ udphdr->chksum = 0x0000; /* Multicast Loop? */ #if LWIP_IGMP if (((pcb->flags & UDP_FLAGS_MULTICAST_LOOP) != 0) && #if LWIP_IPV6 ( #if LWIP_IPV6_MLD (PCB_ISIPV6(pcb) && ip6_addr_ismulticast(ip_2_ip6(dst_ip))) || #endif /* LWIP_IPV6_MLD */ (!PCB_ISIPV6(pcb) && #else /* LWIP_IPV6 */ (( #endif /* LWIP_IPV6 */ ip_addr_ismulticast(dst_ip)))) { q->flags |= PBUF_FLAG_MCASTLOOP; } #endif /* LWIP_IGMP */ LWIP_DEBUGF(UDP_DEBUG, ("udp_send: sending datagram of length %"U16_F"\n", q->tot_len)); #if LWIP_UDPLITE /* UDP Lite protocol? */ if (pcb->flags & UDP_FLAGS_UDPLITE) { u16_t chklen, chklen_hdr; LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP LITE packet length %"U16_F"\n", q->tot_len)); /* set UDP message length in UDP header */ chklen_hdr = chklen = pcb->chksum_len_tx; if ((chklen < sizeof(struct udp_hdr)) || (chklen > q->tot_len)) { if (chklen != 0) { LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP LITE pcb->chksum_len is illegal: %"U16_F"\n", chklen)); } /* For UDP-Lite, checksum length of 0 means checksum over the complete packet. (See RFC 3828 chap. 3.1) At least the UDP-Lite header must be covered by the checksum, therefore, if chksum_len has an illegal value, we generate the checksum over the complete packet to be safe. */ chklen_hdr = 0; chklen = q->tot_len; } udphdr->len = htons(chklen_hdr); /* calculate checksum */ #if CHECKSUM_GEN_UDP #if LWIP_CHECKSUM_ON_COPY if (have_chksum) { chklen = UDP_HLEN; } #endif /* LWIP_CHECKSUM_ON_COPY */ udphdr->chksum = ipX_chksum_pseudo_partial(PCB_ISIPV6(pcb), q, IP_PROTO_UDPLITE, q->tot_len, chklen, ip_2_ipX(src_ip), ip_2_ipX(dst_ip)); #if LWIP_CHECKSUM_ON_COPY if (have_chksum) { u32_t acc; acc = udphdr->chksum + (u16_t)~(chksum); udphdr->chksum = FOLD_U32T(acc); } #endif /* LWIP_CHECKSUM_ON_COPY */ /* chksum zero must become 0xffff, as zero means 'no checksum' */ if (udphdr->chksum == 0x0000) { udphdr->chksum = 0xffff; } #endif /* CHECKSUM_GEN_UDP */ ip_proto = IP_PROTO_UDPLITE; } else #endif /* LWIP_UDPLITE */ { /* UDP */ LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP packet length %"U16_F"\n", q->tot_len)); udphdr->len = htons(q->tot_len); /* calculate checksum */ #if CHECKSUM_GEN_UDP /* Checksum is mandatory over IPv6. */ if (PCB_ISIPV6(pcb) || (pcb->flags & UDP_FLAGS_NOCHKSUM) == 0) { u16_t udpchksum; #if LWIP_CHECKSUM_ON_COPY if (have_chksum) { u32_t acc; udpchksum = ipX_chksum_pseudo_partial(PCB_ISIPV6(pcb), q, IP_PROTO_UDP, q->tot_len, UDP_HLEN, ip_2_ipX(src_ip), ip_2_ipX(dst_ip)); acc = udpchksum + (u16_t)~(chksum); udpchksum = FOLD_U32T(acc); } else #endif /* LWIP_CHECKSUM_ON_COPY */ { udpchksum = ipX_chksum_pseudo(PCB_ISIPV6(pcb), q, IP_PROTO_UDP, q->tot_len, ip_2_ipX(src_ip), ip_2_ipX(dst_ip)); } /* chksum zero must become 0xffff, as zero means 'no checksum' */ if (udpchksum == 0x0000) { udpchksum = 0xffff; } udphdr->chksum = udpchksum; } #endif /* CHECKSUM_GEN_UDP */ ip_proto = IP_PROTO_UDP; } LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP checksum 0x%04"X16_F"\n", udphdr->chksum)); LWIP_DEBUGF(UDP_DEBUG, ("udp_send: ip_output_if (,,,,0x%02"X16_F",)\n", (u16_t)ip_proto)); /* output to IP */ NETIF_SET_HWADDRHINT(netif, &(pcb->addr_hint)); err = ipX_output_if_src(PCB_ISIPV6(pcb), q, src_ip, dst_ip, pcb->ttl, pcb->tos, ip_proto, netif); NETIF_SET_HWADDRHINT(netif, NULL); /* TODO: must this be increased even if error occured? */ snmp_inc_udpoutdatagrams(); /* did we chain a separate header pbuf earlier? */ if (q != p) { /* free the header pbuf */ pbuf_free(q); q = NULL; /* p is still referenced by the caller, and will live on */ } UDP_STATS_INC(udp.xmit); return err; } /** * Bind an UDP PCB. * * @param pcb UDP PCB to be bound with a local address ipaddr and port. * @param ipaddr local IP address to bind with. Use IP_ADDR_ANY to * bind to all local interfaces. * @param port local UDP port to bind with. Use 0 to automatically bind * to a random port between UDP_LOCAL_PORT_RANGE_START and * UDP_LOCAL_PORT_RANGE_END. * * ipaddr & port are expected to be in the same byte order as in the pcb. * * @return lwIP error code. * - ERR_OK. Successful. No error occured. * - ERR_USE. The specified ipaddr and port are already bound to by * another UDP PCB. * * @see udp_disconnect() */ err_t udp_bind(struct udp_pcb *pcb, ip_addr_t *ipaddr, u16_t port) { struct udp_pcb *ipcb; u8_t rebind; LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_bind(ipaddr = ")); ipX_addr_debug_print(PCB_ISIPV6(pcb), UDP_DEBUG | LWIP_DBG_TRACE, ip_2_ipX(ipaddr)); LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, (", port = %"U16_F")\n", port)); rebind = 0; /* Check for double bind and rebind of the same pcb */ for (ipcb = udp_pcbs; ipcb != NULL; ipcb = ipcb->next) { /* is this UDP PCB already on active list? */ if (pcb == ipcb) { /* pcb may occur at most once in active list */ LWIP_ASSERT("rebind == 0", rebind == 0); /* pcb already in list, just rebind */ rebind = 1; } /* By default, we don't allow to bind to a port that any other udp PCB is alread bound to, unless *all* PCBs with that port have tha REUSEADDR flag set. */ #if SO_REUSE else if (!ip_get_option(pcb, SOF_REUSEADDR) && !ip_get_option(ipcb, SOF_REUSEADDR)) { #else /* SO_REUSE */ /* port matches that of PCB in list and REUSEADDR not set -> reject */ else { #endif /* SO_REUSE */ if ((ipcb->local_port == port) && IP_PCB_IPVER_EQ(pcb, ipcb) && /* IP address matches, or one is IP_ADDR_ANY? */ (ipX_addr_isany(PCB_ISIPV6(ipcb), &(ipcb->local_ip)) || ipX_addr_isany(PCB_ISIPV6(ipcb), ip_2_ipX(ipaddr)) || ipX_addr_cmp(PCB_ISIPV6(ipcb), &(ipcb->local_ip), ip_2_ipX(ipaddr)))) { /* other PCB already binds to this local IP and port */ LWIP_DEBUGF(UDP_DEBUG, ("udp_bind: local port %"U16_F" already bound by another pcb\n", port)); return ERR_USE; } } } ipX_addr_set_ipaddr(PCB_ISIPV6(pcb), &pcb->local_ip, ipaddr); /* no port specified? */ if (port == 0) { port = udp_new_port(); if (port == 0) { /* no more ports available in local range */ LWIP_DEBUGF(UDP_DEBUG, ("udp_bind: out of free UDP ports\n")); return ERR_USE; } } pcb->local_port = port; snmp_insert_udpidx_tree(pcb); /* pcb not active yet? */ if (rebind == 0) { /* place the PCB on the active list if not already there */ pcb->next = udp_pcbs; udp_pcbs = pcb; } LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("udp_bind: bound to ")); ipX_addr_debug_print(PCB_ISIPV6(pcb), UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, &pcb->local_ip); LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, (", port %"U16_F")\n", pcb->local_port)); return ERR_OK; } /** * Connect an UDP PCB. * * This will associate the UDP PCB with the remote address. * * @param pcb UDP PCB to be connected with remote address ipaddr and port. * @param ipaddr remote IP address to connect with. * @param port remote UDP port to connect with. * * @return lwIP error code * * ipaddr & port are expected to be in the same byte order as in the pcb. * * The udp pcb is bound to a random local port if not already bound. * * @see udp_disconnect() */ err_t udp_connect(struct udp_pcb *pcb, ip_addr_t *ipaddr, u16_t port) { struct udp_pcb *ipcb; if (pcb->local_port == 0) { err_t err = udp_bind(pcb, ipX_2_ip(&pcb->local_ip), pcb->local_port); if (err != ERR_OK) { return err; } } ipX_addr_set_ipaddr(PCB_ISIPV6(pcb), &pcb->remote_ip, ipaddr); pcb->remote_port = port; pcb->flags |= UDP_FLAGS_CONNECTED; /** TODO: this functionality belongs in upper layers */ #ifdef LWIP_UDP_TODO #if LWIP_IPV6 if (!PCB_ISIPV6(pcb)) #endif /* LWIP_IPV6 */ { /* Nail down local IP for netconn_addr()/getsockname() */ if (ip_addr_isany(ipX_2_ip(&pcb->local_ip)) && !ip_addr_isany(ipX_2_ip(&pcb->remote_ip))) { struct netif *netif; if ((netif = ip_route(ipX_2_ip(&pcb->remote_ip))) == NULL) { LWIP_DEBUGF(UDP_DEBUG, ("udp_connect: No route to 0x%lx\n", ip4_addr_get_u32(ipX_2_ip(&pcb->remote_ip)))); UDP_STATS_INC(udp.rterr); return ERR_RTE; } /** TODO: this will bind the udp pcb locally, to the interface which is used to route output packets to the remote address. However, we might want to accept incoming packets on any interface! */ ipX_addr_copy(0, pcb->local_ip, netif->ip_addr); } else if (ip_addr_isany(ipX_2_ip(&pcb->remote_ip))) { ipX_addr_set_any(0, &pcb->local_ip); } } #endif LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("udp_connect: connected to ")); ipX_addr_debug_print(PCB_ISIPV6(pcb), UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, &pcb->remote_ip); LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, (", port %"U16_F")\n", pcb->remote_port)); /* Insert UDP PCB into the list of active UDP PCBs. */ for (ipcb = udp_pcbs; ipcb != NULL; ipcb = ipcb->next) { if (pcb == ipcb) { /* already on the list, just return */ return ERR_OK; } } /* PCB not yet on the list, add PCB now */ pcb->next = udp_pcbs; udp_pcbs = pcb; return ERR_OK; } /** * Disconnect a UDP PCB * * @param pcb the udp pcb to disconnect. */ void udp_disconnect(struct udp_pcb *pcb) { /* reset remote address association */ ipX_addr_set_any(PCB_ISIPV6(pcb), &pcb->remote_ip); pcb->remote_port = 0; /* mark PCB as unconnected */ pcb->flags &= ~UDP_FLAGS_CONNECTED; } /** * Set a receive callback for a UDP PCB * * This callback will be called when receiving a datagram for the pcb. * * @param pcb the pcb for wich to set the recv callback * @param recv function pointer of the callback function * @param recv_arg additional argument to pass to the callback function */ void udp_recv(struct udp_pcb *pcb, udp_recv_fn recv, void *recv_arg) { /* remember recv() callback and user data */ pcb->recv.ip4 = recv; pcb->recv_arg = recv_arg; } /** * Remove an UDP PCB. * * @param pcb UDP PCB to be removed. The PCB is removed from the list of * UDP PCB's and the data structure is freed from memory. * * @see udp_new() */ void udp_remove(struct udp_pcb *pcb) { struct udp_pcb *pcb2; snmp_delete_udpidx_tree(pcb); /* pcb to be removed is first in list? */ if (udp_pcbs == pcb) { /* make list start at 2nd pcb */ udp_pcbs = udp_pcbs->next; /* pcb not 1st in list */ } else { for (pcb2 = udp_pcbs; pcb2 != NULL; pcb2 = pcb2->next) { /* find pcb in udp_pcbs list */ if (pcb2->next != NULL && pcb2->next == pcb) { /* remove pcb from list */ pcb2->next = pcb->next; } } } memp_free(MEMP_UDP_PCB, pcb); } /** * Create a UDP PCB. * * @return The UDP PCB which was created. NULL if the PCB data structure * could not be allocated. * * @see udp_remove() */ struct udp_pcb * udp_new(void) { struct udp_pcb *pcb; pcb = (struct udp_pcb *)memp_malloc(MEMP_UDP_PCB); /* could allocate UDP PCB? */ if (pcb != NULL) { /* UDP Lite: by initializing to all zeroes, chksum_len is set to 0 * which means checksum is generated over the whole datagram per default * (recommended as default by RFC 3828). */ /* initialize PCB to all zeroes */ memset(pcb, 0, sizeof(struct udp_pcb)); pcb->ttl = UDP_TTL; } return pcb; } #if LWIP_IPV6 /** * Create a UDP PCB for IPv6. * * @return The UDP PCB which was created. NULL if the PCB data structure * could not be allocated. * * @see udp_remove() */ struct udp_pcb * udp_new_ip6(void) { struct udp_pcb *pcb; pcb = udp_new(); ip_set_v6(pcb, 1); return pcb; } #endif /* LWIP_IPV6 */ #if UDP_DEBUG /** * Print UDP header information for debug purposes. * * @param udphdr pointer to the udp header in memory. */ void udp_debug_print(struct udp_hdr *udphdr) { LWIP_DEBUGF(UDP_DEBUG, ("UDP header:\n")); LWIP_DEBUGF(UDP_DEBUG, ("+-------------------------------+\n")); LWIP_DEBUGF(UDP_DEBUG, ("| %5"U16_F" | %5"U16_F" | (src port, dest port)\n", ntohs(udphdr->src), ntohs(udphdr->dest))); LWIP_DEBUGF(UDP_DEBUG, ("+-------------------------------+\n")); LWIP_DEBUGF(UDP_DEBUG, ("| %5"U16_F" | 0x%04"X16_F" | (len, chksum)\n", ntohs(udphdr->len), ntohs(udphdr->chksum))); LWIP_DEBUGF(UDP_DEBUG, ("+-------------------------------+\n")); } #endif /* UDP_DEBUG */ #endif /* LWIP_UDP */ ocproxy-1.60/lwip/src/include/000077500000000000000000000000001303453231400163265ustar00rootroot00000000000000ocproxy-1.60/lwip/src/include/ipv4/000077500000000000000000000000001303453231400172105ustar00rootroot00000000000000ocproxy-1.60/lwip/src/include/ipv4/lwip/000077500000000000000000000000001303453231400201635ustar00rootroot00000000000000ocproxy-1.60/lwip/src/include/ipv4/lwip/autoip.h000066400000000000000000000112201303453231400216310ustar00rootroot00000000000000/** * @file * * AutoIP Automatic LinkLocal IP Configuration */ /* * * Copyright (c) 2007 Dominik Spies * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * Author: Dominik Spies * * This is a AutoIP implementation for the lwIP TCP/IP stack. It aims to conform * with RFC 3927. * * * Please coordinate changes and requests with Dominik Spies * */ #ifndef LWIP_HDR_AUTOIP_H #define LWIP_HDR_AUTOIP_H #include "lwip/opt.h" #if LWIP_AUTOIP /* don't build if not configured for use in lwipopts.h */ #include "lwip/netif.h" #include "lwip/udp.h" #include "netif/etharp.h" #ifdef __cplusplus extern "C" { #endif /* AutoIP Timing */ #define AUTOIP_TMR_INTERVAL 100 #define AUTOIP_TICKS_PER_SECOND (1000 / AUTOIP_TMR_INTERVAL) /* RFC 3927 Constants */ #define PROBE_WAIT 1 /* second (initial random delay) */ #define PROBE_MIN 1 /* second (minimum delay till repeated probe) */ #define PROBE_MAX 2 /* seconds (maximum delay till repeated probe) */ #define PROBE_NUM 3 /* (number of probe packets) */ #define ANNOUNCE_NUM 2 /* (number of announcement packets) */ #define ANNOUNCE_INTERVAL 2 /* seconds (time between announcement packets) */ #define ANNOUNCE_WAIT 2 /* seconds (delay before announcing) */ #define MAX_CONFLICTS 10 /* (max conflicts before rate limiting) */ #define RATE_LIMIT_INTERVAL 60 /* seconds (delay between successive attempts) */ #define DEFEND_INTERVAL 10 /* seconds (min. wait between defensive ARPs) */ /* AutoIP client states */ #define AUTOIP_STATE_OFF 0 #define AUTOIP_STATE_PROBING 1 #define AUTOIP_STATE_ANNOUNCING 2 #define AUTOIP_STATE_BOUND 3 struct autoip { ip_addr_t llipaddr; /* the currently selected, probed, announced or used LL IP-Address */ u8_t state; /* current AutoIP state machine state */ u8_t sent_num; /* sent number of probes or announces, dependent on state */ u16_t ttw; /* ticks to wait, tick is AUTOIP_TMR_INTERVAL long */ u8_t lastconflict; /* ticks until a conflict can be solved by defending */ u8_t tried_llipaddr; /* total number of probed/used Link Local IP-Addresses */ }; #define autoip_init() /* Compatibility define, no init needed. */ /** Set a struct autoip allocated by the application to work with */ void autoip_set_struct(struct netif *netif, struct autoip *autoip); /** Remove a struct autoip previously set to the netif using autoip_set_struct() */ #define autoip_remove_struct(netif) do { (netif)->autoip = NULL; } while (0) /** Start AutoIP client */ err_t autoip_start(struct netif *netif); /** Stop AutoIP client */ err_t autoip_stop(struct netif *netif); /** Handles every incoming ARP Packet, called by etharp_arp_input */ void autoip_arp_reply(struct netif *netif, struct etharp_hdr *hdr); /** Has to be called in loop every AUTOIP_TMR_INTERVAL milliseconds */ void autoip_tmr(void); /** Handle a possible change in the network configuration */ void autoip_network_changed(struct netif *netif); #ifdef __cplusplus } #endif #endif /* LWIP_AUTOIP */ #endif /* LWIP_HDR_AUTOIP_H */ ocproxy-1.60/lwip/src/include/ipv4/lwip/icmp.h000066400000000000000000000105171303453231400212700ustar00rootroot00000000000000/* * Copyright (c) 2001-2004 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #ifndef LWIP_HDR_ICMP_H #define LWIP_HDR_ICMP_H #include "lwip/opt.h" #include "lwip/pbuf.h" #include "lwip/ip_addr.h" #include "lwip/netif.h" #if LWIP_IPV6 && LWIP_ICMP6 #include "lwip/icmp6.h" #endif #ifdef __cplusplus extern "C" { #endif #define ICMP_ER 0 /* echo reply */ #define ICMP_DUR 3 /* destination unreachable */ #define ICMP_SQ 4 /* source quench */ #define ICMP_RD 5 /* redirect */ #define ICMP_ECHO 8 /* echo */ #define ICMP_TE 11 /* time exceeded */ #define ICMP_PP 12 /* parameter problem */ #define ICMP_TS 13 /* timestamp */ #define ICMP_TSR 14 /* timestamp reply */ #define ICMP_IRQ 15 /* information request */ #define ICMP_IR 16 /* information reply */ enum icmp_dur_type { ICMP_DUR_NET = 0, /* net unreachable */ ICMP_DUR_HOST = 1, /* host unreachable */ ICMP_DUR_PROTO = 2, /* protocol unreachable */ ICMP_DUR_PORT = 3, /* port unreachable */ ICMP_DUR_FRAG = 4, /* fragmentation needed and DF set */ ICMP_DUR_SR = 5 /* source route failed */ }; enum icmp_te_type { ICMP_TE_TTL = 0, /* time to live exceeded in transit */ ICMP_TE_FRAG = 1 /* fragment reassembly time exceeded */ }; #ifdef PACK_STRUCT_USE_INCLUDES # include "arch/bpstruct.h" #endif /** This is the standard ICMP header only that the u32_t data * is splitted to two u16_t like ICMP echo needs it. * This header is also used for other ICMP types that do not * use the data part. */ PACK_STRUCT_BEGIN struct icmp_echo_hdr { PACK_STRUCT_FIELD(u8_t type); PACK_STRUCT_FIELD(u8_t code); PACK_STRUCT_FIELD(u16_t chksum); PACK_STRUCT_FIELD(u16_t id); PACK_STRUCT_FIELD(u16_t seqno); } PACK_STRUCT_STRUCT; PACK_STRUCT_END #ifdef PACK_STRUCT_USE_INCLUDES # include "arch/epstruct.h" #endif #define ICMPH_TYPE(hdr) ((hdr)->type) #define ICMPH_CODE(hdr) ((hdr)->code) /** Combines type and code to an u16_t */ #define ICMPH_TYPE_SET(hdr, t) ((hdr)->type = (t)) #define ICMPH_CODE_SET(hdr, c) ((hdr)->code = (c)) #if LWIP_ICMP /* don't build if not configured for use in lwipopts.h */ void icmp_input(struct pbuf *p, struct netif *inp); void icmp_dest_unreach(struct pbuf *p, enum icmp_dur_type t); void icmp_time_exceeded(struct pbuf *p, enum icmp_te_type t); #endif /* LWIP_ICMP */ #if (LWIP_IPV6 && LWIP_ICMP6) #define icmp_port_unreach(isipv6, pbuf) ((isipv6) ? \ icmp6_dest_unreach(pbuf, ICMP6_DUR_PORT) : \ icmp_dest_unreach(pbuf, ICMP_DUR_PORT)) #elif LWIP_ICMP #define icmp_port_unreach(isipv6, pbuf) icmp_dest_unreach(pbuf, ICMP_DUR_PORT) #else /* (LWIP_IPV6 && LWIP_ICMP6) || LWIP_ICMP*/ #define icmp_port_unreach(isipv6, pbuf) #endif /* (LWIP_IPV6 && LWIP_ICMP6) || LWIP_ICMP*/ #ifdef __cplusplus } #endif #endif /* LWIP_HDR_ICMP_H */ ocproxy-1.60/lwip/src/include/ipv4/lwip/igmp.h000066400000000000000000000074761303453231400213060ustar00rootroot00000000000000/* * Copyright (c) 2002 CITEL Technologies Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of CITEL Technologies Ltd nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY CITEL TECHNOLOGIES AND CONTRIBUTORS ``AS IS'' * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL CITEL TECHNOLOGIES OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * This file is a contribution to the lwIP TCP/IP stack. * The Swedish Institute of Computer Science and Adam Dunkels * are specifically granted permission to redistribute this * source code. */ #ifndef LWIP_HDR_IGMP_H #define LWIP_HDR_IGMP_H #include "lwip/opt.h" #include "lwip/ip_addr.h" #include "lwip/netif.h" #include "lwip/pbuf.h" #if LWIP_IGMP /* don't build if not configured for use in lwipopts.h */ #ifdef __cplusplus extern "C" { #endif /* IGMP timer */ #define IGMP_TMR_INTERVAL 100 /* Milliseconds */ #define IGMP_V1_DELAYING_MEMBER_TMR (1000/IGMP_TMR_INTERVAL) #define IGMP_JOIN_DELAYING_MEMBER_TMR (500 /IGMP_TMR_INTERVAL) /* MAC Filter Actions, these are passed to a netif's * igmp_mac_filter callback function. */ #define IGMP_DEL_MAC_FILTER 0 #define IGMP_ADD_MAC_FILTER 1 /** * igmp group structure - there is * a list of groups for each interface * these should really be linked from the interface, but * if we keep them separate we will not affect the lwip original code * too much * * There will be a group for the all systems group address but this * will not run the state machine as it is used to kick off reports * from all the other groups */ struct igmp_group { /** next link */ struct igmp_group *next; /** interface on which the group is active */ struct netif *netif; /** multicast address */ ip_addr_t group_address; /** signifies we were the last person to report */ u8_t last_reporter_flag; /** current state of the group */ u8_t group_state; /** timer for reporting, negative is OFF */ u16_t timer; /** counter of simultaneous uses */ u8_t use; }; /* Prototypes */ void igmp_init(void); err_t igmp_start(struct netif *netif); err_t igmp_stop(struct netif *netif); void igmp_report_groups(struct netif *netif); struct igmp_group *igmp_lookfor_group(struct netif *ifp, ip_addr_t *addr); void igmp_input(struct pbuf *p, struct netif *inp, ip_addr_t *dest); err_t igmp_joingroup(ip_addr_t *ifaddr, ip_addr_t *groupaddr); err_t igmp_leavegroup(ip_addr_t *ifaddr, ip_addr_t *groupaddr); void igmp_tmr(void); #ifdef __cplusplus } #endif #endif /* LWIP_IGMP */ #endif /* LWIP_HDR_IGMP_H */ ocproxy-1.60/lwip/src/include/ipv4/lwip/inet.h000066400000000000000000000110151303453231400212710ustar00rootroot00000000000000/* * Copyright (c) 2001-2004 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #ifndef LWIP_HDR_INET_H #define LWIP_HDR_INET_H #include "lwip/opt.h" #include "lwip/def.h" #include "lwip/ip_addr.h" #ifdef __cplusplus extern "C" { #endif /* If your port already typedef's in_addr_t, define IN_ADDR_T_DEFINED to prevent this code from redefining it. */ #if !defined(in_addr_t) && !defined(IN_ADDR_T_DEFINED) typedef u32_t in_addr_t; #endif /** For compatibility with BSD code */ struct in_addr { in_addr_t s_addr; }; /** 255.255.255.255 */ #define INADDR_NONE IPADDR_NONE /** 127.0.0.1 */ #define INADDR_LOOPBACK IPADDR_LOOPBACK /** 0.0.0.0 */ #define INADDR_ANY IPADDR_ANY /** 255.255.255.255 */ #define INADDR_BROADCAST IPADDR_BROADCAST /* Definitions of the bits in an Internet address integer. On subnets, host and network parts are found according to the subnet mask, not these masks. */ #define IN_CLASSA(a) IP_CLASSA(a) #define IN_CLASSA_NET IP_CLASSA_NET #define IN_CLASSA_NSHIFT IP_CLASSA_NSHIFT #define IN_CLASSA_HOST IP_CLASSA_HOST #define IN_CLASSA_MAX IP_CLASSA_MAX #define IN_CLASSB(b) IP_CLASSB(b) #define IN_CLASSB_NET IP_CLASSB_NET #define IN_CLASSB_NSHIFT IP_CLASSB_NSHIFT #define IN_CLASSB_HOST IP_CLASSB_HOST #define IN_CLASSB_MAX IP_CLASSB_MAX #define IN_CLASSC(c) IP_CLASSC(c) #define IN_CLASSC_NET IP_CLASSC_NET #define IN_CLASSC_NSHIFT IP_CLASSC_NSHIFT #define IN_CLASSC_HOST IP_CLASSC_HOST #define IN_CLASSC_MAX IP_CLASSC_MAX #define IN_CLASSD(d) IP_CLASSD(d) #define IN_CLASSD_NET IP_CLASSD_NET /* These ones aren't really */ #define IN_CLASSD_NSHIFT IP_CLASSD_NSHIFT /* net and host fields, but */ #define IN_CLASSD_HOST IP_CLASSD_HOST /* routing needn't know. */ #define IN_CLASSD_MAX IP_CLASSD_MAX #define IN_MULTICAST(a) IP_MULTICAST(a) #define IN_EXPERIMENTAL(a) IP_EXPERIMENTAL(a) #define IN_BADCLASS(a) IP_BADCLASS(a) #define IN_LOOPBACKNET IP_LOOPBACKNET #ifndef INET_ADDRSTRLEN #define INET_ADDRSTRLEN IP4ADDR_STRLEN_MAX #endif #if LWIP_IPV6 #ifndef INET6_ADDRSTRLEN #define INET6_ADDRSTRLEN IP6ADDR_STRLEN_MAX #endif #endif #define inet_addr_from_ipaddr(target_inaddr, source_ipaddr) ((target_inaddr)->s_addr = ip4_addr_get_u32(source_ipaddr)) #define inet_addr_to_ipaddr(target_ipaddr, source_inaddr) (ip4_addr_set_u32(target_ipaddr, (source_inaddr)->s_addr)) /* ATTENTION: the next define only works because both s_addr and ip_addr_t are an u32_t effectively! */ #define inet_addr_to_ipaddr_p(target_ipaddr_p, source_inaddr) ((target_ipaddr_p) = (ip_addr_t*)&((source_inaddr)->s_addr)) /* directly map this to the lwip internal functions */ #define inet_addr(cp) ipaddr_addr(cp) #define inet_aton(cp, addr) ipaddr_aton(cp, (ip_addr_t*)addr) #define inet_ntoa(addr) ipaddr_ntoa((ip_addr_t*)&(addr)) #define inet_ntoa_r(addr, buf, buflen) ipaddr_ntoa_r((ip_addr_t*)&(addr), buf, buflen) #ifdef __cplusplus } #endif #endif /* LWIP_HDR_INET_H */ ocproxy-1.60/lwip/src/include/ipv4/lwip/ip4.h000066400000000000000000000122751303453231400210370ustar00rootroot00000000000000/* * Copyright (c) 2001-2004 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #ifndef LWIP_HDR_IP4_H #define LWIP_HDR_IP4_H #include "lwip/opt.h" #include "lwip/def.h" #include "lwip/pbuf.h" #include "lwip/ip_addr.h" #include "lwip/ip6_addr.h" #include "lwip/err.h" #include "lwip/netif.h" #ifdef __cplusplus extern "C" { #endif /** Currently, the function ip_output_if_opt() is only used with IGMP */ #define IP_OPTIONS_SEND LWIP_IGMP #define IP_HLEN 20 #define IP_PROTO_ICMP 1 #define IP_PROTO_IGMP 2 #define IP_PROTO_UDP 17 #define IP_PROTO_UDPLITE 136 #define IP_PROTO_TCP 6 #ifdef PACK_STRUCT_USE_INCLUDES # include "arch/bpstruct.h" #endif PACK_STRUCT_BEGIN struct ip_hdr { /* version / header length */ PACK_STRUCT_FIELD(u8_t _v_hl); /* type of service */ PACK_STRUCT_FIELD(u8_t _tos); /* total length */ PACK_STRUCT_FIELD(u16_t _len); /* identification */ PACK_STRUCT_FIELD(u16_t _id); /* fragment offset field */ PACK_STRUCT_FIELD(u16_t _offset); #define IP_RF 0x8000U /* reserved fragment flag */ #define IP_DF 0x4000U /* dont fragment flag */ #define IP_MF 0x2000U /* more fragments flag */ #define IP_OFFMASK 0x1fffU /* mask for fragmenting bits */ /* time to live */ PACK_STRUCT_FIELD(u8_t _ttl); /* protocol*/ PACK_STRUCT_FIELD(u8_t _proto); /* checksum */ PACK_STRUCT_FIELD(u16_t _chksum); /* source and destination IP addresses */ PACK_STRUCT_FIELD(ip_addr_p_t src); PACK_STRUCT_FIELD(ip_addr_p_t dest); } PACK_STRUCT_STRUCT; PACK_STRUCT_END #ifdef PACK_STRUCT_USE_INCLUDES # include "arch/epstruct.h" #endif #define IPH_V(hdr) ((hdr)->_v_hl >> 4) #define IPH_HL(hdr) ((hdr)->_v_hl & 0x0f) #define IPH_TOS(hdr) ((hdr)->_tos) #define IPH_LEN(hdr) ((hdr)->_len) #define IPH_ID(hdr) ((hdr)->_id) #define IPH_OFFSET(hdr) ((hdr)->_offset) #define IPH_TTL(hdr) ((hdr)->_ttl) #define IPH_PROTO(hdr) ((hdr)->_proto) #define IPH_CHKSUM(hdr) ((hdr)->_chksum) #define IPH_VHL_SET(hdr, v, hl) (hdr)->_v_hl = (((v) << 4) | (hl)) #define IPH_TOS_SET(hdr, tos) (hdr)->_tos = (tos) #define IPH_LEN_SET(hdr, len) (hdr)->_len = (len) #define IPH_ID_SET(hdr, id) (hdr)->_id = (id) #define IPH_OFFSET_SET(hdr, off) (hdr)->_offset = (off) #define IPH_TTL_SET(hdr, ttl) (hdr)->_ttl = (u8_t)(ttl) #define IPH_PROTO_SET(hdr, proto) (hdr)->_proto = (u8_t)(proto) #define IPH_CHKSUM_SET(hdr, chksum) (hdr)->_chksum = (chksum) #define ip_init() /* Compatibility define, no init needed. */ struct netif *ip_route(ip_addr_t *dest); err_t ip_input(struct pbuf *p, struct netif *inp); err_t ip_output(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, u8_t ttl, u8_t tos, u8_t proto); err_t ip_output_if(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, u8_t ttl, u8_t tos, u8_t proto, struct netif *netif); err_t ip_output_if_src(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, u8_t ttl, u8_t tos, u8_t proto, struct netif *netif); #if LWIP_NETIF_HWADDRHINT err_t ip_output_hinted(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, u8_t ttl, u8_t tos, u8_t proto, u8_t *addr_hint); #endif /* LWIP_NETIF_HWADDRHINT */ #if IP_OPTIONS_SEND err_t ip_output_if_opt(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, u8_t ttl, u8_t tos, u8_t proto, struct netif *netif, void *ip_options, u16_t optlen); err_t ip_output_if_opt_src(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, u8_t ttl, u8_t tos, u8_t proto, struct netif *netif, void *ip_options, u16_t optlen); #endif /* IP_OPTIONS_SEND */ #define ip_netif_get_local_ipX(netif) (((netif) != NULL) ? ip_2_ipX(&((netif)->ip_addr)) : NULL) #if IP_DEBUG void ip_debug_print(struct pbuf *p); #else #define ip_debug_print(p) #endif /* IP_DEBUG */ #ifdef __cplusplus } #endif #endif /* LWIP_HDR_IP_H */ ocproxy-1.60/lwip/src/include/ipv4/lwip/ip4_addr.h000066400000000000000000000231351303453231400220260ustar00rootroot00000000000000/* * Copyright (c) 2001-2004 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #ifndef LWIP_HDR_IP4_ADDR_H #define LWIP_HDR_IP4_ADDR_H #include "lwip/opt.h" #include "lwip/def.h" #ifdef __cplusplus extern "C" { #endif /* This is the aligned version of ip_addr_t, used as local variable, on the stack, etc. */ struct ip_addr { u32_t addr; }; /* This is the packed version of ip_addr_t, used in network headers that are itself packed */ #ifdef PACK_STRUCT_USE_INCLUDES # include "arch/bpstruct.h" #endif PACK_STRUCT_BEGIN struct ip_addr_packed { PACK_STRUCT_FIELD(u32_t addr); } PACK_STRUCT_STRUCT; PACK_STRUCT_END #ifdef PACK_STRUCT_USE_INCLUDES # include "arch/epstruct.h" #endif /** ip_addr_t uses a struct for convenience only, so that the same defines can * operate both on ip_addr_t as well as on ip_addr_p_t. */ typedef struct ip_addr ip_addr_t; typedef struct ip_addr_packed ip_addr_p_t; /* * struct ipaddr2 is used in the definition of the ARP packet format in * order to support compilers that don't have structure packing. */ #ifdef PACK_STRUCT_USE_INCLUDES # include "arch/bpstruct.h" #endif PACK_STRUCT_BEGIN struct ip_addr2 { PACK_STRUCT_FIELD(u16_t addrw[2]); } PACK_STRUCT_STRUCT; PACK_STRUCT_END #ifdef PACK_STRUCT_USE_INCLUDES # include "arch/epstruct.h" #endif /* Forward declaration to not include netif.h */ struct netif; extern const ip_addr_t ip_addr_any; extern const ip_addr_t ip_addr_broadcast; /** IP_ADDR_ can be used as a fixed IP address * for the wildcard and the broadcast address */ #define IP_ADDR_ANY ((ip_addr_t *)&ip_addr_any) #define IP_ADDR_BROADCAST ((ip_addr_t *)&ip_addr_broadcast) /** 255.255.255.255 */ #define IPADDR_NONE ((u32_t)0xffffffffUL) /** 127.0.0.1 */ #define IPADDR_LOOPBACK ((u32_t)0x7f000001UL) /** 0.0.0.0 */ #define IPADDR_ANY ((u32_t)0x00000000UL) /** 255.255.255.255 */ #define IPADDR_BROADCAST ((u32_t)0xffffffffUL) /* Definitions of the bits in an Internet address integer. On subnets, host and network parts are found according to the subnet mask, not these masks. */ #define IP_CLASSA(a) ((((u32_t)(a)) & 0x80000000UL) == 0) #define IP_CLASSA_NET 0xff000000 #define IP_CLASSA_NSHIFT 24 #define IP_CLASSA_HOST (0xffffffff & ~IP_CLASSA_NET) #define IP_CLASSA_MAX 128 #define IP_CLASSB(a) ((((u32_t)(a)) & 0xc0000000UL) == 0x80000000UL) #define IP_CLASSB_NET 0xffff0000 #define IP_CLASSB_NSHIFT 16 #define IP_CLASSB_HOST (0xffffffff & ~IP_CLASSB_NET) #define IP_CLASSB_MAX 65536 #define IP_CLASSC(a) ((((u32_t)(a)) & 0xe0000000UL) == 0xc0000000UL) #define IP_CLASSC_NET 0xffffff00 #define IP_CLASSC_NSHIFT 8 #define IP_CLASSC_HOST (0xffffffff & ~IP_CLASSC_NET) #define IP_CLASSD(a) (((u32_t)(a) & 0xf0000000UL) == 0xe0000000UL) #define IP_CLASSD_NET 0xf0000000 /* These ones aren't really */ #define IP_CLASSD_NSHIFT 28 /* net and host fields, but */ #define IP_CLASSD_HOST 0x0fffffff /* routing needn't know. */ #define IP_MULTICAST(a) IP_CLASSD(a) #define IP_EXPERIMENTAL(a) (((u32_t)(a) & 0xf0000000UL) == 0xf0000000UL) #define IP_BADCLASS(a) (((u32_t)(a) & 0xf0000000UL) == 0xf0000000UL) #define IP_LOOPBACKNET 127 /* official! */ #if BYTE_ORDER == BIG_ENDIAN /** Set an IP address given by the four byte-parts */ #define IP4_ADDR(ipaddr, a,b,c,d) \ (ipaddr)->addr = ((u32_t)((a) & 0xff) << 24) | \ ((u32_t)((b) & 0xff) << 16) | \ ((u32_t)((c) & 0xff) << 8) | \ (u32_t)((d) & 0xff) #else /** Set an IP address given by the four byte-parts. Little-endian version that prevents the use of htonl. */ #define IP4_ADDR(ipaddr, a,b,c,d) \ (ipaddr)->addr = ((u32_t)((d) & 0xff) << 24) | \ ((u32_t)((c) & 0xff) << 16) | \ ((u32_t)((b) & 0xff) << 8) | \ (u32_t)((a) & 0xff) #endif /** MEMCPY-like copying of IP addresses where addresses are known to be * 16-bit-aligned if the port is correctly configured (so a port could define * this to copying 2 u16_t's) - no NULL-pointer-checking needed. */ #ifndef IPADDR2_COPY #define IPADDR2_COPY(dest, src) SMEMCPY(dest, src, sizeof(ip_addr_t)) #endif /** Copy IP address - faster than ip_addr_set: no NULL check */ #define ip_addr_copy(dest, src) ((dest).addr = (src).addr) /** Safely copy one IP address to another (src may be NULL) */ #define ip_addr_set(dest, src) ((dest)->addr = \ ((src) == NULL ? 0 : \ (src)->addr)) /** Set complete address to zero */ #define ip_addr_set_zero(ipaddr) ((ipaddr)->addr = 0) /** Set address to IPADDR_ANY (no need for htonl()) */ #define ip_addr_set_any(ipaddr) ((ipaddr)->addr = IPADDR_ANY) /** Set address to loopback address */ #define ip_addr_set_loopback(ipaddr) ((ipaddr)->addr = PP_HTONL(IPADDR_LOOPBACK)) /** Safely copy one IP address to another and change byte order * from host- to network-order. */ #define ip_addr_set_hton(dest, src) ((dest)->addr = \ ((src) == NULL ? 0:\ htonl((src)->addr))) /** IPv4 only: set the IP address given as an u32_t */ #define ip4_addr_set_u32(dest_ipaddr, src_u32) ((dest_ipaddr)->addr = (src_u32)) /** IPv4 only: get the IP address as an u32_t */ #define ip4_addr_get_u32(src_ipaddr) ((src_ipaddr)->addr) /** Get the network address by combining host address with netmask */ #define ip_addr_get_network(target, host, netmask) ((target)->addr = ((host)->addr) & ((netmask)->addr)) /** * Determine if two address are on the same network. * * @arg addr1 IP address 1 * @arg addr2 IP address 2 * @arg mask network identifier mask * @return !0 if the network identifiers of both address match */ #define ip_addr_netcmp(addr1, addr2, mask) (((addr1)->addr & \ (mask)->addr) == \ ((addr2)->addr & \ (mask)->addr)) #define ip_addr_cmp(addr1, addr2) ((addr1)->addr == (addr2)->addr) #define ip_addr_isany(addr1) ((addr1) == NULL || (addr1)->addr == IPADDR_ANY) #define ip_addr_isbroadcast(ipaddr, netif) ip4_addr_isbroadcast((ipaddr)->addr, (netif)) u8_t ip4_addr_isbroadcast(u32_t addr, const struct netif *netif); #define ip_addr_netmask_valid(netmask) ip4_addr_netmask_valid((netmask)->addr) u8_t ip4_addr_netmask_valid(u32_t netmask); #define ip_addr_ismulticast(addr1) (((addr1)->addr & PP_HTONL(0xf0000000UL)) == PP_HTONL(0xe0000000UL)) #define ip_addr_islinklocal(addr1) (((addr1)->addr & PP_HTONL(0xffff0000UL)) == PP_HTONL(0xa9fe0000UL)) #define ip_addr_debug_print(debug, ipaddr) \ LWIP_DEBUGF(debug, ("%" U16_F ".%" U16_F ".%" U16_F ".%" U16_F, \ ipaddr != NULL ? ip4_addr1_16(ipaddr) : 0, \ ipaddr != NULL ? ip4_addr2_16(ipaddr) : 0, \ ipaddr != NULL ? ip4_addr3_16(ipaddr) : 0, \ ipaddr != NULL ? ip4_addr4_16(ipaddr) : 0)) /* Get one byte from the 4-byte address */ #define ip4_addr1(ipaddr) (((u8_t*)(ipaddr))[0]) #define ip4_addr2(ipaddr) (((u8_t*)(ipaddr))[1]) #define ip4_addr3(ipaddr) (((u8_t*)(ipaddr))[2]) #define ip4_addr4(ipaddr) (((u8_t*)(ipaddr))[3]) /* These are cast to u16_t, with the intent that they are often arguments * to printf using the U16_F format from cc.h. */ #define ip4_addr1_16(ipaddr) ((u16_t)ip4_addr1(ipaddr)) #define ip4_addr2_16(ipaddr) ((u16_t)ip4_addr2(ipaddr)) #define ip4_addr3_16(ipaddr) ((u16_t)ip4_addr3(ipaddr)) #define ip4_addr4_16(ipaddr) ((u16_t)ip4_addr4(ipaddr)) #define IP4ADDR_STRLEN_MAX 16 #define IPADDR_STRLEN_MAX IP4ADDR_STRLEN_MAX /** For backwards compatibility */ #define ip_ntoa(ipaddr) ipaddr_ntoa(ipaddr) u32_t ipaddr_addr(const char *cp); int ipaddr_aton(const char *cp, ip_addr_t *addr); /** returns ptr to static buffer; not reentrant! */ char *ipaddr_ntoa(const ip_addr_t *addr); char *ipaddr_ntoa_r(const ip_addr_t *addr, char *buf, int buflen); #ifdef __cplusplus } #endif #endif /* LWIP_HDR_IP_ADDR_H */ ocproxy-1.60/lwip/src/include/ipv4/lwip/ip_frag.h000066400000000000000000000057631303453231400217560ustar00rootroot00000000000000/* * Copyright (c) 2001-2004 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Jani Monoses * */ #ifndef LWIP_HDR_IP_FRAG_H #define LWIP_HDR_IP_FRAG_H #include "lwip/opt.h" #include "lwip/err.h" #include "lwip/pbuf.h" #include "lwip/netif.h" #include "lwip/ip_addr.h" #include "lwip/ip.h" #ifdef __cplusplus extern "C" { #endif #if IP_REASSEMBLY /* The IP reassembly timer interval in milliseconds. */ #define IP_TMR_INTERVAL 1000 /* IP reassembly helper struct. * This is exported because memp needs to know the size. */ struct ip_reassdata { struct ip_reassdata *next; struct pbuf *p; struct ip_hdr iphdr; u16_t datagram_len; u8_t flags; u8_t timer; }; void ip_reass_init(void); void ip_reass_tmr(void); struct pbuf * ip_reass(struct pbuf *p); #endif /* IP_REASSEMBLY */ #if IP_FRAG #if !IP_FRAG_USES_STATIC_BUF && !LWIP_NETIF_TX_SINGLE_PBUF /** A custom pbuf that holds a reference to another pbuf, which is freed * when this custom pbuf is freed. This is used to create a custom PBUF_REF * that points into the original pbuf. */ #ifndef LWIP_PBUF_CUSTOM_REF_DEFINED #define LWIP_PBUF_CUSTOM_REF_DEFINED struct pbuf_custom_ref { /** 'base class' */ struct pbuf_custom pc; /** pointer to the original pbuf that is referenced */ struct pbuf *original; }; #endif /* LWIP_PBUF_CUSTOM_REF_DEFINED */ #endif /* !IP_FRAG_USES_STATIC_BUF && !LWIP_NETIF_TX_SINGLE_PBUF */ err_t ip_frag(struct pbuf *p, struct netif *netif, ip_addr_t *dest); #endif /* IP_FRAG */ #ifdef __cplusplus } #endif #endif /* LWIP_HDR_IP_FRAG_H */ ocproxy-1.60/lwip/src/include/ipv6/000077500000000000000000000000001303453231400172125ustar00rootroot00000000000000ocproxy-1.60/lwip/src/include/ipv6/lwip/000077500000000000000000000000001303453231400201655ustar00rootroot00000000000000ocproxy-1.60/lwip/src/include/ipv6/lwip/dhcp6.h000066400000000000000000000040271303453231400213450ustar00rootroot00000000000000/** * @file * * IPv6 address autoconfiguration as per RFC 4862. */ /* * Copyright (c) 2010 Inico Technologies Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Ivan Delamer * * IPv6 address autoconfiguration as per RFC 4862. * * Please coordinate changes and requests with Ivan Delamer * */ #ifndef LWIP_HDR_IP6_DHCP6_H #define LWIP_HDR_IP6_DHCP6_H #include "lwip/opt.h" #if LWIP_IPV6_DHCP6 /* don't build if not configured for use in lwipopts.h */ struct dhcp6 { /*TODO: implement DHCP6*/ }; #endif /* LWIP_IPV6_DHCP6 */ #endif /* LWIP_HDR_IP6_DHCP6_H */ ocproxy-1.60/lwip/src/include/ipv6/lwip/ethip6.h000066400000000000000000000043141303453231400215370ustar00rootroot00000000000000/** * @file * * Ethernet output for IPv6. Uses ND tables for link-layer addressing. */ /* * Copyright (c) 2010 Inico Technologies Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Ivan Delamer * * * Please coordinate changes and requests with Ivan Delamer * */ #ifndef LWIP_HDR_ETHIP6_H #define LWIP_HDR_ETHIP6_H #include "lwip/opt.h" #if LWIP_IPV6 && LWIP_ETHERNET /* don't build if not configured for use in lwipopts.h */ #include "lwip/pbuf.h" #include "lwip/ip6.h" #include "lwip/ip6_addr.h" #include "lwip/netif.h" #ifdef __cplusplus extern "C" { #endif err_t ethip6_output(struct netif *netif, struct pbuf *q, ip6_addr_t *ip6addr); #ifdef __cplusplus } #endif #endif /* LWIP_IPV6 && LWIP_ETHERNET */ #endif /* LWIP_HDR_ETHIP6_H */ ocproxy-1.60/lwip/src/include/ipv6/lwip/icmp6.h000066400000000000000000000124271303453231400213620ustar00rootroot00000000000000/** * @file * * IPv6 version of ICMP, as per RFC 4443. */ /* * Copyright (c) 2010 Inico Technologies Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Ivan Delamer * * * Please coordinate changes and requests with Ivan Delamer * */ #ifndef LWIP_HDR_ICMP6_H #define LWIP_HDR_ICMP6_H #include "lwip/opt.h" #include "lwip/pbuf.h" #include "lwip/ip6_addr.h" #include "lwip/netif.h" #ifdef __cplusplus extern "C" { #endif enum icmp6_type { ICMP6_TYPE_DUR = 1, /* Destination unreachable */ ICMP6_TYPE_PTB = 2, /* Packet too big */ ICMP6_TYPE_TE = 3, /* Time exceeded */ ICMP6_TYPE_PP = 4, /* Parameter problem */ ICMP6_TYPE_PE1 = 100, /* Private experimentation */ ICMP6_TYPE_PE2 = 101, /* Private experimentation */ ICMP6_TYPE_RSV_ERR = 127, /* Reserved for expansion of error messages */ ICMP6_TYPE_EREQ = 128, /* Echo request */ ICMP6_TYPE_EREP = 129, /* Echo reply */ ICMP6_TYPE_MLQ = 130, /* Multicast listener query */ ICMP6_TYPE_MLR = 131, /* Multicast listener report */ ICMP6_TYPE_MLD = 132, /* Multicast listener done */ ICMP6_TYPE_RS = 133, /* Router solicitation */ ICMP6_TYPE_RA = 134, /* Router advertisement */ ICMP6_TYPE_NS = 135, /* Neighbor solicitation */ ICMP6_TYPE_NA = 136, /* Neighbor advertisement */ ICMP6_TYPE_RD = 137, /* Redirect */ ICMP6_TYPE_MRA = 151, /* Multicast router advertisement */ ICMP6_TYPE_MRS = 152, /* Multicast router solicitation */ ICMP6_TYPE_MRT = 153, /* Multicast router termination */ ICMP6_TYPE_PE3 = 200, /* Private experimentation */ ICMP6_TYPE_PE4 = 201, /* Private experimentation */ ICMP6_TYPE_RSV_INF = 255 /* Reserved for expansion of informational messages */ }; enum icmp6_dur_code { ICMP6_DUR_NO_ROUTE = 0, /* No route to destination */ ICMP6_DUR_PROHIBITED = 1, /* Communication with destination administratively prohibited */ ICMP6_DUR_SCOPE = 2, /* Beyond scope of source address */ ICMP6_DUR_ADDRESS = 3, /* Address unreachable */ ICMP6_DUR_PORT = 4, /* Port unreachable */ ICMP6_DUR_POLICY = 5, /* Source address failed ingress/egress policy */ ICMP6_DUR_REJECT_ROUTE = 6 /* Reject route to destination */ }; enum icmp6_te_code { ICMP6_TE_HL = 0, /* Hop limit exceeded in transit */ ICMP6_TE_FRAG = 1 /* Fragment reassembly time exceeded */ }; enum icmp6_pp_code { ICMP6_PP_FIELD = 0, /* Erroneous header field encountered */ ICMP6_PP_HEADER = 1, /* Unrecognized next header type encountered */ ICMP6_PP_OPTION = 2 /* Unrecognized IPv6 option encountered */ }; /** This is the standard ICMP6 header. */ #ifdef PACK_STRUCT_USE_INCLUDES # include "arch/bpstruct.h" #endif PACK_STRUCT_BEGIN struct icmp6_hdr { PACK_STRUCT_FIELD(u8_t type); PACK_STRUCT_FIELD(u8_t code); PACK_STRUCT_FIELD(u16_t chksum); PACK_STRUCT_FIELD(u32_t data); } PACK_STRUCT_STRUCT; PACK_STRUCT_END #ifdef PACK_STRUCT_USE_INCLUDES # include "arch/epstruct.h" #endif /** This is the ICMP6 header adapted for echo req/resp. */ #ifdef PACK_STRUCT_USE_INCLUDES # include "arch/bpstruct.h" #endif PACK_STRUCT_BEGIN struct icmp6_echo_hdr { PACK_STRUCT_FIELD(u8_t type); PACK_STRUCT_FIELD(u8_t code); PACK_STRUCT_FIELD(u16_t chksum); PACK_STRUCT_FIELD(u16_t id); PACK_STRUCT_FIELD(u16_t seqno); } PACK_STRUCT_STRUCT; PACK_STRUCT_END #ifdef PACK_STRUCT_USE_INCLUDES # include "arch/epstruct.h" #endif #if LWIP_ICMP6 && LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */ void icmp6_input(struct pbuf *p, struct netif *inp); void icmp6_dest_unreach(struct pbuf *p, enum icmp6_dur_code c); void icmp6_packet_too_big(struct pbuf *p, u32_t mtu); void icmp6_time_exceeded(struct pbuf *p, enum icmp6_te_code c); void icmp6_param_problem(struct pbuf *p, enum icmp6_pp_code c, u32_t pointer); #endif /* LWIP_ICMP6 && LWIP_IPV6 */ #ifdef __cplusplus } #endif #endif /* LWIP_HDR_ICMP6_H */ ocproxy-1.60/lwip/src/include/ipv6/lwip/inet6.h000066400000000000000000000074101303453231400213650ustar00rootroot00000000000000/** * @file * * INET v6 addresses. */ /* * Copyright (c) 2010 Inico Technologies Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Ivan Delamer * * * Please coordinate changes and requests with Ivan Delamer * */ #ifndef LWIP_HDR_INET6_H #define LWIP_HDR_INET6_H #include "lwip/opt.h" #if LWIP_IPV6 && LWIP_SOCKET /* don't build if not configured for use in lwipopts.h */ #include "lwip/ip6_addr.h" #include "lwip/def.h" #ifdef __cplusplus extern "C" { #endif /** For compatibility with BSD code */ struct in6_addr { union { u8_t u8_addr[16]; u32_t u32_addr[4]; } un; #define s6_addr un.u8_addr }; #define IN6ADDR_ANY_INIT {0,0,0,0} #define IN6ADDR_LOOPBACK_INIT {0,0,0,PP_HTONL(1)} #define inet6_addr_from_ip6addr(target_in6addr, source_ip6addr) {(target_in6addr)->un.u32_addr[0] = (source_ip6addr)->addr[0]; \ (target_in6addr)->un.u32_addr[1] = (source_ip6addr)->addr[1]; \ (target_in6addr)->un.u32_addr[2] = (source_ip6addr)->addr[2]; \ (target_in6addr)->un.u32_addr[3] = (source_ip6addr)->addr[3];} #define inet6_addr_to_ip6addr(target_ip6addr, source_in6addr) {(target_ip6addr)->addr[0] = (source_in6addr)->un.u32_addr[0]; \ (target_ip6addr)->addr[1] = (source_in6addr)->un.u32_addr[1]; \ (target_ip6addr)->addr[2] = (source_in6addr)->un.u32_addr[2]; \ (target_ip6addr)->addr[3] = (source_in6addr)->un.u32_addr[3];} /* ATTENTION: the next define only works because both in6_addr and ip6_addr_t are an u32_t[4] effectively! */ #define inet6_addr_to_ip6addr_p(target_ip6addr_p, source_in6addr) ((target_ip6addr_p) = (ip6_addr_t*)(source_in6addr)) /* directly map this to the lwip internal functions */ #define inet6_aton(cp, addr) ip6addr_aton(cp, (ip6_addr_t*)addr) #define inet6_ntoa(addr) ip6addr_ntoa((ip6_addr_t*)&(addr)) #define inet6_ntoa_r(addr, buf, buflen) ip6addr_ntoa_r((ip6_addr_t*)&(addr), buf, buflen) #ifdef __cplusplus } #endif #endif /* LWIP_IPV6 */ #endif /* LWIP_HDR_INET6_H */ ocproxy-1.60/lwip/src/include/ipv6/lwip/ip6.h000066400000000000000000000146111303453231400210370ustar00rootroot00000000000000/** * @file * * IPv6 layer. */ /* * Copyright (c) 2010 Inico Technologies Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Ivan Delamer * * * Please coordinate changes and requests with Ivan Delamer * */ #ifndef LWIP_HDR_IP6_H #define LWIP_HDR_IP6_H #include "lwip/opt.h" #if LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */ #include "lwip/ip6_addr.h" #include "lwip/def.h" #include "lwip/pbuf.h" #include "lwip/netif.h" #include "lwip/err.h" #ifdef __cplusplus extern "C" { #endif #define IP6_HLEN 40 #define IP6_NEXTH_HOPBYHOP 0 #define IP6_NEXTH_TCP 6 #define IP6_NEXTH_UDP 17 #define IP6_NEXTH_ENCAPS 41 #define IP6_NEXTH_ROUTING 43 #define IP6_NEXTH_FRAGMENT 44 #define IP6_NEXTH_ICMP6 58 #define IP6_NEXTH_NONE 59 #define IP6_NEXTH_DESTOPTS 60 #define IP6_NEXTH_UDPLITE 136 /* The IPv6 header. */ #ifdef PACK_STRUCT_USE_INCLUDES # include "arch/bpstruct.h" #endif PACK_STRUCT_BEGIN struct ip6_hdr { /* version / traffic class / flow label */ PACK_STRUCT_FIELD(u32_t _v_tc_fl); /* payload length */ PACK_STRUCT_FIELD(u16_t _plen); /* next header */ PACK_STRUCT_FIELD(u8_t _nexth); /* hop limit */ PACK_STRUCT_FIELD(u8_t _hoplim); /* source and destination IP addresses */ PACK_STRUCT_FIELD(ip6_addr_p_t src); PACK_STRUCT_FIELD(ip6_addr_p_t dest); } PACK_STRUCT_STRUCT; PACK_STRUCT_END #ifdef PACK_STRUCT_USE_INCLUDES # include "arch/epstruct.h" #endif /* Hop-by-hop router alert option. */ #define IP6_HBH_HLEN 8 #define IP6_PAD1_OPTION 0 #define IP6_PADN_ALERT_OPTION 1 #define IP6_ROUTER_ALERT_OPTION 5 #define IP6_ROUTER_ALERT_VALUE_MLD 0 #ifdef PACK_STRUCT_USE_INCLUDES # include "arch/bpstruct.h" #endif PACK_STRUCT_BEGIN struct ip6_hbh_hdr { /* next header */ PACK_STRUCT_FIELD(u8_t _nexth); /* header length */ PACK_STRUCT_FIELD(u8_t _hlen); /* router alert option type */ PACK_STRUCT_FIELD(u8_t _ra_opt_type); /* router alert option data len */ PACK_STRUCT_FIELD(u8_t _ra_opt_dlen); /* router alert option data */ PACK_STRUCT_FIELD(u16_t _ra_opt_data); /* PadN option type */ PACK_STRUCT_FIELD(u8_t _padn_opt_type); /* PadN option data len */ PACK_STRUCT_FIELD(u8_t _padn_opt_dlen); } PACK_STRUCT_STRUCT; PACK_STRUCT_END #ifdef PACK_STRUCT_USE_INCLUDES # include "arch/epstruct.h" #endif /* Fragment header. */ #define IP6_FRAG_HLEN 8 #define IP6_FRAG_OFFSET_MASK 0xfff8 #define IP6_FRAG_MORE_FLAG 0x0001 #ifdef PACK_STRUCT_USE_INCLUDES # include "arch/bpstruct.h" #endif PACK_STRUCT_BEGIN struct ip6_frag_hdr { /* next header */ PACK_STRUCT_FIELD(u8_t _nexth); /* reserved */ PACK_STRUCT_FIELD(u8_t reserved); /* fragment offset */ PACK_STRUCT_FIELD(u16_t _fragment_offset); /* fragmented packet identification */ PACK_STRUCT_FIELD(u32_t _identification); } PACK_STRUCT_STRUCT; PACK_STRUCT_END #ifdef PACK_STRUCT_USE_INCLUDES # include "arch/epstruct.h" #endif #define IP6H_V(hdr) ((ntohl((hdr)->_v_tc_fl) >> 28) & 0x0f) #define IP6H_TC(hdr) ((ntohl((hdr)->_v_tc_fl) >> 20) & 0xff) #define IP6H_FL(hdr) (ntohl((hdr)->_v_tc_fl) & 0x000fffff) #define IP6H_PLEN(hdr) (ntohs((hdr)->_plen)) #define IP6H_NEXTH(hdr) ((hdr)->_nexth) #define IP6H_NEXTH_P(hdr) ((u8_t *)(hdr) + 6) #define IP6H_HOPLIM(hdr) ((hdr)->_hoplim) #define IP6H_VTCFL_SET(hdr, v, tc, fl) (hdr)->_v_tc_fl = (htonl(((v) << 28) | ((tc) << 20) | (fl))) #define IP6H_PLEN_SET(hdr, plen) (hdr)->_plen = htons(plen) #define IP6H_NEXTH_SET(hdr, nexth) (hdr)->_nexth = (nexth) #define IP6H_HOPLIM_SET(hdr, hl) (hdr)->_hoplim = (u8_t)(hl) #define ip6_init() /* TODO should we init current addresses and header pointer? */ struct netif *ip6_route(struct ip6_addr *src, struct ip6_addr *dest); ip6_addr_t *ip6_select_source_address(struct netif *netif, ip6_addr_t * dest); err_t ip6_input(struct pbuf *p, struct netif *inp); err_t ip6_output(struct pbuf *p, struct ip6_addr *src, struct ip6_addr *dest, u8_t hl, u8_t tc, u8_t nexth); err_t ip6_output_if(struct pbuf *p, struct ip6_addr *src, struct ip6_addr *dest, u8_t hl, u8_t tc, u8_t nexth, struct netif *netif); err_t ip6_output_if_src(struct pbuf *p, struct ip6_addr *src, struct ip6_addr *dest, u8_t hl, u8_t tc, u8_t nexth, struct netif *netif); #if LWIP_NETIF_HWADDRHINT err_t ip6_output_hinted(struct pbuf *p, ip6_addr_t *src, ip6_addr_t *dest, u8_t hl, u8_t tc, u8_t nexth, u8_t *addr_hint); #endif /* LWIP_NETIF_HWADDRHINT */ #if LWIP_IPV6_MLD err_t ip6_options_add_hbh_ra(struct pbuf * p, u8_t nexth, u8_t value); #endif /* LWIP_IPV6_MLD */ #define ip6_netif_get_local_ipX(netif, dest) (((netif) != NULL) ? \ ip6_2_ipX(ip6_select_source_address(netif, dest)) : NULL) #if IP6_DEBUG void ip6_debug_print(struct pbuf *p); #else #define ip6_debug_print(p) #endif /* IP6_DEBUG */ #ifdef __cplusplus } #endif #endif /* LWIP_IPV6 */ #endif /* LWIP_HDR_IP6_H */ ocproxy-1.60/lwip/src/include/ipv6/lwip/ip6_addr.h000066400000000000000000000335451303453231400220400ustar00rootroot00000000000000/** * @file * * IPv6 addresses. */ /* * Copyright (c) 2010 Inico Technologies Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Ivan Delamer * * Structs and macros for handling IPv6 addresses. * * Please coordinate changes and requests with Ivan Delamer * */ #ifndef LWIP_HDR_IP6_ADDR_H #define LWIP_HDR_IP6_ADDR_H #include "lwip/opt.h" #if LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */ #ifdef __cplusplus extern "C" { #endif /* This is the aligned version of ip6_addr_t, used as local variable, on the stack, etc. */ struct ip6_addr { u32_t addr[4]; }; /* This is the packed version of ip6_addr_t, used in network headers that are itself packed */ #ifdef PACK_STRUCT_USE_INCLUDES # include "arch/bpstruct.h" #endif PACK_STRUCT_BEGIN struct ip6_addr_packed { PACK_STRUCT_FIELD(u32_t addr[4]); } PACK_STRUCT_STRUCT; PACK_STRUCT_END #ifdef PACK_STRUCT_USE_INCLUDES # include "arch/epstruct.h" #endif /** ip6_addr_t uses a struct for convenience only, so that the same defines can * operate both on ip6_addr_t as well as on ip6_addr_p_t. */ typedef struct ip6_addr ip6_addr_t; typedef struct ip6_addr_packed ip6_addr_p_t; /** IP6_ADDR_ANY can be used as a fixed IPv6 address * for the wildcard */ extern const ip6_addr_t ip6_addr_any; #define IP6_ADDR_ANY ((ip6_addr_t *)&ip6_addr_any) #if BYTE_ORDER == BIG_ENDIAN /** Set an IPv6 partial address given by byte-parts. */ #define IP6_ADDR(ip6addr, index, a,b,c,d) \ (ip6addr)->addr[index] = ((u32_t)((a) & 0xff) << 24) | \ ((u32_t)((b) & 0xff) << 16) | \ ((u32_t)((c) & 0xff) << 8) | \ (u32_t)((d) & 0xff) #else /** Set an IPv6 partial address given by byte-parts. Little-endian version, stored in network order (no htonl). */ #define IP6_ADDR(ip6addr, index, a,b,c,d) \ (ip6addr)->addr[index] = ((u32_t)((d) & 0xff) << 24) | \ ((u32_t)((c) & 0xff) << 16) | \ ((u32_t)((b) & 0xff) << 8) | \ (u32_t)((a) & 0xff) #endif /** Access address in 16-bit block */ #define IP6_ADDR_BLOCK1(ip6addr) ((u16_t)(htonl((ip6addr)->addr[0]) >> 16) & 0xffff) #define IP6_ADDR_BLOCK2(ip6addr) ((u16_t)(htonl((ip6addr)->addr[0])) & 0xffff) #define IP6_ADDR_BLOCK3(ip6addr) ((u16_t)(htonl((ip6addr)->addr[1]) >> 16) & 0xffff) #define IP6_ADDR_BLOCK4(ip6addr) ((u16_t)(htonl((ip6addr)->addr[1])) & 0xffff) #define IP6_ADDR_BLOCK5(ip6addr) ((u16_t)(htonl((ip6addr)->addr[2]) >> 16) & 0xffff) #define IP6_ADDR_BLOCK6(ip6addr) ((u16_t)(htonl((ip6addr)->addr[2])) & 0xffff) #define IP6_ADDR_BLOCK7(ip6addr) ((u16_t)(htonl((ip6addr)->addr[3]) >> 16) & 0xffff) #define IP6_ADDR_BLOCK8(ip6addr) ((u16_t)(htonl((ip6addr)->addr[3])) & 0xffff) /** Copy IPv6 address - faster than ip6_addr_set: no NULL check */ #define ip6_addr_copy(dest, src) do{(dest).addr[0] = (src).addr[0]; \ (dest).addr[1] = (src).addr[1]; \ (dest).addr[2] = (src).addr[2]; \ (dest).addr[3] = (src).addr[3];}while(0) /** Safely copy one IPv6 address to another (src may be NULL) */ #define ip6_addr_set(dest, src) do{(dest)->addr[0] = (src) == NULL ? 0 : (src)->addr[0]; \ (dest)->addr[1] = (src) == NULL ? 0 : (src)->addr[1]; \ (dest)->addr[2] = (src) == NULL ? 0 : (src)->addr[2]; \ (dest)->addr[3] = (src) == NULL ? 0 : (src)->addr[3];}while(0) /** Set complete address to zero */ #define ip6_addr_set_zero(ip6addr) do{(ip6addr)->addr[0] = 0; \ (ip6addr)->addr[1] = 0; \ (ip6addr)->addr[2] = 0; \ (ip6addr)->addr[3] = 0;}while(0) /** Set address to ipv6 'any' (no need for htonl()) */ #define ip6_addr_set_any(ip6addr) ip6_addr_set_zero(ip6addr) /** Set address to ipv6 loopback address */ #define ip6_addr_set_loopback(ip6addr) do{(ip6addr)->addr[0] = 0; \ (ip6addr)->addr[1] = 0; \ (ip6addr)->addr[2] = 0; \ (ip6addr)->addr[3] = PP_HTONL(0x00000001UL);}while(0) /** Safely copy one IPv6 address to another and change byte order * from host- to network-order. */ #define ip6_addr_set_hton(dest, src) do{(dest)->addr[0] = (src) == NULL ? 0 : htonl((src)->addr[0]); \ (dest)->addr[1] = (src) == NULL ? 0 : htonl((src)->addr[1]); \ (dest)->addr[2] = (src) == NULL ? 0 : htonl((src)->addr[2]); \ (dest)->addr[3] = (src) == NULL ? 0 : htonl((src)->addr[3]);}while(0) /** * Determine if two IPv6 address are on the same network. * * @arg addr1 IPv6 address 1 * @arg addr2 IPv6 address 2 * @return !0 if the network identifiers of both address match */ #define ip6_addr_netcmp(addr1, addr2) (((addr1)->addr[0] == (addr2)->addr[0]) && \ ((addr1)->addr[1] == (addr2)->addr[1])) #define ip6_addr_cmp(addr1, addr2) (((addr1)->addr[0] == (addr2)->addr[0]) && \ ((addr1)->addr[1] == (addr2)->addr[1]) && \ ((addr1)->addr[2] == (addr2)->addr[2]) && \ ((addr1)->addr[3] == (addr2)->addr[3])) #define ip6_get_subnet_id(ip6addr) (htonl((ip6addr)->addr[2]) & 0x0000ffffUL) #define ip6_addr_isany(ip6addr) (((ip6addr) == NULL) || \ (((ip6addr)->addr[0] == 0) && \ ((ip6addr)->addr[1] == 0) && \ ((ip6addr)->addr[2] == 0) && \ ((ip6addr)->addr[3] == 0))) #define ip6_addr_isloopback(ip6addr) (((ip6addr)->addr[0] == 0UL) && \ ((ip6addr)->addr[1] == 0UL) && \ ((ip6addr)->addr[2] == 0UL) && \ ((ip6addr)->addr[3] == PP_HTONL(0x00000001UL))) #define ip6_addr_isglobal(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xe0000000UL)) == PP_HTONL(0x20000000UL)) #define ip6_addr_islinklocal(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xffc00000UL)) == PP_HTONL(0xfe800000UL)) #define ip6_addr_issitelocal(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xffc00000UL)) == PP_HTONL(0xfec00000UL)) #define ip6_addr_isuniquelocal(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xfe000000UL)) == PP_HTONL(0xfc000000UL)) #define ip6_addr_ismulticast(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xff000000UL)) == PP_HTONL(0xff000000UL)) #define ip6_addr_multicast_transient_flag(ip6addr) ((ip6addr)->addr[0] & PP_HTONL(0x00100000UL)) #define ip6_addr_multicast_prefix_flag(ip6addr) ((ip6addr)->addr[0] & PP_HTONL(0x00200000UL)) #define ip6_addr_multicast_rendezvous_flag(ip6addr) ((ip6addr)->addr[0] & PP_HTONL(0x00400000UL)) #define ip6_addr_multicast_scope(ip6addr) ((htonl((ip6addr)->addr[0]) >> 16) & 0xf) #define IP6_MULTICAST_SCOPE_RESERVED 0x0 #define IP6_MULTICAST_SCOPE_RESERVED0 0x0 #define IP6_MULTICAST_SCOPE_INTERFACE_LOCAL 0x1 #define IP6_MULTICAST_SCOPE_LINK_LOCAL 0x2 #define IP6_MULTICAST_SCOPE_RESERVED3 0x3 #define IP6_MULTICAST_SCOPE_ADMIN_LOCAL 0x4 #define IP6_MULTICAST_SCOPE_SITE_LOCAL 0x5 #define IP6_MULTICAST_SCOPE_ORGANIZATION_LOCAL 0x8 #define IP6_MULTICAST_SCOPE_GLOBAL 0xe #define IP6_MULTICAST_SCOPE_RESERVEDF 0xf #define ip6_addr_ismulticast_iflocal(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xffff0000UL)) == PP_HTONL(0xff010000UL)) #define ip6_addr_ismulticast_linklocal(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xffff0000UL)) == PP_HTONL(0xff020000UL)) #define ip6_addr_ismulticast_adminlocal(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xffff0000UL)) == PP_HTONL(0xff040000UL)) #define ip6_addr_ismulticast_sitelocal(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xffff0000UL)) == PP_HTONL(0xff050000UL)) #define ip6_addr_ismulticast_orglocal(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xffff0000UL)) == PP_HTONL(0xff080000UL)) #define ip6_addr_ismulticast_global(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xffff0000UL)) == PP_HTONL(0xff0e0000UL)) /* TODO define get/set for well-know multicast addresses, e.g. ff02::1 */ #define ip6_addr_isallnodes_iflocal(ip6addr) (((ip6addr)->addr[0] == PP_HTONL(0xff010000UL)) && \ ((ip6addr)->addr[1] == 0UL) && \ ((ip6addr)->addr[2] == 0UL) && \ ((ip6addr)->addr[3] == PP_HTONL(0x00000001UL))) #define ip6_addr_isallnodes_linklocal(ip6addr) (((ip6addr)->addr[0] == PP_HTONL(0xff020000UL)) && \ ((ip6addr)->addr[1] == 0UL) && \ ((ip6addr)->addr[2] == 0UL) && \ ((ip6addr)->addr[3] == PP_HTONL(0x00000001UL))) #define ip6_addr_set_allnodes_linklocal(ip6addr) do{(ip6addr)->addr[0] = PP_HTONL(0xff020000UL); \ (ip6addr)->addr[1] = 0; \ (ip6addr)->addr[2] = 0; \ (ip6addr)->addr[3] = PP_HTONL(0x00000001UL);}while(0) #define ip6_addr_isallrouters_linklocal(ip6addr) (((ip6addr)->addr[0] == PP_HTONL(0xff020000UL)) && \ ((ip6addr)->addr[1] == 0UL) && \ ((ip6addr)->addr[2] == 0UL) && \ ((ip6addr)->addr[3] == PP_HTONL(0x00000002UL))) #define ip6_addr_set_allrouters_linklocal(ip6addr) do{(ip6addr)->addr[0] = PP_HTONL(0xff020000UL); \ (ip6addr)->addr[1] = 0; \ (ip6addr)->addr[2] = 0; \ (ip6addr)->addr[3] = PP_HTONL(0x00000002UL);}while(0) #define ip6_addr_issolicitednode(ip6addr) ( ((ip6addr)->addr[0] == PP_HTONL(0xff020000UL)) && \ ((ip6addr)->addr[2] == PP_HTONL(0x00000001UL)) && \ (((ip6addr)->addr[3] & PP_HTONL(0xff000000UL)) == PP_HTONL(0xff000000UL)) ) #define ip6_addr_set_solicitednode(ip6addr, if_id) do{(ip6addr)->addr[0] = PP_HTONL(0xff020000UL); \ (ip6addr)->addr[1] = 0; \ (ip6addr)->addr[2] = PP_HTONL(0x00000001UL); \ (ip6addr)->addr[3] = (PP_HTONL(0xff000000UL) | (if_id));}while(0) #define ip6_addr_cmp_solicitednode(ip6addr, sn_addr) (((ip6addr)->addr[0] == PP_HTONL(0xff020000UL)) && \ ((ip6addr)->addr[1] == 0) && \ ((ip6addr)->addr[2] == PP_HTONL(0x00000001UL)) && \ ((ip6addr)->addr[3] == (PP_HTONL(0xff000000UL) | (sn_addr)->addr[3]))) /* IPv6 address states. */ #define IP6_ADDR_INVALID 0x00 #define IP6_ADDR_TENTATIVE 0x08 #define IP6_ADDR_TENTATIVE_1 0x09 /* 1 probe sent */ #define IP6_ADDR_TENTATIVE_2 0x0a /* 2 probes sent */ #define IP6_ADDR_TENTATIVE_3 0x0b /* 3 probes sent */ #define IP6_ADDR_TENTATIVE_4 0x0c /* 4 probes sent */ #define IP6_ADDR_TENTATIVE_5 0x0d /* 5 probes sent */ #define IP6_ADDR_TENTATIVE_6 0x0e /* 6 probes sent */ #define IP6_ADDR_TENTATIVE_7 0x0f /* 7 probes sent */ #define IP6_ADDR_VALID 0x10 #define IP6_ADDR_PREFERRED 0x30 #define IP6_ADDR_DEPRECATED 0x50 #define ip6_addr_isinvalid(addr_state) (addr_state == IP6_ADDR_INVALID) #define ip6_addr_istentative(addr_state) (addr_state & IP6_ADDR_TENTATIVE) #define ip6_addr_isvalid(addr_state) (addr_state & IP6_ADDR_VALID) /* Include valid, preferred, and deprecated. */ #define ip6_addr_ispreferred(addr_state) (addr_state == IP6_ADDR_PREFERRED) #define ip6_addr_isdeprecated(addr_state) (addr_state == IP6_ADDR_DEPRECATED) #define ip6_addr_debug_print(debug, ipaddr) \ LWIP_DEBUGF(debug, ("%" X16_F ":%" X16_F ":%" X16_F ":%" X16_F ":%" X16_F ":%" X16_F ":%" X16_F ":%" X16_F, \ ipaddr != NULL ? IP6_ADDR_BLOCK1(ipaddr) : 0, \ ipaddr != NULL ? IP6_ADDR_BLOCK2(ipaddr) : 0, \ ipaddr != NULL ? IP6_ADDR_BLOCK3(ipaddr) : 0, \ ipaddr != NULL ? IP6_ADDR_BLOCK4(ipaddr) : 0, \ ipaddr != NULL ? IP6_ADDR_BLOCK5(ipaddr) : 0, \ ipaddr != NULL ? IP6_ADDR_BLOCK6(ipaddr) : 0, \ ipaddr != NULL ? IP6_ADDR_BLOCK7(ipaddr) : 0, \ ipaddr != NULL ? IP6_ADDR_BLOCK8(ipaddr) : 0)) #define IP6ADDR_STRLEN_MAX 46 int ip6addr_aton(const char *cp, ip6_addr_t *addr); /** returns ptr to static buffer; not reentrant! */ char *ip6addr_ntoa(const ip6_addr_t *addr); char *ip6addr_ntoa_r(const ip6_addr_t *addr, char *buf, int buflen); #ifdef __cplusplus } #endif #endif /* LWIP_IPV6 */ #endif /* LWIP_HDR_IP6_ADDR_H */ ocproxy-1.60/lwip/src/include/ipv6/lwip/ip6_frag.h000066400000000000000000000063221303453231400220360ustar00rootroot00000000000000/** * @file * * IPv6 fragmentation and reassembly. */ /* * Copyright (c) 2010 Inico Technologies Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Ivan Delamer * * * Please coordinate changes and requests with Ivan Delamer * */ #ifndef LWIP_HDR_IP6_FRAG_H #define LWIP_HDR_IP6_FRAG_H #include "lwip/opt.h" #include "lwip/pbuf.h" #include "lwip/ip6_addr.h" #include "lwip/netif.h" #ifdef __cplusplus extern "C" { #endif #if LWIP_IPV6 && LWIP_IPV6_REASS /* don't build if not configured for use in lwipopts.h */ /* The IPv6 reassembly timer interval in milliseconds. */ #define IP6_REASS_TMR_INTERVAL 1000 /* IPv6 reassembly helper struct. * This is exported because memp needs to know the size. */ struct ip6_reassdata { struct ip6_reassdata *next; struct pbuf *p; struct ip6_hdr * iphdr; u32_t identification; u16_t datagram_len; u8_t nexth; u8_t timer; }; #define ip6_reass_init() /* Compatibility define */ void ip6_reass_tmr(void); struct pbuf * ip6_reass(struct pbuf *p); #endif /* LWIP_IPV6 && LWIP_IPV6_REASS */ #if LWIP_IPV6 && LWIP_IPV6_FRAG /* don't build if not configured for use in lwipopts.h */ /** A custom pbuf that holds a reference to another pbuf, which is freed * when this custom pbuf is freed. This is used to create a custom PBUF_REF * that points into the original pbuf. */ #ifndef LWIP_PBUF_CUSTOM_REF_DEFINED #define LWIP_PBUF_CUSTOM_REF_DEFINED struct pbuf_custom_ref { /** 'base class' */ struct pbuf_custom pc; /** pointer to the original pbuf that is referenced */ struct pbuf *original; }; #endif /* LWIP_PBUF_CUSTOM_REF_DEFINED */ err_t ip6_frag(struct pbuf *p, struct netif *netif, ip6_addr_t *dest); #endif /* LWIP_IPV6 && LWIP_IPV6_FRAG */ #ifdef __cplusplus } #endif #endif /* LWIP_HDR_IP6_FRAG_H */ ocproxy-1.60/lwip/src/include/ipv6/lwip/mld6.h000066400000000000000000000074001303453231400212010ustar00rootroot00000000000000/** * @file * * Multicast listener discovery for IPv6. Aims to be compliant with RFC 2710. * No support for MLDv2. */ /* * Copyright (c) 2010 Inico Technologies Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Ivan Delamer * * * Please coordinate changes and requests with Ivan Delamer * */ #ifndef LWIP_HDR_MLD6_H #define LWIP_HDR_MLD6_H #include "lwip/opt.h" #if LWIP_IPV6_MLD && LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */ #include "lwip/pbuf.h" #include "lwip/netif.h" #ifdef __cplusplus extern "C" { #endif struct mld_group { /** next link */ struct mld_group *next; /** interface on which the group is active */ struct netif *netif; /** multicast address */ ip6_addr_t group_address; /** signifies we were the last person to report */ u8_t last_reporter_flag; /** current state of the group */ u8_t group_state; /** timer for reporting */ u16_t timer; /** counter of simultaneous uses */ u8_t use; }; /** Multicast listener report/query/done message header. */ #ifdef PACK_STRUCT_USE_INCLUDES # include "arch/bpstruct.h" #endif PACK_STRUCT_BEGIN struct mld_header { PACK_STRUCT_FIELD(u8_t type); PACK_STRUCT_FIELD(u8_t code); PACK_STRUCT_FIELD(u16_t chksum); PACK_STRUCT_FIELD(u16_t max_resp_delay); PACK_STRUCT_FIELD(u16_t reserved); PACK_STRUCT_FIELD(ip6_addr_p_t multicast_address); /* Options follow. */ } PACK_STRUCT_STRUCT; PACK_STRUCT_END #ifdef PACK_STRUCT_USE_INCLUDES # include "arch/epstruct.h" #endif #define MLD6_TMR_INTERVAL 100 /* Milliseconds */ /* MAC Filter Actions, these are passed to a netif's * mld_mac_filter callback function. */ #define MLD6_DEL_MAC_FILTER 0 #define MLD6_ADD_MAC_FILTER 1 #define mld6_init() /* TODO should we init tables? */ err_t mld6_stop(struct netif *netif); void mld6_report_groups(struct netif *netif); void mld6_tmr(void); struct mld_group *mld6_lookfor_group(struct netif *ifp, ip6_addr_t *addr); void mld6_input(struct pbuf *p, struct netif *inp); err_t mld6_joingroup(ip6_addr_t *srcaddr, ip6_addr_t *groupaddr); err_t mld6_leavegroup(ip6_addr_t *srcaddr, ip6_addr_t *groupaddr); #ifdef __cplusplus } #endif #endif /* LWIP_IPV6_MLD && LWIP_IPV6 */ #endif /* LWIP_HDR_MLD6_H */ ocproxy-1.60/lwip/src/include/ipv6/lwip/nd6.h000066400000000000000000000242571303453231400210370ustar00rootroot00000000000000/** * @file * * Neighbor discovery and stateless address autoconfiguration for IPv6. * Aims to be compliant with RFC 4861 (Neighbor discovery) and RFC 4862 * (Address autoconfiguration). */ /* * Copyright (c) 2010 Inico Technologies Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Ivan Delamer * * * Please coordinate changes and requests with Ivan Delamer * */ #ifndef LWIP_HDR_ND6_H #define LWIP_HDR_ND6_H #include "lwip/opt.h" #if LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */ #include "lwip/pbuf.h" #include "lwip/ip6.h" #include "lwip/ip6_addr.h" #include "lwip/netif.h" #ifdef __cplusplus extern "C" { #endif /* Struct for tables. */ struct nd6_neighbor_cache_entry { ip6_addr_t next_hop_address; struct netif * netif; u8_t lladdr[NETIF_MAX_HWADDR_LEN]; /*u32_t pmtu;*/ #if LWIP_ND6_QUEUEING /** Pointer to queue of pending outgoing packets on this entry. */ struct nd6_q_entry *q; #else /* LWIP_ND6_QUEUEING */ /** Pointer to a single pending outgoing packet on this entry. */ struct pbuf *q; #endif /* LWIP_ND6_QUEUEING */ u8_t state; u8_t isrouter; union { u32_t reachable_time; u32_t delay_time; u32_t probes_sent; u32_t stale_time; } counter; }; struct nd6_destination_cache_entry { ip6_addr_t destination_addr; ip6_addr_t next_hop_addr; u32_t pmtu; u32_t age; }; struct nd6_prefix_list_entry { ip6_addr_t prefix; struct netif * netif; u32_t invalidation_timer; #if LWIP_IPV6_AUTOCONFIG u8_t flags; #define ND6_PREFIX_AUTOCONFIG_AUTONOMOUS 0x01 #define ND6_PREFIX_AUTOCONFIG_ADDRESS_GENERATED 0x02 #define ND6_PREFIX_AUTOCONFIG_ADDRESS_DUPLICATE 0x04 #endif /* LWIP_IPV6_AUTOCONFIG */ }; struct nd6_router_list_entry { struct nd6_neighbor_cache_entry * neighbor_entry; u32_t invalidation_timer; u8_t flags; }; enum nd6_neighbor_cache_entry_state { ND6_NO_ENTRY = 0, ND6_INCOMPLETE, ND6_REACHABLE, ND6_STALE, ND6_DELAY, ND6_PROBE }; #if LWIP_ND6_QUEUEING /** struct for queueing outgoing packets for unknown address * defined here to be accessed by memp.h */ struct nd6_q_entry { struct nd6_q_entry *next; struct pbuf *p; }; #endif /* LWIP_ND6_QUEUEING */ /** Neighbor solicitation message header. */ #ifdef PACK_STRUCT_USE_INCLUDES # include "arch/bpstruct.h" #endif PACK_STRUCT_BEGIN struct ns_header { PACK_STRUCT_FIELD(u8_t type); PACK_STRUCT_FIELD(u8_t code); PACK_STRUCT_FIELD(u16_t chksum); PACK_STRUCT_FIELD(u32_t reserved); PACK_STRUCT_FIELD(ip6_addr_p_t target_address); /* Options follow. */ } PACK_STRUCT_STRUCT; PACK_STRUCT_END #ifdef PACK_STRUCT_USE_INCLUDES # include "arch/epstruct.h" #endif /** Neighbor advertisement message header. */ #ifdef PACK_STRUCT_USE_INCLUDES # include "arch/bpstruct.h" #endif PACK_STRUCT_BEGIN struct na_header { PACK_STRUCT_FIELD(u8_t type); PACK_STRUCT_FIELD(u8_t code); PACK_STRUCT_FIELD(u16_t chksum); PACK_STRUCT_FIELD(u8_t flags); PACK_STRUCT_FIELD(u8_t reserved[3]); PACK_STRUCT_FIELD(ip6_addr_p_t target_address); /* Options follow. */ } PACK_STRUCT_STRUCT; PACK_STRUCT_END #ifdef PACK_STRUCT_USE_INCLUDES # include "arch/epstruct.h" #endif #define ND6_FLAG_ROUTER (0x80) #define ND6_FLAG_SOLICITED (0x40) #define ND6_FLAG_OVERRIDE (0x20) /** Router solicitation message header. */ #ifdef PACK_STRUCT_USE_INCLUDES # include "arch/bpstruct.h" #endif PACK_STRUCT_BEGIN struct rs_header { PACK_STRUCT_FIELD(u8_t type); PACK_STRUCT_FIELD(u8_t code); PACK_STRUCT_FIELD(u16_t chksum); PACK_STRUCT_FIELD(u32_t reserved); /* Options follow. */ } PACK_STRUCT_STRUCT; PACK_STRUCT_END #ifdef PACK_STRUCT_USE_INCLUDES # include "arch/epstruct.h" #endif /** Router advertisement message header. */ #define ND6_RA_FLAG_MANAGED_ADDR_CONFIG (0x80) #define ND6_RA_FLAG_OTHER_STATEFUL_CONFIG (0x40) #define ND6_RA_FLAG_HOME_AGENT (0x20) #define ND6_RA_PREFERENCE_MASK (0x18) #define ND6_RA_PREFERENCE_HIGH (0x08) #define ND6_RA_PREFERENCE_MEDIUM (0x00) #define ND6_RA_PREFERENCE_LOW (0x18) #define ND6_RA_PREFERENCE_DISABLED (0x10) #ifdef PACK_STRUCT_USE_INCLUDES # include "arch/bpstruct.h" #endif PACK_STRUCT_BEGIN struct ra_header { PACK_STRUCT_FIELD(u8_t type); PACK_STRUCT_FIELD(u8_t code); PACK_STRUCT_FIELD(u16_t chksum); PACK_STRUCT_FIELD(u8_t current_hop_limit); PACK_STRUCT_FIELD(u8_t flags); PACK_STRUCT_FIELD(u16_t router_lifetime); PACK_STRUCT_FIELD(u32_t reachable_time); PACK_STRUCT_FIELD(u32_t retrans_timer); /* Options follow. */ } PACK_STRUCT_STRUCT; PACK_STRUCT_END #ifdef PACK_STRUCT_USE_INCLUDES # include "arch/epstruct.h" #endif /** Redirect message header. */ #ifdef PACK_STRUCT_USE_INCLUDES # include "arch/bpstruct.h" #endif PACK_STRUCT_BEGIN struct redirect_header { PACK_STRUCT_FIELD(u8_t type); PACK_STRUCT_FIELD(u8_t code); PACK_STRUCT_FIELD(u16_t chksum); PACK_STRUCT_FIELD(u32_t reserved); PACK_STRUCT_FIELD(ip6_addr_p_t target_address); PACK_STRUCT_FIELD(ip6_addr_p_t destination_address); /* Options follow. */ } PACK_STRUCT_STRUCT; PACK_STRUCT_END #ifdef PACK_STRUCT_USE_INCLUDES # include "arch/epstruct.h" #endif /** Link-layer address option. */ #define ND6_OPTION_TYPE_SOURCE_LLADDR (0x01) #define ND6_OPTION_TYPE_TARGET_LLADDR (0x02) #ifdef PACK_STRUCT_USE_INCLUDES # include "arch/bpstruct.h" #endif PACK_STRUCT_BEGIN struct lladdr_option { PACK_STRUCT_FIELD(u8_t type); PACK_STRUCT_FIELD(u8_t length); PACK_STRUCT_FIELD(u8_t addr[NETIF_MAX_HWADDR_LEN]); } PACK_STRUCT_STRUCT; PACK_STRUCT_END #ifdef PACK_STRUCT_USE_INCLUDES # include "arch/epstruct.h" #endif /** Prefix information option. */ #define ND6_OPTION_TYPE_PREFIX_INFO (0x03) #define ND6_PREFIX_FLAG_ON_LINK (0x80) #define ND6_PREFIX_FLAG_AUTONOMOUS (0x40) #define ND6_PREFIX_FLAG_ROUTER_ADDRESS (0x20) #define ND6_PREFIX_FLAG_SITE_PREFIX (0x10) #ifdef PACK_STRUCT_USE_INCLUDES # include "arch/bpstruct.h" #endif PACK_STRUCT_BEGIN struct prefix_option { PACK_STRUCT_FIELD(u8_t type); PACK_STRUCT_FIELD(u8_t length); PACK_STRUCT_FIELD(u8_t prefix_length); PACK_STRUCT_FIELD(u8_t flags); PACK_STRUCT_FIELD(u32_t valid_lifetime); PACK_STRUCT_FIELD(u32_t preferred_lifetime); PACK_STRUCT_FIELD(u8_t reserved2[3]); PACK_STRUCT_FIELD(u8_t site_prefix_length); PACK_STRUCT_FIELD(ip6_addr_p_t prefix); } PACK_STRUCT_STRUCT; PACK_STRUCT_END #ifdef PACK_STRUCT_USE_INCLUDES # include "arch/epstruct.h" #endif /** Redirected header option. */ #define ND6_OPTION_TYPE_REDIR_HDR (0x04) #ifdef PACK_STRUCT_USE_INCLUDES # include "arch/bpstruct.h" #endif PACK_STRUCT_BEGIN struct redirected_header_option { PACK_STRUCT_FIELD(u8_t type); PACK_STRUCT_FIELD(u8_t length); PACK_STRUCT_FIELD(u8_t reserved[6]); /* Portion of redirected packet follows. */ /* PACK_STRUCT_FIELD(u8_t redirected[8]); */ } PACK_STRUCT_STRUCT; PACK_STRUCT_END #ifdef PACK_STRUCT_USE_INCLUDES # include "arch/epstruct.h" #endif /** MTU option. */ #define ND6_OPTION_TYPE_MTU (0x05) #ifdef PACK_STRUCT_USE_INCLUDES # include "arch/bpstruct.h" #endif PACK_STRUCT_BEGIN struct mtu_option { PACK_STRUCT_FIELD(u8_t type); PACK_STRUCT_FIELD(u8_t length); PACK_STRUCT_FIELD(u16_t reserved); PACK_STRUCT_FIELD(u32_t mtu); } PACK_STRUCT_STRUCT; PACK_STRUCT_END #ifdef PACK_STRUCT_USE_INCLUDES # include "arch/epstruct.h" #endif /** Route information option. */ #define ND6_OPTION_TYPE_ROUTE_INFO (24) #ifdef PACK_STRUCT_USE_INCLUDES # include "arch/bpstruct.h" #endif PACK_STRUCT_BEGIN struct route_option { PACK_STRUCT_FIELD(u8_t type); PACK_STRUCT_FIELD(u8_t length); PACK_STRUCT_FIELD(u8_t prefix_length); PACK_STRUCT_FIELD(u8_t preference); PACK_STRUCT_FIELD(u32_t route_lifetime); PACK_STRUCT_FIELD(ip6_addr_p_t prefix); } PACK_STRUCT_STRUCT; PACK_STRUCT_END #ifdef PACK_STRUCT_USE_INCLUDES # include "arch/epstruct.h" #endif /** 1 second period */ #define ND6_TMR_INTERVAL 1000 /* Router tables. */ /* TODO make these static? and entries accessible through API? */ extern struct nd6_neighbor_cache_entry neighbor_cache[]; extern struct nd6_destination_cache_entry destination_cache[]; extern struct nd6_prefix_list_entry prefix_list[]; extern struct nd6_router_list_entry default_router_list[]; /* Default values, can be updated by a RA message. */ extern u32_t reachable_time; extern u32_t retrans_timer; #define nd6_init() /* TODO should we init tables? */ void nd6_tmr(void); void nd6_input(struct pbuf *p, struct netif *inp); s8_t nd6_get_next_hop_entry(ip6_addr_t * ip6addr, struct netif * netif); s8_t nd6_select_router(ip6_addr_t * ip6addr, struct netif * netif); u16_t nd6_get_destination_mtu(ip6_addr_t * ip6addr, struct netif * netif); err_t nd6_queue_packet(s8_t neighbor_index, struct pbuf * p); #if LWIP_ND6_TCP_REACHABILITY_HINTS void nd6_reachability_hint(ip6_addr_t * ip6addr); #endif /* LWIP_ND6_TCP_REACHABILITY_HINTS */ #ifdef __cplusplus } #endif #endif /* LWIP_IPV6 */ #endif /* LWIP_HDR_ND6_H */ ocproxy-1.60/lwip/src/include/lwip/000077500000000000000000000000001303453231400173015ustar00rootroot00000000000000ocproxy-1.60/lwip/src/include/lwip/api.h000066400000000000000000000323271303453231400202320ustar00rootroot00000000000000/* * Copyright (c) 2001-2004 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #ifndef LWIP_HDR_API_H #define LWIP_HDR_API_H #include "lwip/opt.h" #if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */ #include /* for size_t */ #include "lwip/netbuf.h" #include "lwip/sys.h" #include "lwip/ip_addr.h" #include "lwip/err.h" #ifdef __cplusplus extern "C" { #endif /* Throughout this file, IP addresses and port numbers are expected to be in * the same byte order as in the corresponding pcb. */ /* Flags for netconn_write (u8_t) */ #define NETCONN_NOFLAG 0x00 #define NETCONN_NOCOPY 0x00 /* Only for source code compatibility */ #define NETCONN_COPY 0x01 #define NETCONN_MORE 0x02 #define NETCONN_DONTBLOCK 0x04 /* Flags for struct netconn.flags (u8_t) */ /** TCP: when data passed to netconn_write doesn't fit into the send buffer, this temporarily stores whether to wake up the original application task if data couldn't be sent in the first try. */ #define NETCONN_FLAG_WRITE_DELAYED 0x01 /** Should this netconn avoid blocking? */ #define NETCONN_FLAG_NON_BLOCKING 0x02 /** Was the last connect action a non-blocking one? */ #define NETCONN_FLAG_IN_NONBLOCKING_CONNECT 0x04 /** If this is set, a TCP netconn must call netconn_recved() to update the TCP receive window (done automatically if not set). */ #define NETCONN_FLAG_NO_AUTO_RECVED 0x08 /** If a nonblocking write has been rejected before, poll_tcp needs to check if the netconn is writable again */ #define NETCONN_FLAG_CHECK_WRITESPACE 0x10 #if LWIP_IPV6 /** If this flag is set then only IPv6 communication is allowed on the netconn. As per RFC#3493 this features defaults to OFF allowing dual-stack usage by default. */ #define NETCONN_FLAG_IPV6_V6ONLY 0x20 #endif /* LWIP_IPV6 */ /* Helpers to process several netconn_types by the same code */ #define NETCONNTYPE_GROUP(t) ((t)&0xF0) #define NETCONNTYPE_DATAGRAM(t) ((t)&0xE0) #if LWIP_IPV6 #define NETCONN_TYPE_IPV6 0x08 #define NETCONNTYPE_ISIPV6(t) ((t)&0x08) #define NETCONNTYPE_ISUDPLITE(t) (((t)&0xF7) == NETCONN_UDPLITE) #define NETCONNTYPE_ISUDPNOCHKSUM(t) (((t)&0xF7) == NETCONN_UDPNOCHKSUM) #else /* LWIP_IPV6 */ #define NETCONNTYPE_ISUDPLITE(t) ((t) == NETCONN_UDPLITE) #define NETCONNTYPE_ISUDPNOCHKSUM(t) ((t) == NETCONN_UDPNOCHKSUM) #endif /* LWIP_IPV6 */ /** Protocol family and type of the netconn */ enum netconn_type { NETCONN_INVALID = 0, /* NETCONN_TCP Group */ NETCONN_TCP = 0x10, #if LWIP_IPV6 NETCONN_TCP_IPV6 = NETCONN_TCP | NETCONN_TYPE_IPV6 /* 0x18 */, #endif /* LWIP_IPV6 */ /* NETCONN_UDP Group */ NETCONN_UDP = 0x20, NETCONN_UDPLITE = 0x21, NETCONN_UDPNOCHKSUM = 0x22, #if LWIP_IPV6 NETCONN_UDP_IPV6 = NETCONN_UDP | NETCONN_TYPE_IPV6 /* 0x28 */, NETCONN_UDPLITE_IPV6 = NETCONN_UDPLITE | NETCONN_TYPE_IPV6 /* 0x29 */, NETCONN_UDPNOCHKSUM_IPV6 = NETCONN_UDPNOCHKSUM | NETCONN_TYPE_IPV6 /* 0x2a */, #endif /* LWIP_IPV6 */ /* NETCONN_RAW Group */ NETCONN_RAW = 0x40 #if LWIP_IPV6 , NETCONN_RAW_IPV6 = NETCONN_RAW | NETCONN_TYPE_IPV6 /* 0x48 */ #endif /* LWIP_IPV6 */ }; /** Current state of the netconn. Non-TCP netconns are always * in state NETCONN_NONE! */ enum netconn_state { NETCONN_NONE, NETCONN_WRITE, NETCONN_LISTEN, NETCONN_CONNECT, NETCONN_CLOSE }; /** Use to inform the callback function about changes */ enum netconn_evt { NETCONN_EVT_RCVPLUS, NETCONN_EVT_RCVMINUS, NETCONN_EVT_SENDPLUS, NETCONN_EVT_SENDMINUS, NETCONN_EVT_ERROR }; #if LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) /** Used for netconn_join_leave_group() */ enum netconn_igmp { NETCONN_JOIN, NETCONN_LEAVE }; #endif /* LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) */ /* forward-declare some structs to avoid to include their headers */ struct ip_pcb; struct tcp_pcb; struct udp_pcb; struct raw_pcb; struct netconn; struct api_msg_msg; /** A callback prototype to inform about events for a netconn */ typedef void (* netconn_callback)(struct netconn *, enum netconn_evt, u16_t len); /** A netconn descriptor */ struct netconn { /** type of the netconn (TCP, UDP or RAW) */ enum netconn_type type; /** current state of the netconn */ enum netconn_state state; /** the lwIP internal protocol control block */ union { struct ip_pcb *ip; struct tcp_pcb *tcp; struct udp_pcb *udp; struct raw_pcb *raw; } pcb; /** the last error this netconn had */ err_t last_err; /** sem that is used to synchroneously execute functions in the core context */ sys_sem_t op_completed; /** mbox where received packets are stored until they are fetched by the netconn application thread (can grow quite big) */ sys_mbox_t recvmbox; #if LWIP_TCP /** mbox where new connections are stored until processed by the application thread */ sys_mbox_t acceptmbox; #endif /* LWIP_TCP */ /** only used for socket layer */ #if LWIP_SOCKET int socket; #endif /* LWIP_SOCKET */ #if LWIP_SO_SNDTIMEO /** timeout to wait for sending data (which means enqueueing data for sending in internal buffers) */ s32_t send_timeout; #endif /* LWIP_SO_RCVTIMEO */ #if LWIP_SO_RCVTIMEO /** timeout to wait for new data to be received (or connections to arrive for listening netconns) */ int recv_timeout; #endif /* LWIP_SO_RCVTIMEO */ #if LWIP_SO_RCVBUF /** maximum amount of bytes queued in recvmbox not used for TCP: adjust TCP_WND instead! */ int recv_bufsize; /** number of bytes currently in recvmbox to be received, tested against recv_bufsize to limit bytes on recvmbox for UDP and RAW, used for FIONREAD */ int recv_avail; #endif /* LWIP_SO_RCVBUF */ /** flags holding more netconn-internal state, see NETCONN_FLAG_* defines */ u8_t flags; #if LWIP_TCP /** TCP: when data passed to netconn_write doesn't fit into the send buffer, this temporarily stores how much is already sent. */ size_t write_offset; /** TCP: when data passed to netconn_write doesn't fit into the send buffer, this temporarily stores the message. Also used during connect and close. */ struct api_msg_msg *current_msg; #endif /* LWIP_TCP */ /** A callback function that is informed about events for this netconn */ netconn_callback callback; }; /** Register an Network connection event */ #define API_EVENT(c,e,l) if (c->callback) { \ (*c->callback)(c, e, l); \ } /** Set conn->last_err to err but don't overwrite fatal errors */ #define NETCONN_SET_SAFE_ERR(conn, err) do { \ SYS_ARCH_DECL_PROTECT(lev); \ SYS_ARCH_PROTECT(lev); \ if (!ERR_IS_FATAL((conn)->last_err)) { \ (conn)->last_err = err; \ } \ SYS_ARCH_UNPROTECT(lev); \ } while(0); /* Network connection functions: */ #define netconn_new(t) netconn_new_with_proto_and_callback(t, 0, NULL) #define netconn_new_with_callback(t, c) netconn_new_with_proto_and_callback(t, 0, c) struct netconn *netconn_new_with_proto_and_callback(enum netconn_type t, u8_t proto, netconn_callback callback); err_t netconn_delete(struct netconn *conn); /** Get the type of a netconn (as enum netconn_type). */ #define netconn_type(conn) (conn->type) err_t netconn_getaddr(struct netconn *conn, ip_addr_t *addr, u16_t *port, u8_t local); #define netconn_peer(c,i,p) netconn_getaddr(c,i,p,0) #define netconn_addr(c,i,p) netconn_getaddr(c,i,p,1) err_t netconn_bind(struct netconn *conn, ip_addr_t *addr, u16_t port); err_t netconn_connect(struct netconn *conn, ip_addr_t *addr, u16_t port); err_t netconn_disconnect (struct netconn *conn); err_t netconn_listen_with_backlog(struct netconn *conn, u8_t backlog); #define netconn_listen(conn) netconn_listen_with_backlog(conn, TCP_DEFAULT_LISTEN_BACKLOG) err_t netconn_accept(struct netconn *conn, struct netconn **new_conn); err_t netconn_recv(struct netconn *conn, struct netbuf **new_buf); err_t netconn_recv_tcp_pbuf(struct netconn *conn, struct pbuf **new_buf); void netconn_recved(struct netconn *conn, u32_t length); err_t netconn_sendto(struct netconn *conn, struct netbuf *buf, ip_addr_t *addr, u16_t port); err_t netconn_send(struct netconn *conn, struct netbuf *buf); err_t netconn_write_partly(struct netconn *conn, const void *dataptr, size_t size, u8_t apiflags, size_t *bytes_written); #define netconn_write(conn, dataptr, size, apiflags) \ netconn_write_partly(conn, dataptr, size, apiflags, NULL) err_t netconn_close(struct netconn *conn); err_t netconn_shutdown(struct netconn *conn, u8_t shut_rx, u8_t shut_tx); #if LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) err_t netconn_join_leave_group(struct netconn *conn, ip_addr_t *multiaddr, ip_addr_t *netif_addr, enum netconn_igmp join_or_leave); #endif /* LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) */ #if LWIP_DNS err_t netconn_gethostbyname(const char *name, ip_addr_t *addr); #endif /* LWIP_DNS */ #if LWIP_IPV6 #define netconn_bind_ip6(conn, ip6addr, port) (NETCONNTYPE_ISIPV6((conn)->type) ? \ netconn_bind(conn, ip6_2_ip(ip6addr), port) : ERR_VAL) #define netconn_connect_ip6(conn, ip6addr, port) (NETCONNTYPE_ISIPV6((conn)->type) ? \ netconn_connect(conn, ip6_2_ip(ip6addr), port) : ERR_VAL) #define netconn_sendto_ip6(conn, buf, ip6addr, port) (NETCONNTYPE_ISIPV6((conn)->type) ? \ netconn_sendto(conn, buf, ip6_2_ip(ip6addr), port) : ERR_VAL) #if LWIP_IPV6_MLD #define netconn_join_leave_group_ip6(conn, multiaddr, srcaddr, join_or_leave) (NETCONNTYPE_ISIPV6((conn)->type) ? \ netconn_join_leave_group(conn, ip6_2_ip(multiaddr), ip6_2_ip(srcaddr), join_or_leave) :\ ERR_VAL) #endif /* LWIP_IPV6_MLD*/ #endif /* LWIP_IPV6 */ #define netconn_err(conn) ((conn)->last_err) #define netconn_recv_bufsize(conn) ((conn)->recv_bufsize) /** Set the blocking status of netconn calls (@todo: write/send is missing) */ #define netconn_set_nonblocking(conn, val) do { if(val) { \ (conn)->flags |= NETCONN_FLAG_NON_BLOCKING; \ } else { \ (conn)->flags &= ~ NETCONN_FLAG_NON_BLOCKING; }} while(0) /** Get the blocking status of netconn calls (@todo: write/send is missing) */ #define netconn_is_nonblocking(conn) (((conn)->flags & NETCONN_FLAG_NON_BLOCKING) != 0) /** TCP: Set the no-auto-recved status of netconn calls (see NETCONN_FLAG_NO_AUTO_RECVED) */ #define netconn_set_noautorecved(conn, val) do { if(val) { \ (conn)->flags |= NETCONN_FLAG_NO_AUTO_RECVED; \ } else { \ (conn)->flags &= ~ NETCONN_FLAG_NO_AUTO_RECVED; }} while(0) /** TCP: Get the no-auto-recved status of netconn calls (see NETCONN_FLAG_NO_AUTO_RECVED) */ #define netconn_get_noautorecved(conn) (((conn)->flags & NETCONN_FLAG_NO_AUTO_RECVED) != 0) #if LWIP_SO_SNDTIMEO /** Set the send timeout in milliseconds */ #define netconn_set_sendtimeout(conn, timeout) ((conn)->send_timeout = (timeout)) /** Get the send timeout in milliseconds */ #define netconn_get_sendtimeout(conn) ((conn)->send_timeout) #endif /* LWIP_SO_SNDTIMEO */ #if LWIP_SO_RCVTIMEO /** Set the receive timeout in milliseconds */ #define netconn_set_recvtimeout(conn, timeout) ((conn)->recv_timeout = (timeout)) /** Get the receive timeout in milliseconds */ #define netconn_get_recvtimeout(conn) ((conn)->recv_timeout) #endif /* LWIP_SO_RCVTIMEO */ #if LWIP_SO_RCVBUF /** Set the receive buffer in bytes */ #define netconn_set_recvbufsize(conn, recvbufsize) ((conn)->recv_bufsize = (recvbufsize)) /** Get the receive buffer in bytes */ #define netconn_get_recvbufsize(conn) ((conn)->recv_bufsize) #endif /* LWIP_SO_RCVBUF*/ #ifdef __cplusplus } #endif #endif /* LWIP_NETCONN */ #endif /* LWIP_HDR_API_H */ ocproxy-1.60/lwip/src/include/lwip/api_msg.h000066400000000000000000000151121303453231400210710ustar00rootroot00000000000000/* * Copyright (c) 2001-2004 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #ifndef LWIP_HDR_API_MSG_H #define LWIP_HDR_API_MSG_H #include "lwip/opt.h" #if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */ #include /* for size_t */ #include "lwip/ip_addr.h" #include "lwip/err.h" #include "lwip/sys.h" #include "lwip/igmp.h" #include "lwip/api.h" #ifdef __cplusplus extern "C" { #endif #if LWIP_MPU_COMPATIBLE #define API_MSG_M_DEF(m) m #else /* LWIP_MPU_COMPATIBLE */ #define API_MSG_M_DEF(m) *m #endif /* LWIP_MPU_COMPATIBLE */ /* For the netconn API, these values are use as a bitmask! */ #define NETCONN_SHUT_RD 1 #define NETCONN_SHUT_WR 2 #define NETCONN_SHUT_RDWR (NETCONN_SHUT_RD | NETCONN_SHUT_WR) /* IP addresses and port numbers are expected to be in * the same byte order as in the corresponding pcb. */ /** This struct includes everything that is necessary to execute a function for a netconn in another thread context (mainly used to process netconns in the tcpip_thread context to be thread safe). */ struct api_msg_msg { /** The netconn which to process - always needed: it includes the semaphore which is used to block the application thread until the function finished. */ struct netconn *conn; /** The return value of the function executed in tcpip_thread. */ err_t err; /** Depending on the executed function, one of these union members is used */ union { /** used for lwip_netconn_do_send */ struct netbuf *b; /** used for lwip_netconn_do_newconn */ struct { u8_t proto; } n; /** used for lwip_netconn_do_bind and lwip_netconn_do_connect */ struct { ip_addr_t API_MSG_M_DEF(ipaddr); u16_t port; } bc; /** used for lwip_netconn_do_getaddr */ struct { ipX_addr_t API_MSG_M_DEF(ipaddr); u16_t API_MSG_M_DEF(port); u8_t local; } ad; /** used for lwip_netconn_do_write */ struct { const void *dataptr; size_t len; u8_t apiflags; #if LWIP_SO_SNDTIMEO u32_t time_started; #endif /* LWIP_SO_SNDTIMEO */ } w; /** used for lwip_netconn_do_recv */ struct { u32_t len; } r; /** used for lwip_netconn_do_close (/shutdown) */ struct { u8_t shut; } sd; #if LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) /** used for lwip_netconn_do_join_leave_group */ struct { ipX_addr_t API_MSG_M_DEF(multiaddr); ipX_addr_t API_MSG_M_DEF(netif_addr); enum netconn_igmp join_or_leave; } jl; #endif /* LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) */ #if TCP_LISTEN_BACKLOG struct { u8_t backlog; } lb; #endif /* TCP_LISTEN_BACKLOG */ } msg; }; /** This struct contains a function to execute in another thread context and a struct api_msg_msg that serves as an argument for this function. This is passed to tcpip_apimsg to execute functions in tcpip_thread context. */ struct api_msg { /** function to execute in tcpip_thread context */ void (* function)(struct api_msg_msg *msg); /** arguments for this function */ struct api_msg_msg msg; }; #if LWIP_DNS /** As lwip_netconn_do_gethostbyname requires more arguments but doesn't require a netconn, it has its own struct (to avoid struct api_msg getting bigger than necessary). lwip_netconn_do_gethostbyname must be called using tcpip_callback instead of tcpip_apimsg (see netconn_gethostbyname). */ struct dns_api_msg { /** Hostname to query or dotted IP address string */ #if LWIP_MPU_COMPATIBLE char name[DNS_MAX_NAME_LENGTH]; #else /* LWIP_MPU_COMPATIBLE */ const char *name; #endif /* LWIP_MPU_COMPATIBLE */ /** Rhe resolved address is stored here */ ip_addr_t API_MSG_M_DEF(addr); /** This semaphore is posted when the name is resolved, the application thread should wait on it. */ sys_sem_t API_MSG_M_DEF(sem); /** Errors are given back here */ err_t API_MSG_M_DEF(err); }; #endif /* LWIP_DNS */ void lwip_netconn_do_newconn ( struct api_msg_msg *msg); void lwip_netconn_do_delconn ( struct api_msg_msg *msg); void lwip_netconn_do_bind ( struct api_msg_msg *msg); void lwip_netconn_do_connect ( struct api_msg_msg *msg); void lwip_netconn_do_disconnect ( struct api_msg_msg *msg); void lwip_netconn_do_listen ( struct api_msg_msg *msg); void lwip_netconn_do_send ( struct api_msg_msg *msg); void lwip_netconn_do_recv ( struct api_msg_msg *msg); void lwip_netconn_do_write ( struct api_msg_msg *msg); void lwip_netconn_do_getaddr ( struct api_msg_msg *msg); void lwip_netconn_do_close ( struct api_msg_msg *msg); void lwip_netconn_do_shutdown ( struct api_msg_msg *msg); #if LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) void lwip_netconn_do_join_leave_group( struct api_msg_msg *msg); #endif /* LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) */ #if LWIP_DNS void lwip_netconn_do_gethostbyname(void *arg); #endif /* LWIP_DNS */ struct netconn* netconn_alloc(enum netconn_type t, netconn_callback callback); void netconn_free(struct netconn *conn); #ifdef __cplusplus } #endif #endif /* LWIP_NETCONN */ #endif /* LWIP_HDR_API_MSG_H */ ocproxy-1.60/lwip/src/include/lwip/arch.h000066400000000000000000000224711303453231400203750ustar00rootroot00000000000000/* * Copyright (c) 2001-2004 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #ifndef LWIP_HDR_ARCH_H #define LWIP_HDR_ARCH_H #ifndef LITTLE_ENDIAN #define LITTLE_ENDIAN 1234 #endif #ifndef BIG_ENDIAN #define BIG_ENDIAN 4321 #endif #include "arch/cc.h" /** Temporary: define format string for size_t if not defined in cc.h */ #ifndef SZT_F #define SZT_F U32_F #endif /* SZT_F */ /** Temporary upgrade helper: define format string for u8_t as hex if not defined in cc.h */ #ifndef X8_F #define X8_F "02x" #endif /* X8_F */ #ifdef __cplusplus extern "C" { #endif #ifndef PACK_STRUCT_BEGIN #define PACK_STRUCT_BEGIN #endif /* PACK_STRUCT_BEGIN */ #ifndef PACK_STRUCT_END #define PACK_STRUCT_END #endif /* PACK_STRUCT_END */ #ifndef PACK_STRUCT_FIELD #define PACK_STRUCT_FIELD(x) x #endif /* PACK_STRUCT_FIELD */ #ifndef LWIP_UNUSED_ARG #define LWIP_UNUSED_ARG(x) (void)x #endif /* LWIP_UNUSED_ARG */ #ifdef LWIP_PROVIDE_ERRNO #define EPERM 1 /* Operation not permitted */ #define ENOENT 2 /* No such file or directory */ #define ESRCH 3 /* No such process */ #define EINTR 4 /* Interrupted system call */ #define EIO 5 /* I/O error */ #define ENXIO 6 /* No such device or address */ #define E2BIG 7 /* Arg list too long */ #define ENOEXEC 8 /* Exec format error */ #define EBADF 9 /* Bad file number */ #define ECHILD 10 /* No child processes */ #define EAGAIN 11 /* Try again */ #define ENOMEM 12 /* Out of memory */ #define EACCES 13 /* Permission denied */ #define EFAULT 14 /* Bad address */ #define ENOTBLK 15 /* Block device required */ #define EBUSY 16 /* Device or resource busy */ #define EEXIST 17 /* File exists */ #define EXDEV 18 /* Cross-device link */ #define ENODEV 19 /* No such device */ #define ENOTDIR 20 /* Not a directory */ #define EISDIR 21 /* Is a directory */ #define EINVAL 22 /* Invalid argument */ #define ENFILE 23 /* File table overflow */ #define EMFILE 24 /* Too many open files */ #define ENOTTY 25 /* Not a typewriter */ #define ETXTBSY 26 /* Text file busy */ #define EFBIG 27 /* File too large */ #define ENOSPC 28 /* No space left on device */ #define ESPIPE 29 /* Illegal seek */ #define EROFS 30 /* Read-only file system */ #define EMLINK 31 /* Too many links */ #define EPIPE 32 /* Broken pipe */ #define EDOM 33 /* Math argument out of domain of func */ #define ERANGE 34 /* Math result not representable */ #define EDEADLK 35 /* Resource deadlock would occur */ #define ENAMETOOLONG 36 /* File name too long */ #define ENOLCK 37 /* No record locks available */ #define ENOSYS 38 /* Function not implemented */ #define ENOTEMPTY 39 /* Directory not empty */ #define ELOOP 40 /* Too many symbolic links encountered */ #define EWOULDBLOCK EAGAIN /* Operation would block */ #define ENOMSG 42 /* No message of desired type */ #define EIDRM 43 /* Identifier removed */ #define ECHRNG 44 /* Channel number out of range */ #define EL2NSYNC 45 /* Level 2 not synchronized */ #define EL3HLT 46 /* Level 3 halted */ #define EL3RST 47 /* Level 3 reset */ #define ELNRNG 48 /* Link number out of range */ #define EUNATCH 49 /* Protocol driver not attached */ #define ENOCSI 50 /* No CSI structure available */ #define EL2HLT 51 /* Level 2 halted */ #define EBADE 52 /* Invalid exchange */ #define EBADR 53 /* Invalid request descriptor */ #define EXFULL 54 /* Exchange full */ #define ENOANO 55 /* No anode */ #define EBADRQC 56 /* Invalid request code */ #define EBADSLT 57 /* Invalid slot */ #define EDEADLOCK EDEADLK #define EBFONT 59 /* Bad font file format */ #define ENOSTR 60 /* Device not a stream */ #define ENODATA 61 /* No data available */ #define ETIME 62 /* Timer expired */ #define ENOSR 63 /* Out of streams resources */ #define ENONET 64 /* Machine is not on the network */ #define ENOPKG 65 /* Package not installed */ #define EREMOTE 66 /* Object is remote */ #define ENOLINK 67 /* Link has been severed */ #define EADV 68 /* Advertise error */ #define ESRMNT 69 /* Srmount error */ #define ECOMM 70 /* Communication error on send */ #define EPROTO 71 /* Protocol error */ #define EMULTIHOP 72 /* Multihop attempted */ #define EDOTDOT 73 /* RFS specific error */ #define EBADMSG 74 /* Not a data message */ #define EOVERFLOW 75 /* Value too large for defined data type */ #define ENOTUNIQ 76 /* Name not unique on network */ #define EBADFD 77 /* File descriptor in bad state */ #define EREMCHG 78 /* Remote address changed */ #define ELIBACC 79 /* Can not access a needed shared library */ #define ELIBBAD 80 /* Accessing a corrupted shared library */ #define ELIBSCN 81 /* .lib section in a.out corrupted */ #define ELIBMAX 82 /* Attempting to link in too many shared libraries */ #define ELIBEXEC 83 /* Cannot exec a shared library directly */ #define EILSEQ 84 /* Illegal byte sequence */ #define ERESTART 85 /* Interrupted system call should be restarted */ #define ESTRPIPE 86 /* Streams pipe error */ #define EUSERS 87 /* Too many users */ #define ENOTSOCK 88 /* Socket operation on non-socket */ #define EDESTADDRREQ 89 /* Destination address required */ #define EMSGSIZE 90 /* Message too long */ #define EPROTOTYPE 91 /* Protocol wrong type for socket */ #define ENOPROTOOPT 92 /* Protocol not available */ #define EPROTONOSUPPORT 93 /* Protocol not supported */ #define ESOCKTNOSUPPORT 94 /* Socket type not supported */ #define EOPNOTSUPP 95 /* Operation not supported on transport endpoint */ #define EPFNOSUPPORT 96 /* Protocol family not supported */ #define EAFNOSUPPORT 97 /* Address family not supported by protocol */ #define EADDRINUSE 98 /* Address already in use */ #define EADDRNOTAVAIL 99 /* Cannot assign requested address */ #define ENETDOWN 100 /* Network is down */ #define ENETUNREACH 101 /* Network is unreachable */ #define ENETRESET 102 /* Network dropped connection because of reset */ #define ECONNABORTED 103 /* Software caused connection abort */ #define ECONNRESET 104 /* Connection reset by peer */ #define ENOBUFS 105 /* No buffer space available */ #define EISCONN 106 /* Transport endpoint is already connected */ #define ENOTCONN 107 /* Transport endpoint is not connected */ #define ESHUTDOWN 108 /* Cannot send after transport endpoint shutdown */ #define ETOOMANYREFS 109 /* Too many references: cannot splice */ #define ETIMEDOUT 110 /* Connection timed out */ #define ECONNREFUSED 111 /* Connection refused */ #define EHOSTDOWN 112 /* Host is down */ #define EHOSTUNREACH 113 /* No route to host */ #define EALREADY 114 /* Operation already in progress */ #define EINPROGRESS 115 /* Operation now in progress */ #define ESTALE 116 /* Stale NFS file handle */ #define EUCLEAN 117 /* Structure needs cleaning */ #define ENOTNAM 118 /* Not a XENIX named type file */ #define ENAVAIL 119 /* No XENIX semaphores available */ #define EISNAM 120 /* Is a named type file */ #define EREMOTEIO 121 /* Remote I/O error */ #define EDQUOT 122 /* Quota exceeded */ #define ENOMEDIUM 123 /* No medium found */ #define EMEDIUMTYPE 124 /* Wrong medium type */ #ifndef errno extern int errno; #endif #endif /* LWIP_PROVIDE_ERRNO */ #ifdef __cplusplus } #endif #endif /* LWIP_HDR_ARCH_H */ ocproxy-1.60/lwip/src/include/lwip/debug.h000066400000000000000000000101071303453231400205370ustar00rootroot00000000000000/* * Copyright (c) 2001-2004 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #ifndef LWIP_HDR_DEBUG_H #define LWIP_HDR_DEBUG_H #include "lwip/arch.h" #include "lwip/opt.h" /** lower two bits indicate debug level * - 0 all * - 1 warning * - 2 serious * - 3 severe */ #define LWIP_DBG_LEVEL_ALL 0x00 #define LWIP_DBG_LEVEL_OFF LWIP_DBG_LEVEL_ALL /* compatibility define only */ #define LWIP_DBG_LEVEL_WARNING 0x01 /* bad checksums, dropped packets, ... */ #define LWIP_DBG_LEVEL_SERIOUS 0x02 /* memory allocation failures, ... */ #define LWIP_DBG_LEVEL_SEVERE 0x03 #define LWIP_DBG_MASK_LEVEL 0x03 /** flag for LWIP_DEBUGF to enable that debug message */ #define LWIP_DBG_ON 0x80U /** flag for LWIP_DEBUGF to disable that debug message */ #define LWIP_DBG_OFF 0x00U /** flag for LWIP_DEBUGF indicating a tracing message (to follow program flow) */ #define LWIP_DBG_TRACE 0x40U /** flag for LWIP_DEBUGF indicating a state debug message (to follow module states) */ #define LWIP_DBG_STATE 0x20U /** flag for LWIP_DEBUGF indicating newly added code, not thoroughly tested yet */ #define LWIP_DBG_FRESH 0x10U /** flag for LWIP_DEBUGF to halt after printing this debug message */ #define LWIP_DBG_HALT 0x08U #ifndef LWIP_NOASSERT #define LWIP_ASSERT(message, assertion) do { if(!(assertion)) \ LWIP_PLATFORM_ASSERT(message); } while(0) #else /* LWIP_NOASSERT */ #define LWIP_ASSERT(message, assertion) #endif /* LWIP_NOASSERT */ /** if "expression" isn't true, then print "message" and execute "handler" expression */ #ifndef LWIP_ERROR #define LWIP_ERROR(message, expression, handler) do { if (!(expression)) { \ LWIP_PLATFORM_ASSERT(message); handler;}} while(0) #endif /* LWIP_ERROR */ #ifdef LWIP_DEBUG /** print debug message only if debug message type is enabled... * AND is of correct type AND is at least LWIP_DBG_LEVEL */ #define LWIP_DEBUGF(debug, message) do { \ if ( \ ((debug) & LWIP_DBG_ON) && \ ((debug) & LWIP_DBG_TYPES_ON) && \ ((s16_t)((debug) & LWIP_DBG_MASK_LEVEL) >= LWIP_DBG_MIN_LEVEL)) { \ LWIP_PLATFORM_DIAG(message); \ if ((debug) & LWIP_DBG_HALT) { \ while(1); \ } \ } \ } while(0) #else /* LWIP_DEBUG */ #define LWIP_DEBUGF(debug, message) #endif /* LWIP_DEBUG */ #endif /* LWIP_HDR_DEBUG_H */ ocproxy-1.60/lwip/src/include/lwip/def.h000066400000000000000000000074571303453231400202250ustar00rootroot00000000000000/* * Copyright (c) 2001-2004 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #ifndef LWIP_HDR_DEF_H #define LWIP_HDR_DEF_H /* arch.h might define NULL already */ #include "lwip/arch.h" #include "lwip/opt.h" #ifdef __cplusplus extern "C" { #endif #define LWIP_MAX(x , y) (((x) > (y)) ? (x) : (y)) #define LWIP_MIN(x , y) (((x) < (y)) ? (x) : (y)) #ifndef NULL #define NULL ((void *)0) #endif /* Endianess-optimized shifting of two u8_t to create one u16_t */ #if BYTE_ORDER == LITTLE_ENDIAN #define LWIP_MAKE_U16(a, b) ((a << 8) | b) #else #define LWIP_MAKE_U16(a, b) ((b << 8) | a) #endif #ifndef LWIP_PLATFORM_BYTESWAP #define LWIP_PLATFORM_BYTESWAP 0 #endif #ifndef LWIP_PREFIX_BYTEORDER_FUNCS /* workaround for naming collisions on some platforms */ #ifdef htons #undef htons #endif /* htons */ #ifdef htonl #undef htonl #endif /* htonl */ #ifdef ntohs #undef ntohs #endif /* ntohs */ #ifdef ntohl #undef ntohl #endif /* ntohl */ #define htons(x) lwip_htons(x) #define ntohs(x) lwip_ntohs(x) #define htonl(x) lwip_htonl(x) #define ntohl(x) lwip_ntohl(x) #endif /* LWIP_PREFIX_BYTEORDER_FUNCS */ #if BYTE_ORDER == BIG_ENDIAN #define lwip_htons(x) (x) #define lwip_ntohs(x) (x) #define lwip_htonl(x) (x) #define lwip_ntohl(x) (x) #define PP_HTONS(x) (x) #define PP_NTOHS(x) (x) #define PP_HTONL(x) (x) #define PP_NTOHL(x) (x) #else /* BYTE_ORDER != BIG_ENDIAN */ #if LWIP_PLATFORM_BYTESWAP #define lwip_htons(x) LWIP_PLATFORM_HTONS(x) #define lwip_ntohs(x) LWIP_PLATFORM_HTONS(x) #define lwip_htonl(x) LWIP_PLATFORM_HTONL(x) #define lwip_ntohl(x) LWIP_PLATFORM_HTONL(x) #else /* LWIP_PLATFORM_BYTESWAP */ u16_t lwip_htons(u16_t x); u16_t lwip_ntohs(u16_t x); u32_t lwip_htonl(u32_t x); u32_t lwip_ntohl(u32_t x); #endif /* LWIP_PLATFORM_BYTESWAP */ /* These macros should be calculated by the preprocessor and are used with compile-time constants only (so that there is no little-endian overhead at runtime). */ #define PP_HTONS(x) ((((x) & 0xff) << 8) | (((x) & 0xff00) >> 8)) #define PP_NTOHS(x) PP_HTONS(x) #define PP_HTONL(x) ((((x) & 0xff) << 24) | \ (((x) & 0xff00) << 8) | \ (((x) & 0xff0000UL) >> 8) | \ (((x) & 0xff000000UL) >> 24)) #define PP_NTOHL(x) PP_HTONL(x) #endif /* BYTE_ORDER == BIG_ENDIAN */ #ifdef __cplusplus } #endif #endif /* LWIP_HDR_DEF_H */ ocproxy-1.60/lwip/src/include/lwip/dhcp.h000066400000000000000000000171371303453231400204010ustar00rootroot00000000000000/** @file */ #ifndef LWIP_HDR_DHCP_H #define LWIP_HDR_DHCP_H #include "lwip/opt.h" #if LWIP_DHCP /* don't build if not configured for use in lwipopts.h */ #include "lwip/netif.h" #include "lwip/udp.h" #ifdef __cplusplus extern "C" { #endif /** period (in seconds) of the application calling dhcp_coarse_tmr() */ #define DHCP_COARSE_TIMER_SECS 60 /** period (in milliseconds) of the application calling dhcp_coarse_tmr() */ #define DHCP_COARSE_TIMER_MSECS (DHCP_COARSE_TIMER_SECS * 1000UL) /** period (in milliseconds) of the application calling dhcp_fine_tmr() */ #define DHCP_FINE_TIMER_MSECS 500 #define DHCP_CHADDR_LEN 16U #define DHCP_SNAME_LEN 64U #define DHCP_FILE_LEN 128U struct dhcp { /** transaction identifier of last sent request */ u32_t xid; /** our connection to the DHCP server */ struct udp_pcb *pcb; /** incoming msg */ struct dhcp_msg *msg_in; /** current DHCP state machine state */ u8_t state; /** retries of current request */ u8_t tries; #if LWIP_DHCP_AUTOIP_COOP u8_t autoip_coop_state; #endif u8_t subnet_mask_given; struct pbuf *p_out; /* pbuf of outcoming msg */ struct dhcp_msg *msg_out; /* outgoing msg */ u16_t options_out_len; /* outgoing msg options length */ u16_t request_timeout; /* #ticks with period DHCP_FINE_TIMER_SECS for request timeout */ u16_t t1_timeout; /* #ticks with period DHCP_COARSE_TIMER_SECS for renewal time */ u16_t t2_timeout; /* #ticks with period DHCP_COARSE_TIMER_SECS for rebind time */ ip_addr_t server_ip_addr; /* dhcp server address that offered this lease */ ip_addr_t offered_ip_addr; ip_addr_t offered_sn_mask; ip_addr_t offered_gw_addr; u32_t offered_t0_lease; /* lease period (in seconds) */ u32_t offered_t1_renew; /* recommended renew time (usually 50% of lease period) */ u32_t offered_t2_rebind; /* recommended rebind time (usually 66% of lease period) */ /* @todo: LWIP_DHCP_BOOTP_FILE configuration option? integrate with possible TFTP-client for booting? */ #if LWIP_DHCP_BOOTP_FILE ip_addr_t offered_si_addr; char boot_file_name[DHCP_FILE_LEN]; #endif /* LWIP_DHCP_BOOTPFILE */ }; /* MUST be compiled with "pack structs" or equivalent! */ #ifdef PACK_STRUCT_USE_INCLUDES # include "arch/bpstruct.h" #endif PACK_STRUCT_BEGIN /** minimum set of fields of any DHCP message */ struct dhcp_msg { PACK_STRUCT_FIELD(u8_t op); PACK_STRUCT_FIELD(u8_t htype); PACK_STRUCT_FIELD(u8_t hlen); PACK_STRUCT_FIELD(u8_t hops); PACK_STRUCT_FIELD(u32_t xid); PACK_STRUCT_FIELD(u16_t secs); PACK_STRUCT_FIELD(u16_t flags); PACK_STRUCT_FIELD(ip_addr_p_t ciaddr); PACK_STRUCT_FIELD(ip_addr_p_t yiaddr); PACK_STRUCT_FIELD(ip_addr_p_t siaddr); PACK_STRUCT_FIELD(ip_addr_p_t giaddr); PACK_STRUCT_FIELD(u8_t chaddr[DHCP_CHADDR_LEN]); PACK_STRUCT_FIELD(u8_t sname[DHCP_SNAME_LEN]); PACK_STRUCT_FIELD(u8_t file[DHCP_FILE_LEN]); PACK_STRUCT_FIELD(u32_t cookie); #define DHCP_MIN_OPTIONS_LEN 68U /** make sure user does not configure this too small */ #if ((defined(DHCP_OPTIONS_LEN)) && (DHCP_OPTIONS_LEN < DHCP_MIN_OPTIONS_LEN)) # undef DHCP_OPTIONS_LEN #endif /** allow this to be configured in lwipopts.h, but not too small */ #if (!defined(DHCP_OPTIONS_LEN)) /** set this to be sufficient for your options in outgoing DHCP msgs */ # define DHCP_OPTIONS_LEN DHCP_MIN_OPTIONS_LEN #endif PACK_STRUCT_FIELD(u8_t options[DHCP_OPTIONS_LEN]); } PACK_STRUCT_STRUCT; PACK_STRUCT_END #ifdef PACK_STRUCT_USE_INCLUDES # include "arch/epstruct.h" #endif void dhcp_set_struct(struct netif *netif, struct dhcp *dhcp); /** Remove a struct dhcp previously set to the netif using dhcp_set_struct() */ #define dhcp_remove_struct(netif) do { (netif)->dhcp = NULL; } while(0) void dhcp_cleanup(struct netif *netif); /** start DHCP configuration */ err_t dhcp_start(struct netif *netif); /** enforce early lease renewal (not needed normally)*/ err_t dhcp_renew(struct netif *netif); /** release the DHCP lease, usually called before dhcp_stop()*/ err_t dhcp_release(struct netif *netif); /** stop DHCP configuration */ void dhcp_stop(struct netif *netif); /** inform server of our manual IP address */ void dhcp_inform(struct netif *netif); /** Handle a possible change in the network configuration */ void dhcp_network_changed(struct netif *netif); /** if enabled, check whether the offered IP address is not in use, using ARP */ #if DHCP_DOES_ARP_CHECK void dhcp_arp_reply(struct netif *netif, ip_addr_t *addr); #endif /** to be called every minute */ void dhcp_coarse_tmr(void); /** to be called every half second */ void dhcp_fine_tmr(void); /** DHCP message item offsets and length */ #define DHCP_OP_OFS 0 #define DHCP_HTYPE_OFS 1 #define DHCP_HLEN_OFS 2 #define DHCP_HOPS_OFS 3 #define DHCP_XID_OFS 4 #define DHCP_SECS_OFS 8 #define DHCP_FLAGS_OFS 10 #define DHCP_CIADDR_OFS 12 #define DHCP_YIADDR_OFS 16 #define DHCP_SIADDR_OFS 20 #define DHCP_GIADDR_OFS 24 #define DHCP_CHADDR_OFS 28 #define DHCP_SNAME_OFS 44 #define DHCP_FILE_OFS 108 #define DHCP_MSG_LEN 236 #define DHCP_COOKIE_OFS DHCP_MSG_LEN #define DHCP_OPTIONS_OFS (DHCP_MSG_LEN + 4) #define DHCP_CLIENT_PORT 68 #define DHCP_SERVER_PORT 67 /** DHCP client states */ #define DHCP_OFF 0 #define DHCP_REQUESTING 1 #define DHCP_INIT 2 #define DHCP_REBOOTING 3 #define DHCP_REBINDING 4 #define DHCP_RENEWING 5 #define DHCP_SELECTING 6 #define DHCP_INFORMING 7 #define DHCP_CHECKING 8 #define DHCP_PERMANENT 9 #define DHCP_BOUND 10 /** not yet implemented #define DHCP_RELEASING 11 */ #define DHCP_BACKING_OFF 12 /** AUTOIP cooperatation flags */ #define DHCP_AUTOIP_COOP_STATE_OFF 0 #define DHCP_AUTOIP_COOP_STATE_ON 1 #define DHCP_BOOTREQUEST 1 #define DHCP_BOOTREPLY 2 /** DHCP message types */ #define DHCP_DISCOVER 1 #define DHCP_OFFER 2 #define DHCP_REQUEST 3 #define DHCP_DECLINE 4 #define DHCP_ACK 5 #define DHCP_NAK 6 #define DHCP_RELEASE 7 #define DHCP_INFORM 8 /** DHCP hardware type, currently only ethernet is supported */ #define DHCP_HTYPE_ETH 1 #define DHCP_MAGIC_COOKIE 0x63825363UL /* This is a list of options for BOOTP and DHCP, see RFC 2132 for descriptions */ /** BootP options */ #define DHCP_OPTION_PAD 0 #define DHCP_OPTION_SUBNET_MASK 1 /* RFC 2132 3.3 */ #define DHCP_OPTION_ROUTER 3 #define DHCP_OPTION_DNS_SERVER 6 #define DHCP_OPTION_HOSTNAME 12 #define DHCP_OPTION_IP_TTL 23 #define DHCP_OPTION_MTU 26 #define DHCP_OPTION_BROADCAST 28 #define DHCP_OPTION_TCP_TTL 37 #define DHCP_OPTION_END 255 /** DHCP options */ #define DHCP_OPTION_REQUESTED_IP 50 /* RFC 2132 9.1, requested IP address */ #define DHCP_OPTION_LEASE_TIME 51 /* RFC 2132 9.2, time in seconds, in 4 bytes */ #define DHCP_OPTION_OVERLOAD 52 /* RFC2132 9.3, use file and/or sname field for options */ #define DHCP_OPTION_MESSAGE_TYPE 53 /* RFC 2132 9.6, important for DHCP */ #define DHCP_OPTION_MESSAGE_TYPE_LEN 1 #define DHCP_OPTION_SERVER_ID 54 /* RFC 2132 9.7, server IP address */ #define DHCP_OPTION_PARAMETER_REQUEST_LIST 55 /* RFC 2132 9.8, requested option types */ #define DHCP_OPTION_MAX_MSG_SIZE 57 /* RFC 2132 9.10, message size accepted >= 576 */ #define DHCP_OPTION_MAX_MSG_SIZE_LEN 2 #define DHCP_OPTION_T1 58 /* T1 renewal time */ #define DHCP_OPTION_T2 59 /* T2 rebinding time */ #define DHCP_OPTION_US 60 #define DHCP_OPTION_CLIENT_ID 61 #define DHCP_OPTION_TFTP_SERVERNAME 66 #define DHCP_OPTION_BOOTFILE 67 /** possible combinations of overloading the file and sname fields with options */ #define DHCP_OVERLOAD_NONE 0 #define DHCP_OVERLOAD_FILE 1 #define DHCP_OVERLOAD_SNAME 2 #define DHCP_OVERLOAD_SNAME_FILE 3 #ifdef __cplusplus } #endif #endif /* LWIP_DHCP */ #endif /*LWIP_HDR_DHCP_H*/ ocproxy-1.60/lwip/src/include/lwip/dns.h000066400000000000000000000131331303453231400202370ustar00rootroot00000000000000/** * lwip DNS resolver header file. * Author: Jim Pettinato * April 2007 * ported from uIP resolv.c Copyright (c) 2002-2003, Adam Dunkels. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote * products derived from this software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef LWIP_HDR_DNS_H #define LWIP_HDR_DNS_H #include "lwip/opt.h" #if LWIP_DNS /* don't build if not configured for use in lwipopts.h */ #ifdef __cplusplus extern "C" { #endif /** DNS timer period */ #define DNS_TMR_INTERVAL 1000 /** DNS field TYPE used for "Resource Records" */ #define DNS_RRTYPE_A 1 /* a host address */ #define DNS_RRTYPE_NS 2 /* an authoritative name server */ #define DNS_RRTYPE_MD 3 /* a mail destination (Obsolete - use MX) */ #define DNS_RRTYPE_MF 4 /* a mail forwarder (Obsolete - use MX) */ #define DNS_RRTYPE_CNAME 5 /* the canonical name for an alias */ #define DNS_RRTYPE_SOA 6 /* marks the start of a zone of authority */ #define DNS_RRTYPE_MB 7 /* a mailbox domain name (EXPERIMENTAL) */ #define DNS_RRTYPE_MG 8 /* a mail group member (EXPERIMENTAL) */ #define DNS_RRTYPE_MR 9 /* a mail rename domain name (EXPERIMENTAL) */ #define DNS_RRTYPE_NULL 10 /* a null RR (EXPERIMENTAL) */ #define DNS_RRTYPE_WKS 11 /* a well known service description */ #define DNS_RRTYPE_PTR 12 /* a domain name pointer */ #define DNS_RRTYPE_HINFO 13 /* host information */ #define DNS_RRTYPE_MINFO 14 /* mailbox or mail list information */ #define DNS_RRTYPE_MX 15 /* mail exchange */ #define DNS_RRTYPE_TXT 16 /* text strings */ /** DNS field CLASS used for "Resource Records" */ #define DNS_RRCLASS_IN 1 /* the Internet */ #define DNS_RRCLASS_CS 2 /* the CSNET class (Obsolete - used only for examples in some obsolete RFCs) */ #define DNS_RRCLASS_CH 3 /* the CHAOS class */ #define DNS_RRCLASS_HS 4 /* Hesiod [Dyer 87] */ #define DNS_RRCLASS_FLUSH 0x800 /* Flush bit */ /* The size used for the next line is rather a hack, but it prevents including socket.h in all files that include memp.h, and that would possibly break portability (since socket.h defines some types and constants possibly already define by the OS). Calculation rule: sizeof(struct addrinfo) + sizeof(struct sockaddr_in) + DNS_MAX_NAME_LENGTH + 1 byte zero-termination */ #define NETDB_ELEM_SIZE (32 + 16 + DNS_MAX_NAME_LENGTH + 1) #if DNS_LOCAL_HOSTLIST /** struct used for local host-list */ struct local_hostlist_entry { /** static hostname */ const char *name; /** static host address in network byteorder */ ip_addr_t addr; struct local_hostlist_entry *next; }; #if DNS_LOCAL_HOSTLIST_IS_DYNAMIC #ifndef DNS_LOCAL_HOSTLIST_MAX_NAMELEN #define DNS_LOCAL_HOSTLIST_MAX_NAMELEN DNS_MAX_NAME_LENGTH #endif #define LOCALHOSTLIST_ELEM_SIZE ((sizeof(struct local_hostlist_entry) + DNS_LOCAL_HOSTLIST_MAX_NAMELEN + 1)) #endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ #endif /* DNS_LOCAL_HOSTLIST */ /** Callback which is invoked when a hostname is found. * A function of this type must be implemented by the application using the DNS resolver. * @param name pointer to the name that was looked up. * @param ipaddr pointer to an ip_addr_t containing the IP address of the hostname, * or NULL if the name could not be found (or on any other error). * @param callback_arg a user-specified callback argument passed to dns_gethostbyname */ typedef void (*dns_found_callback)(const char *name, ip_addr_t *ipaddr, void *callback_arg); void dns_init(void); void dns_tmr(void); void dns_setserver(u8_t numdns, ip_addr_t *dnsserver); ip_addr_t dns_getserver(u8_t numdns); err_t dns_gethostbyname(const char *hostname, ip_addr_t *addr, dns_found_callback found, void *callback_arg); #if DNS_LOCAL_HOSTLIST && DNS_LOCAL_HOSTLIST_IS_DYNAMIC int dns_local_removehost(const char *hostname, const ip_addr_t *addr); err_t dns_local_addhost(const char *hostname, const ip_addr_t *addr); #endif /* DNS_LOCAL_HOSTLIST && DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ #ifdef __cplusplus } #endif #endif /* LWIP_DNS */ #endif /* LWIP_HDR_DNS_H */ ocproxy-1.60/lwip/src/include/lwip/err.h000066400000000000000000000061611303453231400202460ustar00rootroot00000000000000/* * Copyright (c) 2001-2004 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #ifndef LWIP_HDR_ERR_H #define LWIP_HDR_ERR_H #include "lwip/opt.h" #include "lwip/arch.h" #ifdef __cplusplus extern "C" { #endif /** Define LWIP_ERR_T in cc.h if you want to use * a different type for your platform (must be signed). */ #ifdef LWIP_ERR_T typedef LWIP_ERR_T err_t; #else /* LWIP_ERR_T */ typedef s8_t err_t; #endif /* LWIP_ERR_T*/ /* Definitions for error constants. */ #define ERR_OK 0 /* No error, everything OK. */ #define ERR_MEM -1 /* Out of memory error. */ #define ERR_BUF -2 /* Buffer error. */ #define ERR_TIMEOUT -3 /* Timeout. */ #define ERR_RTE -4 /* Routing problem. */ #define ERR_INPROGRESS -5 /* Operation in progress */ #define ERR_VAL -6 /* Illegal value. */ #define ERR_WOULDBLOCK -7 /* Operation would block. */ #define ERR_USE -8 /* Address in use. */ #define ERR_ISCONN -9 /* Already connected. */ #define ERR_IS_FATAL(e) ((e) < ERR_ISCONN) #define ERR_ABRT -10 /* Connection aborted. */ #define ERR_RST -11 /* Connection reset. */ #define ERR_CLSD -12 /* Connection closed. */ #define ERR_CONN -13 /* Not connected. */ #define ERR_ARG -14 /* Illegal argument. */ #define ERR_IF -15 /* Low-level netif error */ #ifdef LWIP_DEBUG extern const char *lwip_strerr(err_t err); #else #define lwip_strerr(x) "" #endif /* LWIP_DEBUG */ #ifdef __cplusplus } #endif #endif /* LWIP_HDR_ERR_H */ ocproxy-1.60/lwip/src/include/lwip/inet_chksum.h000066400000000000000000000110241303453231400217610ustar00rootroot00000000000000/* * Copyright (c) 2001-2004 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #ifndef LWIP_HDR_INET_CHKSUM_H #define LWIP_HDR_INET_CHKSUM_H #include "lwip/opt.h" #include "lwip/pbuf.h" #include "lwip/ip_addr.h" /** Swap the bytes in an u16_t: much like htons() for little-endian */ #ifndef SWAP_BYTES_IN_WORD #if LWIP_PLATFORM_BYTESWAP && (BYTE_ORDER == LITTLE_ENDIAN) /* little endian and PLATFORM_BYTESWAP defined */ #define SWAP_BYTES_IN_WORD(w) LWIP_PLATFORM_HTONS(w) #else /* LWIP_PLATFORM_BYTESWAP && (BYTE_ORDER == LITTLE_ENDIAN) */ /* can't use htons on big endian (or PLATFORM_BYTESWAP not defined)... */ #define SWAP_BYTES_IN_WORD(w) (((w) & 0xff) << 8) | (((w) & 0xff00) >> 8) #endif /* LWIP_PLATFORM_BYTESWAP && (BYTE_ORDER == LITTLE_ENDIAN)*/ #endif /* SWAP_BYTES_IN_WORD */ /** Split an u32_t in two u16_ts and add them up */ #ifndef FOLD_U32T #define FOLD_U32T(u) (((u) >> 16) + ((u) & 0x0000ffffUL)) #endif #if LWIP_CHECKSUM_ON_COPY /** Function-like macro: same as MEMCPY but returns the checksum of copied data as u16_t */ #ifndef LWIP_CHKSUM_COPY #define LWIP_CHKSUM_COPY(dst, src, len) lwip_chksum_copy(dst, src, len) #ifndef LWIP_CHKSUM_COPY_ALGORITHM #define LWIP_CHKSUM_COPY_ALGORITHM 1 #endif /* LWIP_CHKSUM_COPY_ALGORITHM */ #endif /* LWIP_CHKSUM_COPY */ #else /* LWIP_CHECKSUM_ON_COPY */ #define LWIP_CHKSUM_COPY_ALGORITHM 0 #endif /* LWIP_CHECKSUM_ON_COPY */ #ifdef __cplusplus extern "C" { #endif u16_t inet_chksum(void *dataptr, u16_t len); u16_t inet_chksum_pbuf(struct pbuf *p); u16_t inet_chksum_pseudo(struct pbuf *p, u8_t proto, u16_t proto_len, ip_addr_t *src, ip_addr_t *dest); u16_t inet_chksum_pseudo_partial(struct pbuf *p, u8_t proto, u16_t proto_len, u16_t chksum_len, ip_addr_t *src, ip_addr_t *dest); #if LWIP_CHKSUM_COPY_ALGORITHM u16_t lwip_chksum_copy(void *dst, const void *src, u16_t len); #endif /* LWIP_CHKSUM_COPY_ALGORITHM */ #if LWIP_IPV6 u16_t ip6_chksum_pseudo(struct pbuf *p, u8_t proto, u16_t proto_len, ip6_addr_t *src, ip6_addr_t *dest); u16_t ip6_chksum_pseudo_partial(struct pbuf *p, u8_t proto, u16_t proto_len, u16_t chksum_len, ip6_addr_t *src, ip6_addr_t *dest); #define ipX_chksum_pseudo(isipv6, p, proto, proto_len, src, dest) \ ((isipv6) ? \ ip6_chksum_pseudo(p, proto, proto_len, ipX_2_ip6(src), ipX_2_ip6(dest)) :\ inet_chksum_pseudo(p, proto, proto_len, ipX_2_ip(src), ipX_2_ip(dest))) #define ipX_chksum_pseudo_partial(isipv6, p, proto, proto_len, chksum_len, src, dest) \ ((isipv6) ? \ ip6_chksum_pseudo_partial(p, proto, proto_len, chksum_len, ipX_2_ip6(src), ipX_2_ip6(dest)) :\ inet_chksum_pseudo_partial(p, proto, proto_len, chksum_len, ipX_2_ip(src), ipX_2_ip(dest))) #else /* LWIP_IPV6 */ #define ipX_chksum_pseudo(isipv6, p, proto, proto_len, src, dest) \ inet_chksum_pseudo(p, proto, proto_len, src, dest) #define ipX_chksum_pseudo_partial(isipv6, p, proto, proto_len, chksum_len, src, dest) \ inet_chksum_pseudo_partial(p, proto, proto_len, chksum_len, src, dest) #endif /* LWIP_IPV6 */ #ifdef __cplusplus } #endif #endif /* LWIP_HDR_INET_H */ ocproxy-1.60/lwip/src/include/lwip/init.h000066400000000000000000000056171303453231400204260ustar00rootroot00000000000000/* * Copyright (c) 2001-2004 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #ifndef LWIP_HDR_INIT_H #define LWIP_HDR_INIT_H #include "lwip/opt.h" #ifdef __cplusplus extern "C" { #endif /** X.x.x: Major version of the stack */ #define LWIP_VERSION_MAJOR 1U /** x.X.x: Minor version of the stack */ #define LWIP_VERSION_MINOR 4U /** x.x.X: Revision of the stack */ #define LWIP_VERSION_REVISION 1U /** For release candidates, this is set to 1..254 * For official releases, this is set to 255 (LWIP_RC_RELEASE) * For development versions (CVS), this is set to 0 (LWIP_RC_DEVELOPMENT) */ #define LWIP_VERSION_RC 0U /** LWIP_VERSION_RC is set to LWIP_RC_RELEASE for official releases */ #define LWIP_RC_RELEASE 255U /** LWIP_VERSION_RC is set to LWIP_RC_DEVELOPMENT for CVS versions */ #define LWIP_RC_DEVELOPMENT 0U #define LWIP_VERSION_IS_RELEASE (LWIP_VERSION_RC == LWIP_RC_RELEASE) #define LWIP_VERSION_IS_DEVELOPMENT (LWIP_VERSION_RC == LWIP_RC_DEVELOPMENT) #define LWIP_VERSION_IS_RC ((LWIP_VERSION_RC != LWIP_RC_RELEASE) && (LWIP_VERSION_RC != LWIP_RC_DEVELOPMENT)) /** Provides the version of the stack */ #define LWIP_VERSION (LWIP_VERSION_MAJOR << 24 | LWIP_VERSION_MINOR << 16 | \ LWIP_VERSION_REVISION << 8 | LWIP_VERSION_RC) /* Modules initialization */ void lwip_init(void); #ifdef __cplusplus } #endif #endif /* LWIP_HDR_INIT_H */ ocproxy-1.60/lwip/src/include/lwip/ip.h000066400000000000000000000260641303453231400200720ustar00rootroot00000000000000/* * Copyright (c) 2001-2004 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #ifndef LWIP_HDR_IP_H__ #define LWIP_HDR_IP_H__ #include "lwip/opt.h" #include "lwip/def.h" #include "lwip/pbuf.h" #include "lwip/ip_addr.h" #include "lwip/err.h" #include "lwip/netif.h" #include "lwip/ip4.h" #include "lwip/ip6.h" #ifdef __cplusplus extern "C" { #endif /* This is passed as the destination address to ip_output_if (not to ip_output), meaning that an IP header already is constructed in the pbuf. This is used when TCP retransmits. */ #ifdef IP_HDRINCL #undef IP_HDRINCL #endif /* IP_HDRINCL */ #define IP_HDRINCL NULL #if LWIP_NETIF_HWADDRHINT #define IP_PCB_ADDRHINT ;u8_t addr_hint #else #define IP_PCB_ADDRHINT #endif /* LWIP_NETIF_HWADDRHINT */ #if LWIP_IPV6 #define IP_PCB_ISIPV6_MEMBER u8_t isipv6; #define IP_PCB_IPVER_EQ(pcb1, pcb2) ((pcb1)->isipv6 == (pcb2)->isipv6) #define IP_PCB_IPVER_INPUT_MATCH(pcb) (ip_current_is_v6() ? \ ((pcb)->isipv6 != 0) : \ ((pcb)->isipv6 == 0)) #define PCB_ISIPV6(pcb) ((pcb)->isipv6) #else #define IP_PCB_ISIPV6_MEMBER #define IP_PCB_IPVER_EQ(pcb1, pcb2) 1 #define IP_PCB_IPVER_INPUT_MATCH(pcb) 1 #define PCB_ISIPV6(pcb) 0 #endif /* LWIP_IPV6 */ /* This is the common part of all PCB types. It needs to be at the beginning of a PCB type definition. It is located here so that changes to this common part are made in one location instead of having to change all PCB structs. */ #define IP_PCB \ IP_PCB_ISIPV6_MEMBER \ /* ip addresses in network byte order */ \ ipX_addr_t local_ip; \ ipX_addr_t remote_ip; \ /* Socket options */ \ u8_t so_options; \ /* Type Of Service */ \ u8_t tos; \ /* Time To Live */ \ u8_t ttl \ /* link layer address resolution hint */ \ IP_PCB_ADDRHINT struct ip_pcb { /* Common members of all PCB types */ IP_PCB; }; /* * Option flags per-socket. These are the same like SO_XXX. */ /*#define SOF_DEBUG 0x01U Unimplemented: turn on debugging info recording */ #define SOF_ACCEPTCONN 0x02U /* socket has had listen() */ #define SOF_REUSEADDR 0x04U /* allow local address reuse */ #define SOF_KEEPALIVE 0x08U /* keep connections alive */ /*#define SOF_DONTROUTE 0x10U Unimplemented: just use interface addresses */ #define SOF_BROADCAST 0x20U /* permit to send and to receive broadcast messages (see IP_SOF_BROADCAST option) */ /*#define SOF_USELOOPBACK 0x40U Unimplemented: bypass hardware when possible */ #define SOF_LINGER 0x80U /* linger on close if data present */ /*#define SOF_OOBINLINE 0x0100U Unimplemented: leave received OOB data in line */ /*#define SOF_REUSEPORT 0x0200U Unimplemented: allow local address & port reuse */ /* These flags are inherited (e.g. from a listen-pcb to a connection-pcb): */ #define SOF_INHERITED (SOF_REUSEADDR|SOF_KEEPALIVE|SOF_LINGER/*|SOF_DEBUG|SOF_DONTROUTE|SOF_OOBINLINE*/) /* Global variables of this module, kept in a struct for efficient access using base+index. */ struct ip_globals { /** The interface that provided the packet for the current callback invocation. */ struct netif *current_netif; /** Header of the input packet currently being processed. */ const struct ip_hdr *current_ip4_header; #if LWIP_IPV6 /** Header of the input IPv6 packet currently being processed. */ const struct ip6_hdr *current_ip6_header; #endif /* LWIP_IPV6 */ /** Total header length of current_ip4/6_header (i.e. after this, the UDP/TCP header starts) */ u16_t current_ip_header_tot_len; /** Source IP address of current_header */ ipX_addr_t current_iphdr_src; /** Destination IP address of current_header */ ipX_addr_t current_iphdr_dest; }; extern struct ip_globals ip_data; /** Get the interface that received the current packet. * This function must only be called from a receive callback (udp_recv, * raw_recv, tcp_accept). It will return NULL otherwise. */ #define ip_current_netif() (ip_data.current_netif) /** Get the IP header of the current packet. * This function must only be called from a receive callback (udp_recv, * raw_recv, tcp_accept). It will return NULL otherwise. */ #define ip_current_header() (ip_data.current_ip4_header) /** Total header length of ip(6)_current_header() (i.e. after this, the UDP/TCP header starts) */ #define ip_current_header_tot_len() (ip_data.current_ip_header_tot_len) /** Source IP address of current_header */ #define ipX_current_src_addr() (&ip_data.current_iphdr_src) /** Destination IP address of current_header */ #define ipX_current_dest_addr() (&ip_data.current_iphdr_dest) #if LWIP_IPV6 /** Get the IPv6 header of the current packet. * This function must only be called from a receive callback (udp_recv, * raw_recv, tcp_accept). It will return NULL otherwise. */ #define ip6_current_header() (ip_data.current_ip6_header) /** Returns TRUE if the current IP input packet is IPv6, FALSE if it is IPv4 */ #define ip_current_is_v6() (ip6_current_header() != NULL) /** Source IPv6 address of current_header */ #define ip6_current_src_addr() (ipX_2_ip6(&ip_data.current_iphdr_src)) /** Destination IPv6 address of current_header */ #define ip6_current_dest_addr() (ipX_2_ip6(&ip_data.current_iphdr_dest)) /** Get the transport layer protocol */ #define ip_current_header_proto() (ip_current_is_v6() ? \ IP6H_NEXTH(ip6_current_header()) :\ IPH_PROTO(ip_current_header())) /** Get the transport layer header */ #define ipX_next_header_ptr() ((void*)((ip_current_is_v6() ? \ (u8_t*)ip6_current_header() : (u8_t*)ip_current_header()) + ip_current_header_tot_len())) /** Set an IP_PCB to IPv6 (IPv4 is the default) */ #define ip_set_v6(pcb, val) do{if(pcb != NULL) { pcb->isipv6 = val; }}while(0) /** Source IP4 address of current_header */ #define ip_current_src_addr() (ipX_2_ip(&ip_data.current_iphdr_src)) /** Destination IP4 address of current_header */ #define ip_current_dest_addr() (ipX_2_ip(&ip_data.current_iphdr_dest)) #else /* LWIP_IPV6 */ /** Always returns FALSE when only supporting IPv4 */ #define ip_current_is_v6() 0 /** Get the transport layer protocol */ #define ip_current_header_proto() IPH_PROTO(ip_current_header()) /** Get the transport layer header */ #define ipX_next_header_ptr() ((void*)((u8_t*)ip_current_header() + ip_current_header_tot_len())) /** Source IP4 address of current_header */ #define ip_current_src_addr() (&ip_data.current_iphdr_src) /** Destination IP4 address of current_header */ #define ip_current_dest_addr() (&ip_data.current_iphdr_dest) #endif /* LWIP_IPV6 */ /** Union source address of current_header */ #define ipX_current_src_addr() (&ip_data.current_iphdr_src) /** Union destination address of current_header */ #define ipX_current_dest_addr() (&ip_data.current_iphdr_dest) /** Gets an IP pcb option (SOF_* flags) */ #define ip_get_option(pcb, opt) ((pcb)->so_options & (opt)) /** Sets an IP pcb option (SOF_* flags) */ #define ip_set_option(pcb, opt) ((pcb)->so_options |= (opt)) /** Resets an IP pcb option (SOF_* flags) */ #define ip_reset_option(pcb, opt) ((pcb)->so_options &= ~(opt)) #if LWIP_IPV6 #define ipX_output(isipv6, p, src, dest, ttl, tos, proto) \ ((isipv6) ? \ ip6_output(p, ipX_2_ip6(src), ipX_2_ip6(dest), ttl, tos, proto) : \ ip_output(p, ipX_2_ip(src), ipX_2_ip(dest), ttl, tos, proto)) #define ipX_output_if(isipv6, p, src, dest, ttl, tos, proto, netif) \ ((isipv6) ? \ ip6_output_if(p, ip_2_ip6(src), ip_2_ip6(dest), ttl, tos, proto, netif) : \ ip_output_if(p, (src), (dest), ttl, tos, proto, netif)) #define ipX_output_if_src(isipv6, p, src, dest, ttl, tos, proto, netif) \ ((isipv6) ? \ ip6_output_if_src(p, ip_2_ip6(src), ip_2_ip6(dest), ttl, tos, proto, netif) : \ ip_output_if_src(p, (src), (dest), ttl, tos, proto, netif)) #define ipX_output_hinted(isipv6, p, src, dest, ttl, tos, proto, addr_hint) \ ((isipv6) ? \ ip6_output_hinted(p, ipX_2_ip6(src), ipX_2_ip6(dest), ttl, tos, proto, addr_hint) : \ ip_output_hinted(p, ipX_2_ip(src), ipX_2_ip(dest), ttl, tos, proto, addr_hint)) #define ipX_route(isipv6, src, dest) \ ((isipv6) ? \ ip6_route(ipX_2_ip6(src), ipX_2_ip6(dest)) : \ ip_route(ipX_2_ip(dest))) #define ipX_netif_get_local_ipX(isipv6, netif, dest) \ ((isipv6) ? \ ip6_netif_get_local_ipX(netif, ipX_2_ip6(dest)) : \ ip_netif_get_local_ipX(netif)) #define ipX_debug_print(is_ipv6, p) ((is_ipv6) ? ip6_debug_print(p) : ip_debug_print(p)) #else /* LWIP_IPV6 */ #define ipX_output(isipv6, p, src, dest, ttl, tos, proto) \ ip_output(p, src, dest, ttl, tos, proto) #define ipX_output_if(isipv6, p, src, dest, ttl, tos, proto, netif) \ ip_output_if(p, src, dest, ttl, tos, proto, netif) #define ipX_output_if_src(isipv6, p, src, dest, ttl, tos, proto, netif) \ ip_output_if_src(p, src, dest, ttl, tos, proto, netif) #define ipX_output_hinted(isipv6, p, src, dest, ttl, tos, proto, addr_hint) \ ip_output_hinted(p, src, dest, ttl, tos, proto, addr_hint) #define ipX_route(isipv6, src, dest) \ ip_route(ipX_2_ip(dest)) #define ipX_netif_get_local_ipX(isipv6, netif, dest) \ ip_netif_get_local_ipX(netif) #define ipX_debug_print(is_ipv6, p) ip_debug_print(p) #endif /* LWIP_IPV6 */ #define ipX_route_get_local_ipX(isipv6, src, dest, netif, ipXaddr) do { \ (netif) = ipX_route(isipv6, src, dest); \ (ipXaddr) = ipX_netif_get_local_ipX(isipv6, netif, dest); \ }while(0) #ifdef __cplusplus } #endif #endif /* LWIP_HDR_IP_H__ */ ocproxy-1.60/lwip/src/include/lwip/ip_addr.h000066400000000000000000000127671303453231400210710ustar00rootroot00000000000000/* * Copyright (c) 2001-2004 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #ifndef LWIP_HDR_IP_ADDR_H__ #define LWIP_HDR_IP_ADDR_H__ #include "lwip/opt.h" #include "lwip/def.h" #include "lwip/ip4_addr.h" #include "lwip/ip6_addr.h" #ifdef __cplusplus extern "C" { #endif #if LWIP_IPV6 /* A union struct for both IP version's addresses. */ typedef union { ip_addr_t ip4; ip6_addr_t ip6; } ipX_addr_t; /** These functions only exist for type-safe conversion from ip_addr_t to ip6_addr_t and back */ #ifdef LWIP_ALLOW_STATIC_FN_IN_HEADER static ip6_addr_t* ip_2_ip6(ip_addr_t *ipaddr) { return (ip6_addr_t*)ipaddr;} static ip_addr_t* ip6_2_ip(ip6_addr_t *ip6addr) { return (ip_addr_t*)ip6addr; } static ipX_addr_t* ip_2_ipX(ip_addr_t *ipaddr) { return (ipX_addr_t*)ipaddr; } static ipX_addr_t* ip6_2_ipX(ip6_addr_t *ip6addr) { return (ipX_addr_t*)ip6addr; } #else /* LWIP_ALLOW_STATIC_FN_IN_HEADER */ #define ip_2_ip6(ipaddr) ((ip6_addr_t*)(ipaddr)) #define ip6_2_ip(ip6addr) ((ip_addr_t*)(ip6addr)) #define ip_2_ipX(ipaddr) ((ipX_addr_t*)ipaddr) #define ip6_2_ipX(ip6addr) ((ipX_addr_t*)ip6addr) #endif /* LWIP_ALLOW_STATIC_FN_IN_HEADER*/ #define ipX_2_ip6(ip6addr) (&((ip6addr)->ip6)) #define ipX_2_ip(ipaddr) (&((ipaddr)->ip4)) #define ipX_addr_copy(is_ipv6, dest, src) do{if(is_ipv6){ \ ip6_addr_copy((dest).ip6, (src).ip6); }else{ \ ip_addr_copy((dest).ip4, (src).ip4); }}while(0) #define ipX_addr_set(is_ipv6, dest, src) do{if(is_ipv6){ \ ip6_addr_set(ipX_2_ip6(dest), ipX_2_ip6(src)); }else{ \ ip_addr_set(ipX_2_ip(dest), ipX_2_ip(src)); }}while(0) #define ipX_addr_set_ipaddr(is_ipv6, dest, src) do{if(is_ipv6){ \ ip6_addr_set(ipX_2_ip6(dest), ip_2_ip6(src)); }else{ \ ip_addr_set(ipX_2_ip(dest), src); }}while(0) #define ipX_addr_set_zero(is_ipv6, ipaddr) do{if(is_ipv6){ \ ip6_addr_set_zero(ipX_2_ip6(ipaddr)); }else{ \ ip_addr_set_zero(ipX_2_ip(ipaddr)); }}while(0) #define ipX_addr_set_any(is_ipv6, ipaddr) do{if(is_ipv6){ \ ip6_addr_set_any(ipX_2_ip6(ipaddr)); }else{ \ ip_addr_set_any(ipX_2_ip(ipaddr)); }}while(0) #define ipX_addr_set_loopback(is_ipv6, ipaddr) do{if(is_ipv6){ \ ip6_addr_set_loopback(ipX_2_ip6(ipaddr)); }else{ \ ip_addr_set_loopback(ipX_2_ip(ipaddr)); }}while(0) #define ipX_addr_set_hton(is_ipv6, dest, src) do{if(is_ipv6){ \ ip6_addr_set_hton(ipX_2_ip6(ipaddr), (src)) ;}else{ \ ip_addr_set_hton(ipX_2_ip(ipaddr), (src));}}while(0) #define ipX_addr_cmp(is_ipv6, addr1, addr2) ((is_ipv6) ? \ ip6_addr_cmp(ipX_2_ip6(addr1), ipX_2_ip6(addr2)) : \ ip_addr_cmp(ipX_2_ip(addr1), ipX_2_ip(addr2))) #define ipX_addr_isany(is_ipv6, ipaddr) ((is_ipv6) ? \ ip6_addr_isany(ipX_2_ip6(ipaddr)) : \ ip_addr_isany(ipX_2_ip(ipaddr))) #define ipX_addr_ismulticast(is_ipv6, ipaddr) ((is_ipv6) ? \ ip6_addr_ismulticast(ipX_2_ip6(ipaddr)) : \ ip_addr_ismulticast(ipX_2_ip(ipaddr))) #define ipX_addr_debug_print(is_ipv6, debug, ipaddr) do { if(is_ipv6) { \ ip6_addr_debug_print(debug, ipX_2_ip6(ipaddr)); } else { \ ip_addr_debug_print(debug, ipX_2_ip(ipaddr)); }}while(0) #else /* LWIP_IPV6 */ typedef ip_addr_t ipX_addr_t; #define ipX_2_ip(ipaddr) (ipaddr) #define ip_2_ipX(ipaddr) (ipaddr) #define ipX_addr_copy(is_ipv6, dest, src) ip_addr_copy(dest, src) #define ipX_addr_set(is_ipv6, dest, src) ip_addr_set(dest, src) #define ipX_addr_set_ipaddr(is_ipv6, dest, src) ip_addr_set(dest, src) #define ipX_addr_set_zero(is_ipv6, ipaddr) ip_addr_set_zero(ipaddr) #define ipX_addr_set_any(is_ipv6, ipaddr) ip_addr_set_any(ipaddr) #define ipX_addr_set_loopback(is_ipv6, ipaddr) ip_addr_set_loopback(ipaddr) #define ipX_addr_set_hton(is_ipv6, dest, src) ip_addr_set_hton(dest, src) #define ipX_addr_cmp(is_ipv6, addr1, addr2) ip_addr_cmp(addr1, addr2) #define ipX_addr_isany(is_ipv6, ipaddr) ip_addr_isany(ipaddr) #define ipX_addr_ismulticast(is_ipv6, ipaddr) ip_addr_ismulticast(ipaddr) #define ipX_addr_debug_print(is_ipv6, debug, ipaddr) ip_addr_debug_print(debug, ipaddr) #endif /* LWIP_IPV6 */ #ifdef __cplusplus } #endif #endif /* LWIP_HDR_IP_ADDR_H__ */ ocproxy-1.60/lwip/src/include/lwip/mem.h000066400000000000000000000100761303453231400202340ustar00rootroot00000000000000/* * Copyright (c) 2001-2004 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #ifndef LWIP_HDR_MEM_H #define LWIP_HDR_MEM_H #include "lwip/opt.h" #ifdef __cplusplus extern "C" { #endif #if MEM_LIBC_MALLOC #include /* for size_t */ typedef size_t mem_size_t; #define MEM_SIZE_F SZT_F /* aliases for C library malloc() */ #define mem_init() /* in case C library malloc() needs extra protection, * allow these defines to be overridden. */ #ifndef mem_free #define mem_free free #endif #ifndef mem_malloc #define mem_malloc malloc #endif #ifndef mem_calloc #define mem_calloc calloc #endif /* Since there is no C library allocation function to shrink memory without moving it, define this to nothing. */ #ifndef mem_trim #define mem_trim(mem, size) (mem) #endif #else /* MEM_LIBC_MALLOC */ /* MEM_SIZE would have to be aligned, but using 64000 here instead of * 65535 leaves some room for alignment... */ #if MEM_SIZE > 64000L typedef u32_t mem_size_t; #define MEM_SIZE_F U32_F #else typedef u16_t mem_size_t; #define MEM_SIZE_F U16_F #endif /* MEM_SIZE > 64000 */ #if MEM_USE_POOLS /** mem_init is not used when using pools instead of a heap */ #define mem_init() /** mem_trim is not used when using pools instead of a heap: we can't free part of a pool element and don't want to copy the rest */ #define mem_trim(mem, size) (mem) #else /* MEM_USE_POOLS */ /* lwIP alternative malloc */ void mem_init(void); void *mem_trim(void *mem, mem_size_t size); #endif /* MEM_USE_POOLS */ void *mem_malloc(mem_size_t size); void *mem_calloc(mem_size_t count, mem_size_t size); void mem_free(void *mem); #endif /* MEM_LIBC_MALLOC */ /** Calculate memory size for an aligned buffer - returns the next highest * multiple of MEM_ALIGNMENT (e.g. LWIP_MEM_ALIGN_SIZE(3) and * LWIP_MEM_ALIGN_SIZE(4) will both yield 4 for MEM_ALIGNMENT == 4). */ #ifndef LWIP_MEM_ALIGN_SIZE #define LWIP_MEM_ALIGN_SIZE(size) (((size) + MEM_ALIGNMENT - 1) & ~(MEM_ALIGNMENT-1)) #endif /** Calculate safe memory size for an aligned buffer when using an unaligned * type as storage. This includes a safety-margin on (MEM_ALIGNMENT - 1) at the * start (e.g. if buffer is u8_t[] and actual data will be u32_t*) */ #ifndef LWIP_MEM_ALIGN_BUFFER #define LWIP_MEM_ALIGN_BUFFER(size) (((size) + MEM_ALIGNMENT - 1)) #endif /** Align a memory pointer to the alignment defined by MEM_ALIGNMENT * so that ADDR % MEM_ALIGNMENT == 0 */ #ifndef LWIP_MEM_ALIGN #define LWIP_MEM_ALIGN(addr) ((void *)(((mem_ptr_t)(addr) + MEM_ALIGNMENT - 1) & ~(mem_ptr_t)(MEM_ALIGNMENT-1))) #endif #ifdef __cplusplus } #endif #endif /* LWIP_HDR_MEM_H */ ocproxy-1.60/lwip/src/include/lwip/memp.h000066400000000000000000000075471303453231400204250ustar00rootroot00000000000000/* * Copyright (c) 2001-2004 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #ifndef LWIP_HDR_MEMP_H #define LWIP_HDR_MEMP_H #include "lwip/opt.h" #ifdef __cplusplus extern "C" { #endif /* Create the list of all memory pools managed by memp. MEMP_MAX represents a NULL pool at the end */ typedef enum { #define LWIP_MEMPOOL(name,num,size,desc) MEMP_##name, #include "lwip/memp_std.h" MEMP_MAX } memp_t; #if MEM_USE_POOLS /* Use a helper type to get the start and end of the user "memory pools" for mem_malloc */ typedef enum { /* Get the first (via: MEMP_POOL_HELPER_START = ((u8_t) 1*MEMP_POOL_A + 0*MEMP_POOL_B + 0*MEMP_POOL_C + 0)*/ MEMP_POOL_HELPER_FIRST = ((u8_t) #define LWIP_MEMPOOL(name,num,size,desc) #define LWIP_MALLOC_MEMPOOL_START 1 #define LWIP_MALLOC_MEMPOOL(num, size) * MEMP_POOL_##size + 0 #define LWIP_MALLOC_MEMPOOL_END #include "lwip/memp_std.h" ) , /* Get the last (via: MEMP_POOL_HELPER_END = ((u8_t) 0 + MEMP_POOL_A*0 + MEMP_POOL_B*0 + MEMP_POOL_C*1) */ MEMP_POOL_HELPER_LAST = ((u8_t) #define LWIP_MEMPOOL(name,num,size,desc) #define LWIP_MALLOC_MEMPOOL_START #define LWIP_MALLOC_MEMPOOL(num, size) 0 + MEMP_POOL_##size * #define LWIP_MALLOC_MEMPOOL_END 1 #include "lwip/memp_std.h" ) } memp_pool_helper_t; /* The actual start and stop values are here (cast them over) We use this helper type and these defines so we can avoid using const memp_t values */ #define MEMP_POOL_FIRST ((memp_t) MEMP_POOL_HELPER_FIRST) #define MEMP_POOL_LAST ((memp_t) MEMP_POOL_HELPER_LAST) #endif /* MEM_USE_POOLS */ #if MEMP_MEM_MALLOC || MEM_USE_POOLS extern const u16_t memp_sizes[MEMP_MAX]; #endif /* MEMP_MEM_MALLOC || MEM_USE_POOLS */ #if MEMP_MEM_MALLOC #include "mem.h" #define memp_init() #define memp_malloc(type) mem_malloc(memp_sizes[type]) #define memp_free(type, mem) mem_free(mem) #else /* MEMP_MEM_MALLOC */ #if MEM_USE_POOLS /** This structure is used to save the pool one element came from. */ struct memp_malloc_helper { memp_t poolnr; }; #endif /* MEM_USE_POOLS */ void memp_init(void); #if MEMP_OVERFLOW_CHECK void *memp_malloc_fn(memp_t type, const char* file, const int line); #define memp_malloc(t) memp_malloc_fn((t), __FILE__, __LINE__) #else void *memp_malloc(memp_t type); #endif void memp_free(memp_t type, void *mem); #endif /* MEMP_MEM_MALLOC */ #ifdef __cplusplus } #endif #endif /* LWIP_HDR_MEMP_H */ ocproxy-1.60/lwip/src/include/lwip/memp_std.h000066400000000000000000000153661303453231400212750ustar00rootroot00000000000000/* * SETUP: Make sure we define everything we will need. * * We have create three types of pools: * 1) MEMPOOL - standard pools * 2) MALLOC_MEMPOOL - to be used by mem_malloc in mem.c * 3) PBUF_MEMPOOL - a mempool of pbuf's, so include space for the pbuf struct * * If the include'r doesn't require any special treatment of each of the types * above, then will declare #2 & #3 to be just standard mempools. */ #ifndef LWIP_MALLOC_MEMPOOL /* This treats "malloc pools" just like any other pool. The pools are a little bigger to provide 'size' as the amount of user data. */ #define LWIP_MALLOC_MEMPOOL(num, size) LWIP_MEMPOOL(POOL_##size, num, (size + LWIP_MEM_ALIGN_SIZE(sizeof(struct memp_malloc_helper))), "MALLOC_"#size) #define LWIP_MALLOC_MEMPOOL_START #define LWIP_MALLOC_MEMPOOL_END #endif /* LWIP_MALLOC_MEMPOOL */ #ifndef LWIP_PBUF_MEMPOOL /* This treats "pbuf pools" just like any other pool. * Allocates buffers for a pbuf struct AND a payload size */ #define LWIP_PBUF_MEMPOOL(name, num, payload, desc) LWIP_MEMPOOL(name, num, (MEMP_ALIGN_SIZE(sizeof(struct pbuf)) + MEMP_ALIGN_SIZE(payload)), desc) #endif /* LWIP_PBUF_MEMPOOL */ /* * A list of internal pools used by LWIP. * * LWIP_MEMPOOL(pool_name, number_elements, element_size, pool_description) * creates a pool name MEMP_pool_name. description is used in stats.c */ #if LWIP_RAW LWIP_MEMPOOL(RAW_PCB, MEMP_NUM_RAW_PCB, sizeof(struct raw_pcb), "RAW_PCB") #endif /* LWIP_RAW */ #if LWIP_UDP LWIP_MEMPOOL(UDP_PCB, MEMP_NUM_UDP_PCB, sizeof(struct udp_pcb), "UDP_PCB") #endif /* LWIP_UDP */ #if LWIP_TCP LWIP_MEMPOOL(TCP_PCB, MEMP_NUM_TCP_PCB, sizeof(struct tcp_pcb), "TCP_PCB") LWIP_MEMPOOL(TCP_PCB_LISTEN, MEMP_NUM_TCP_PCB_LISTEN, sizeof(struct tcp_pcb_listen), "TCP_PCB_LISTEN") LWIP_MEMPOOL(TCP_SEG, MEMP_NUM_TCP_SEG, sizeof(struct tcp_seg), "TCP_SEG") #endif /* LWIP_TCP */ #if IP_REASSEMBLY LWIP_MEMPOOL(REASSDATA, MEMP_NUM_REASSDATA, sizeof(struct ip_reassdata), "REASSDATA") #endif /* IP_REASSEMBLY */ #if (IP_FRAG && !IP_FRAG_USES_STATIC_BUF && !LWIP_NETIF_TX_SINGLE_PBUF) || LWIP_IPV6_FRAG LWIP_MEMPOOL(FRAG_PBUF, MEMP_NUM_FRAG_PBUF, sizeof(struct pbuf_custom_ref),"FRAG_PBUF") #endif /* IP_FRAG && !IP_FRAG_USES_STATIC_BUF && !LWIP_NETIF_TX_SINGLE_PBUF */ #if LWIP_NETCONN LWIP_MEMPOOL(NETBUF, MEMP_NUM_NETBUF, sizeof(struct netbuf), "NETBUF") LWIP_MEMPOOL(NETCONN, MEMP_NUM_NETCONN, sizeof(struct netconn), "NETCONN") #endif /* LWIP_NETCONN */ #if NO_SYS==0 LWIP_MEMPOOL(TCPIP_MSG_API, MEMP_NUM_TCPIP_MSG_API, sizeof(struct tcpip_msg), "TCPIP_MSG_API") #if LWIP_MPU_COMPATIBLE LWIP_MEMPOOL(API_MSG, MEMP_NUM_API_MSG, sizeof(struct api_msg), "API_MSG") #if LWIP_DNS LWIP_MEMPOOL(DNS_API_MSG, MEMP_NUM_DNS_API_MSG, sizeof(struct dns_api_msg), "DNS_API_MSG") #endif #if LWIP_SOCKET LWIP_MEMPOOL(SOCKET_SETGETSOCKOPT_DATA, MEMP_NUM_SOCKET_SETGETSOCKOPT_DATA, sizeof(struct lwip_setgetsockopt_data), "SOCKET_SETGETSOCKOPT_DATA") #endif #if LWIP_NETIF_API LWIP_MEMPOOL(NETIFAPI_MSG, MEMP_NUM_NETIFAPI_MSG, sizeof(struct netifapi_msg), "NETIFAPI_MSG") #endif #endif /* LWIP_MPU_COMPATIBLE */ #if !LWIP_TCPIP_CORE_LOCKING_INPUT LWIP_MEMPOOL(TCPIP_MSG_INPKT,MEMP_NUM_TCPIP_MSG_INPKT, sizeof(struct tcpip_msg), "TCPIP_MSG_INPKT") #endif /* !LWIP_TCPIP_CORE_LOCKING_INPUT */ #endif /* NO_SYS==0 */ #if LWIP_ARP && ARP_QUEUEING LWIP_MEMPOOL(ARP_QUEUE, MEMP_NUM_ARP_QUEUE, sizeof(struct etharp_q_entry), "ARP_QUEUE") #endif /* LWIP_ARP && ARP_QUEUEING */ #if LWIP_IGMP LWIP_MEMPOOL(IGMP_GROUP, MEMP_NUM_IGMP_GROUP, sizeof(struct igmp_group), "IGMP_GROUP") #endif /* LWIP_IGMP */ #if (!NO_SYS || (NO_SYS && !NO_SYS_NO_TIMERS)) /* LWIP_TIMERS */ LWIP_MEMPOOL(SYS_TIMEOUT, MEMP_NUM_SYS_TIMEOUT, sizeof(struct sys_timeo), "SYS_TIMEOUT") #endif /* LWIP_TIMERS */ #if LWIP_SNMP LWIP_MEMPOOL(SNMP_ROOTNODE, MEMP_NUM_SNMP_ROOTNODE, sizeof(struct mib_list_rootnode), "SNMP_ROOTNODE") LWIP_MEMPOOL(SNMP_NODE, MEMP_NUM_SNMP_NODE, sizeof(struct mib_list_node), "SNMP_NODE") LWIP_MEMPOOL(SNMP_VARBIND, MEMP_NUM_SNMP_VARBIND, sizeof(struct snmp_varbind), "SNMP_VARBIND") LWIP_MEMPOOL(SNMP_VALUE, MEMP_NUM_SNMP_VALUE, SNMP_MAX_VALUE_SIZE, "SNMP_VALUE") #endif /* LWIP_SNMP */ #if LWIP_DNS && LWIP_SOCKET LWIP_MEMPOOL(NETDB, MEMP_NUM_NETDB, NETDB_ELEM_SIZE, "NETDB") #endif /* LWIP_DNS && LWIP_SOCKET */ #if LWIP_DNS && DNS_LOCAL_HOSTLIST && DNS_LOCAL_HOSTLIST_IS_DYNAMIC LWIP_MEMPOOL(LOCALHOSTLIST, MEMP_NUM_LOCALHOSTLIST, LOCALHOSTLIST_ELEM_SIZE, "LOCALHOSTLIST") #endif /* LWIP_DNS && DNS_LOCAL_HOSTLIST && DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ #if PPP_SUPPORT LWIP_MEMPOOL(PPP_PCB, MEMP_NUM_PPP_PCB, sizeof(ppp_pcb), "PPP_PCB") #if PPPOE_SUPPORT LWIP_MEMPOOL(PPPOE_IF, MEMP_NUM_PPPOE_INTERFACES, sizeof(struct pppoe_softc), "PPPOE_IF") #endif /* PPPOE_SUPPORT */ #if PPPOL2TP_SUPPORT LWIP_MEMPOOL(PPPOL2TP_PCB, MEMP_NUM_PPPOL2TP_INTERFACES, sizeof(pppol2tp_pcb), "PPPOL2TP_PCB") #endif /* PPPOL2TP_SUPPORT */ #endif /* PPP_SUPPORT */ #if LWIP_IPV6 && LWIP_ND6_QUEUEING LWIP_MEMPOOL(ND6_QUEUE, MEMP_NUM_ND6_QUEUE, sizeof(struct nd6_q_entry), "ND6_QUEUE") #endif /* LWIP_IPV6 && LWIP_ND6_QUEUEING */ #if LWIP_IPV6 && LWIP_IPV6_REASS LWIP_MEMPOOL(IP6_REASSDATA, MEMP_NUM_REASSDATA, sizeof(struct ip6_reassdata), "IP6_REASSDATA") #endif /* LWIP_IPV6 && LWIP_IPV6_REASS */ #if LWIP_IPV6 && LWIP_IPV6_MLD LWIP_MEMPOOL(MLD6_GROUP, MEMP_NUM_MLD6_GROUP, sizeof(struct mld_group), "MLD6_GROUP") #endif /* LWIP_IPV6 && LWIP_IPV6_MLD */ /* * A list of pools of pbuf's used by LWIP. * * LWIP_PBUF_MEMPOOL(pool_name, number_elements, pbuf_payload_size, pool_description) * creates a pool name MEMP_pool_name. description is used in stats.c * This allocates enough space for the pbuf struct and a payload. * (Example: pbuf_payload_size=0 allocates only size for the struct) */ LWIP_PBUF_MEMPOOL(PBUF, MEMP_NUM_PBUF, 0, "PBUF_REF/ROM") LWIP_PBUF_MEMPOOL(PBUF_POOL, PBUF_POOL_SIZE, PBUF_POOL_BUFSIZE, "PBUF_POOL") /* * Allow for user-defined pools; this must be explicitly set in lwipopts.h * since the default is to NOT look for lwippools.h */ #if MEMP_USE_CUSTOM_POOLS #include "lwippools.h" #endif /* MEMP_USE_CUSTOM_POOLS */ /* * REQUIRED CLEANUP: Clear up so we don't get "multiply defined" error later * (#undef is ignored for something that is not defined) */ #undef LWIP_MEMPOOL #undef LWIP_MALLOC_MEMPOOL #undef LWIP_MALLOC_MEMPOOL_START #undef LWIP_MALLOC_MEMPOOL_END #undef LWIP_PBUF_MEMPOOL ocproxy-1.60/lwip/src/include/lwip/netbuf.h000066400000000000000000000110571303453231400207410ustar00rootroot00000000000000/* * Copyright (c) 2001-2004 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #ifndef LWIP_HDR_NETBUF_H #define LWIP_HDR_NETBUF_H #include "lwip/opt.h" #include "lwip/pbuf.h" #include "lwip/ip_addr.h" #include "lwip/ip6_addr.h" #ifdef __cplusplus extern "C" { #endif /** This netbuf has dest-addr/port set */ #define NETBUF_FLAG_DESTADDR 0x01 /** This netbuf includes a checksum */ #define NETBUF_FLAG_CHKSUM 0x02 struct netbuf { struct pbuf *p, *ptr; ipX_addr_t addr; u16_t port; #if LWIP_NETBUF_RECVINFO || LWIP_CHECKSUM_ON_COPY #if LWIP_CHECKSUM_ON_COPY u8_t flags; #endif /* LWIP_CHECKSUM_ON_COPY */ u16_t toport_chksum; #if LWIP_NETBUF_RECVINFO ipX_addr_t toaddr; #endif /* LWIP_NETBUF_RECVINFO */ #endif /* LWIP_NETBUF_RECVINFO || LWIP_CHECKSUM_ON_COPY */ }; /* Network buffer functions: */ struct netbuf * netbuf_new (void); void netbuf_delete (struct netbuf *buf); void * netbuf_alloc (struct netbuf *buf, u16_t size); void netbuf_free (struct netbuf *buf); err_t netbuf_ref (struct netbuf *buf, const void *dataptr, u16_t size); void netbuf_chain (struct netbuf *head, struct netbuf *tail); err_t netbuf_data (struct netbuf *buf, void **dataptr, u16_t *len); s8_t netbuf_next (struct netbuf *buf); void netbuf_first (struct netbuf *buf); #define netbuf_copy_partial(buf, dataptr, len, offset) \ pbuf_copy_partial((buf)->p, (dataptr), (len), (offset)) #define netbuf_copy(buf,dataptr,len) netbuf_copy_partial(buf, dataptr, len, 0) #define netbuf_take(buf, dataptr, len) pbuf_take((buf)->p, dataptr, len) #define netbuf_len(buf) ((buf)->p->tot_len) #define netbuf_fromaddr(buf) (ipX_2_ip(&((buf)->addr))) #define netbuf_set_fromaddr(buf, fromaddr) ip_addr_set(ipX_2_ip(&((buf)->addr)), fromaddr) #define netbuf_fromport(buf) ((buf)->port) #if LWIP_NETBUF_RECVINFO #define netbuf_destaddr(buf) (ipX_2_ip(&((buf)->toaddr))) #define netbuf_set_destaddr(buf, destaddr) ip_addr_set(ipX_2_ip(&((buf)->toaddr)), destaddr) #define netbuf_destport(buf) (((buf)->flags & NETBUF_FLAG_DESTADDR) ? (buf)->toport_chksum : 0) #endif /* LWIP_NETBUF_RECVINFO */ #if LWIP_CHECKSUM_ON_COPY #define netbuf_set_chksum(buf, chksum) do { (buf)->flags = NETBUF_FLAG_CHKSUM; \ (buf)->toport_chksum = chksum; } while(0) #endif /* LWIP_CHECKSUM_ON_COPY */ #if LWIP_IPV6 #define netbuf_fromaddr_ip6(buf) (ipX_2_ip6(&((buf)->addr))) #define netbuf_set_fromaddr_ip6(buf, fromaddr) ip6_addr_set(ipX_2_ip6(&((buf)->addr)), fromaddr) #define netbuf_destaddr_ip6(buf) (ipX_2_ip6(&((buf)->toaddr))) #define netbuf_set_destaddr_ip6(buf, destaddr) ip6_addr_set(ipX_2_ip6(&((buf)->toaddr)), destaddr) #endif /* LWIP_IPV6 */ #define netbuf_fromaddr_ipX(buf) (&((buf)->addr)) #define netbuf_destaddr_ipX(buf) (&((buf)->toaddr)) #ifdef __cplusplus } #endif #endif /* LWIP_HDR_NETBUF_H */ ocproxy-1.60/lwip/src/include/lwip/netdb.h000066400000000000000000000110551303453231400205500ustar00rootroot00000000000000/* * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Simon Goldschmidt * */ #ifndef LWIP_HDR_NETDB_H #define LWIP_HDR_NETDB_H #include "lwip/opt.h" #if LWIP_DNS && LWIP_SOCKET #include /* for size_t */ #include "lwip/inet.h" #include "lwip/sockets.h" #ifdef __cplusplus extern "C" { #endif /* some rarely used options */ #ifndef LWIP_DNS_API_DECLARE_H_ERRNO #define LWIP_DNS_API_DECLARE_H_ERRNO 1 #endif #ifndef LWIP_DNS_API_DEFINE_ERRORS #define LWIP_DNS_API_DEFINE_ERRORS 1 #endif #ifndef LWIP_DNS_API_DECLARE_STRUCTS #define LWIP_DNS_API_DECLARE_STRUCTS 1 #endif #if LWIP_DNS_API_DEFINE_ERRORS /** Errors used by the DNS API functions, h_errno can be one of them */ #define EAI_NONAME 200 #define EAI_SERVICE 201 #define EAI_FAIL 202 #define EAI_MEMORY 203 #define HOST_NOT_FOUND 210 #define NO_DATA 211 #define NO_RECOVERY 212 #define TRY_AGAIN 213 #endif /* LWIP_DNS_API_DEFINE_ERRORS */ #if LWIP_DNS_API_DECLARE_STRUCTS struct hostent { char *h_name; /* Official name of the host. */ char **h_aliases; /* A pointer to an array of pointers to alternative host names, terminated by a null pointer. */ int h_addrtype; /* Address type. */ int h_length; /* The length, in bytes, of the address. */ char **h_addr_list; /* A pointer to an array of pointers to network addresses (in network byte order) for the host, terminated by a null pointer. */ #define h_addr h_addr_list[0] /* for backward compatibility */ }; struct addrinfo { int ai_flags; /* Input flags. */ int ai_family; /* Address family of socket. */ int ai_socktype; /* Socket type. */ int ai_protocol; /* Protocol of socket. */ socklen_t ai_addrlen; /* Length of socket address. */ struct sockaddr *ai_addr; /* Socket address of socket. */ char *ai_canonname; /* Canonical name of service location. */ struct addrinfo *ai_next; /* Pointer to next in list. */ }; #endif /* LWIP_DNS_API_DECLARE_STRUCTS */ #if LWIP_DNS_API_DECLARE_H_ERRNO /* application accessable error code set by the DNS API functions */ extern int h_errno; #endif /* LWIP_DNS_API_DECLARE_H_ERRNO*/ struct hostent *lwip_gethostbyname(const char *name); int lwip_gethostbyname_r(const char *name, struct hostent *ret, char *buf, size_t buflen, struct hostent **result, int *h_errnop); void lwip_freeaddrinfo(struct addrinfo *ai); int lwip_getaddrinfo(const char *nodename, const char *servname, const struct addrinfo *hints, struct addrinfo **res); #if LWIP_COMPAT_SOCKETS #define gethostbyname(name) lwip_gethostbyname(name) #define gethostbyname_r(name, ret, buf, buflen, result, h_errnop) \ lwip_gethostbyname_r(name, ret, buf, buflen, result, h_errnop) #define freeaddrinfo(addrinfo) lwip_freeaddrinfo(addrinfo) #define getaddrinfo(nodname, servname, hints, res) \ lwip_getaddrinfo(nodname, servname, hints, res) #endif /* LWIP_COMPAT_SOCKETS */ #ifdef __cplusplus } #endif #endif /* LWIP_DNS && LWIP_SOCKET */ #endif /* LWIP_HDR_NETDB_H */ ocproxy-1.60/lwip/src/include/lwip/netif.h000066400000000000000000000347151303453231400205710ustar00rootroot00000000000000/* * Copyright (c) 2001-2004 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #ifndef LWIP_HDR_NETIF_H #define LWIP_HDR_NETIF_H #include "lwip/opt.h" #define ENABLE_LOOPBACK (LWIP_NETIF_LOOPBACK || LWIP_HAVE_LOOPIF) #include "lwip/err.h" #include "lwip/ip_addr.h" #include "lwip/ip6_addr.h" #include "lwip/def.h" #include "lwip/pbuf.h" #if LWIP_DHCP struct dhcp; #endif #if LWIP_AUTOIP struct autoip; #endif #if LWIP_IPV6_DHCP6 #include "lwip/dhcp6.h" #endif /* LWIP_IPV6_DHCP6 */ #ifdef __cplusplus extern "C" { #endif /* Throughout this file, IP addresses are expected to be in * the same byte order as in IP_PCB. */ /** must be the maximum of all used hardware address lengths across all types of interfaces in use */ #define NETIF_MAX_HWADDR_LEN 6U /** Whether the network interface is 'up'. This is * a software flag used to control whether this network * interface is enabled and processes traffic. * It is set by the startup code (for static IP configuration) or * by dhcp/autoip when an address has been assigned. */ #define NETIF_FLAG_UP 0x01U /** If set, the netif has broadcast capability. * Set by the netif driver in its init function. */ #define NETIF_FLAG_BROADCAST 0x02U /** If set, the netif is one end of a point-to-point connection. * Set by the netif driver in its init function. */ #define NETIF_FLAG_POINTTOPOINT 0x04U /** If set, the interface is configured using DHCP. * Set by the DHCP code when starting or stopping DHCP. */ #define NETIF_FLAG_DHCP 0x08U /** If set, the interface has an active link * (set by the network interface driver). * Either set by the netif driver in its init function (if the link * is up at that time) or at a later point once the link comes up * (if link detection is supported by the hardware). */ #define NETIF_FLAG_LINK_UP 0x10U /** If set, the netif is an ethernet device using ARP. * Set by the netif driver in its init function. * Used to check input packet types and use of DHCP. */ #define NETIF_FLAG_ETHARP 0x20U /** If set, the netif is an ethernet device. It might not use * ARP or TCP/IP if it is used for PPPoE only. */ #define NETIF_FLAG_ETHERNET 0x40U /** If set, the netif has IGMP capability. * Set by the netif driver in its init function. */ #define NETIF_FLAG_IGMP 0x80U /** Function prototype for netif init functions. Set up flags and output/linkoutput * callback functions in this function. * * @param netif The netif to initialize */ typedef err_t (*netif_init_fn)(struct netif *netif); /** Function prototype for netif->input functions. This function is saved as 'input' * callback function in the netif struct. Call it when a packet has been received. * * @param p The received packet, copied into a pbuf * @param inp The netif which received the packet */ typedef err_t (*netif_input_fn)(struct pbuf *p, struct netif *inp); /** Function prototype for netif->output functions. Called by lwIP when a packet * shall be sent. For ethernet netif, set this to 'etharp_output' and set * 'linkoutput'. * * @param netif The netif which shall send a packet * @param p The packet to send (p->payload points to IP header) * @param ipaddr The IP address to which the packet shall be sent */ typedef err_t (*netif_output_fn)(struct netif *netif, struct pbuf *p, ip_addr_t *ipaddr); #if LWIP_IPV6 /** Function prototype for netif->output_ip6 functions. Called by lwIP when a packet * shall be sent. For ethernet netif, set this to 'ethip6_output' and set * 'linkoutput'. * * @param netif The netif which shall send a packet * @param p The packet to send (p->payload points to IP header) * @param ipaddr The IPv6 address to which the packet shall be sent */ typedef err_t (*netif_output_ip6_fn)(struct netif *netif, struct pbuf *p, ip6_addr_t *ipaddr); #endif /* LWIP_IPV6 */ /** Function prototype for netif->linkoutput functions. Only used for ethernet * netifs. This function is called by ARP when a packet shall be sent. * * @param netif The netif which shall send a packet * @param p The packet to send (raw ethernet packet) */ typedef err_t (*netif_linkoutput_fn)(struct netif *netif, struct pbuf *p); /** Function prototype for netif status- or link-callback functions. */ typedef void (*netif_status_callback_fn)(struct netif *netif); /** Function prototype for netif igmp_mac_filter functions */ typedef err_t (*netif_igmp_mac_filter_fn)(struct netif *netif, ip_addr_t *group, u8_t action); #if LWIP_IPV6 && LWIP_IPV6_MLD /** Function prototype for netif mld_mac_filter functions */ typedef err_t (*netif_mld_mac_filter_fn)(struct netif *netif, ip6_addr_t *group, u8_t action); #endif /* LWIP_IPV6 && LWIP_IPV6_MLD */ /** Generic data structure used for all lwIP network interfaces. * The following fields should be filled in by the initialization * function for the device driver: hwaddr_len, hwaddr[], mtu, flags */ struct netif { /** pointer to next in linked list */ struct netif *next; /** IP address configuration in network byte order */ ip_addr_t ip_addr; ip_addr_t netmask; ip_addr_t gw; #if LWIP_IPV6 /** Array of IPv6 addresses for this netif. */ ip6_addr_t ip6_addr[LWIP_IPV6_NUM_ADDRESSES]; /** The state of each IPv6 address (Tentative, Preferred, etc). * @see ip6_addr.h */ u8_t ip6_addr_state[LWIP_IPV6_NUM_ADDRESSES]; #endif /* LWIP_IPV6 */ /** This function is called by the network device driver * to pass a packet up the TCP/IP stack. */ netif_input_fn input; /** This function is called by the IP module when it wants * to send a packet on the interface. This function typically * first resolves the hardware address, then sends the packet. */ netif_output_fn output; /** This function is called by the ARP module when it wants * to send a packet on the interface. This function outputs * the pbuf as-is on the link medium. */ netif_linkoutput_fn linkoutput; #if LWIP_IPV6 /** This function is called by the IPv6 module when it wants * to send a packet on the interface. This function typically * first resolves the hardware address, then sends the packet. */ netif_output_ip6_fn output_ip6; #endif /* LWIP_IPV6 */ #if LWIP_NETIF_STATUS_CALLBACK /** This function is called when the netif state is set to up or down */ netif_status_callback_fn status_callback; #endif /* LWIP_NETIF_STATUS_CALLBACK */ #if LWIP_NETIF_LINK_CALLBACK /** This function is called when the netif link is set to up or down */ netif_status_callback_fn link_callback; #endif /* LWIP_NETIF_LINK_CALLBACK */ #if LWIP_NETIF_REMOVE_CALLBACK /** This function is called when the netif has been removed */ netif_status_callback_fn remove_callback; #endif /* LWIP_NETIF_REMOVE_CALLBACK */ /** This field can be set by the device driver and could point * to state information for the device. */ void *state; #if LWIP_DHCP /** the DHCP client state information for this netif */ struct dhcp *dhcp; #endif /* LWIP_DHCP */ #if LWIP_AUTOIP /** the AutoIP client state information for this netif */ struct autoip *autoip; #endif #if LWIP_IPV6_AUTOCONFIG /** is this netif enabled for IPv6 autoconfiguration */ u8_t ip6_autoconfig_enabled; #endif /* LWIP_IPV6_AUTOCONFIG */ #if LWIP_IPV6_SEND_ROUTER_SOLICIT /** Number of Router Solicitation messages that remain to be sent. */ u8_t rs_count; #endif /* LWIP_IPV6_SEND_ROUTER_SOLICIT */ #if LWIP_IPV6_DHCP6 /** the DHCPv6 client state information for this netif */ struct dhcp6 *dhcp6; #endif /* LWIP_IPV6_DHCP6 */ #if LWIP_NETIF_HOSTNAME /* the hostname for this netif, NULL is a valid value */ char* hostname; #endif /* LWIP_NETIF_HOSTNAME */ /** maximum transfer unit (in bytes) */ u16_t mtu; /** number of bytes used in hwaddr */ u8_t hwaddr_len; /** link level hardware address of this interface */ u8_t hwaddr[NETIF_MAX_HWADDR_LEN]; /** flags (see NETIF_FLAG_ above) */ u8_t flags; /** descriptive abbreviation */ char name[2]; /** number of this interface */ u8_t num; #if LWIP_SNMP /** link type (from "snmp_ifType" enum from snmp.h) */ u8_t link_type; /** (estimate) link speed */ u32_t link_speed; /** timestamp at last change made (up/down) */ u32_t ts; /** counters */ u32_t ifinoctets; u32_t ifinucastpkts; u32_t ifinnucastpkts; u32_t ifindiscards; u32_t ifoutoctets; u32_t ifoutucastpkts; u32_t ifoutnucastpkts; u32_t ifoutdiscards; #endif /* LWIP_SNMP */ #if LWIP_IGMP /** This function could be called to add or delete an entry in the multicast filter table of the ethernet MAC.*/ netif_igmp_mac_filter_fn igmp_mac_filter; #endif /* LWIP_IGMP */ #if LWIP_IPV6 && LWIP_IPV6_MLD /** This function could be called to add or delete an entry in the IPv6 multicast filter table of the ethernet MAC. */ netif_mld_mac_filter_fn mld_mac_filter; #endif /* LWIP_IPV6 && LWIP_IPV6_MLD */ #if LWIP_NETIF_HWADDRHINT u8_t *addr_hint; #endif /* LWIP_NETIF_HWADDRHINT */ #if ENABLE_LOOPBACK /* List of packets to be queued for ourselves. */ struct pbuf *loop_first; struct pbuf *loop_last; #if LWIP_LOOPBACK_MAX_PBUFS u16_t loop_cnt_current; #endif /* LWIP_LOOPBACK_MAX_PBUFS */ #endif /* ENABLE_LOOPBACK */ }; #if LWIP_SNMP #define NETIF_INIT_SNMP(netif, type, speed) \ /* use "snmp_ifType" enum from snmp.h for "type", snmp_ifType_ethernet_csmacd by example */ \ (netif)->link_type = (type); \ /* your link speed here (units: bits per second) */ \ (netif)->link_speed = (speed); \ (netif)->ts = 0; \ (netif)->ifinoctets = 0; \ (netif)->ifinucastpkts = 0; \ (netif)->ifinnucastpkts = 0; \ (netif)->ifindiscards = 0; \ (netif)->ifoutoctets = 0; \ (netif)->ifoutucastpkts = 0; \ (netif)->ifoutnucastpkts = 0; \ (netif)->ifoutdiscards = 0 #else /* LWIP_SNMP */ #define NETIF_INIT_SNMP(netif, type, speed) #endif /* LWIP_SNMP */ /** The list of network interfaces. */ extern struct netif *netif_list; /** The default network interface. */ extern struct netif *netif_default; void netif_init(void); struct netif *netif_add(struct netif *netif, ip_addr_t *ipaddr, ip_addr_t *netmask, ip_addr_t *gw, void *state, netif_init_fn init, netif_input_fn input); void netif_set_addr(struct netif *netif, ip_addr_t *ipaddr, ip_addr_t *netmask, ip_addr_t *gw); void netif_remove(struct netif * netif); /* Returns a network interface given its name. The name is of the form "et0", where the first two letters are the "name" field in the netif structure, and the digit is in the num field in the same structure. */ struct netif *netif_find(char *name); void netif_set_default(struct netif *netif); void netif_set_ipaddr(struct netif *netif, ip_addr_t *ipaddr); void netif_set_netmask(struct netif *netif, ip_addr_t *netmask); void netif_set_gw(struct netif *netif, ip_addr_t *gw); void netif_set_up(struct netif *netif); void netif_set_down(struct netif *netif); /** Ask if an interface is up */ #define netif_is_up(netif) (((netif)->flags & NETIF_FLAG_UP) ? (u8_t)1 : (u8_t)0) #if LWIP_NETIF_STATUS_CALLBACK void netif_set_status_callback(struct netif *netif, netif_status_callback_fn status_callback); #endif /* LWIP_NETIF_STATUS_CALLBACK */ #if LWIP_NETIF_REMOVE_CALLBACK void netif_set_remove_callback(struct netif *netif, netif_status_callback_fn remove_callback); #endif /* LWIP_NETIF_REMOVE_CALLBACK */ void netif_set_link_up(struct netif *netif); void netif_set_link_down(struct netif *netif); /** Ask if a link is up */ #define netif_is_link_up(netif) (((netif)->flags & NETIF_FLAG_LINK_UP) ? (u8_t)1 : (u8_t)0) #if LWIP_NETIF_LINK_CALLBACK void netif_set_link_callback(struct netif *netif, netif_status_callback_fn link_callback); #endif /* LWIP_NETIF_LINK_CALLBACK */ #if LWIP_NETIF_HOSTNAME #define netif_set_hostname(netif, name) do { if((netif) != NULL) { (netif)->hostname = name; }}while(0) #define netif_get_hostname(netif) (((netif) != NULL) ? ((netif)->hostname) : NULL) #endif /* LWIP_NETIF_HOSTNAME */ #if LWIP_IGMP #define netif_set_igmp_mac_filter(netif, function) do { if((netif) != NULL) { (netif)->igmp_mac_filter = function; }}while(0) #define netif_get_igmp_mac_filter(netif) (((netif) != NULL) ? ((netif)->igmp_mac_filter) : NULL) #endif /* LWIP_IGMP */ #if ENABLE_LOOPBACK err_t netif_loop_output(struct netif *netif, struct pbuf *p); void netif_poll(struct netif *netif); #if !LWIP_NETIF_LOOPBACK_MULTITHREADING void netif_poll_all(void); #endif /* !LWIP_NETIF_LOOPBACK_MULTITHREADING */ #endif /* ENABLE_LOOPBACK */ #if LWIP_IPV6 #define netif_ip6_addr(netif, i) (&((netif)->ip6_addr[(i)])) #define netif_ip6_addr_state(netif, i) ((netif)->ip6_addr_state[(i)]) #define netif_ip6_addr_set_state(netif, i, state) ((netif)->ip6_addr_state[(i)] = (state)) s8_t netif_get_ip6_addr_match(struct netif * netif, ip6_addr_t * ip6addr); void netif_create_ip6_linklocal_address(struct netif * netif, u8_t from_mac_48bit); #endif /* LWIP_IPV6 */ #if LWIP_NETIF_HWADDRHINT #define NETIF_SET_HWADDRHINT(netif, hint) ((netif)->addr_hint = (hint)) #else /* LWIP_NETIF_HWADDRHINT */ #define NETIF_SET_HWADDRHINT(netif, hint) #endif /* LWIP_NETIF_HWADDRHINT */ #ifdef __cplusplus } #endif #endif /* LWIP_HDR_NETIF_H */ ocproxy-1.60/lwip/src/include/lwip/netifapi.h000066400000000000000000000104771303453231400212620ustar00rootroot00000000000000/* * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * */ #ifndef LWIP_HDR_NETIFAPI_H #define LWIP_HDR_NETIFAPI_H #include "lwip/opt.h" #if LWIP_NETIF_API /* don't build if not configured for use in lwipopts.h */ #include "lwip/sys.h" #include "lwip/netif.h" #include "lwip/dhcp.h" #include "lwip/autoip.h" #ifdef __cplusplus extern "C" { #endif #if LWIP_MPU_COMPATIBLE #define NETIFAPI_IPADDR_DEF(m) m #else /* LWIP_MPU_COMPATIBLE */ #define NETIFAPI_IPADDR_DEF(m) *m #endif /* LWIP_MPU_COMPATIBLE */ typedef void (*netifapi_void_fn)(struct netif *netif); typedef err_t (*netifapi_errt_fn)(struct netif *netif); struct netifapi_msg_msg { #if !LWIP_TCPIP_CORE_LOCKING sys_sem_t sem; #endif /* !LWIP_TCPIP_CORE_LOCKING */ err_t err; struct netif *netif; union { struct { ip_addr_t NETIFAPI_IPADDR_DEF(ipaddr); ip_addr_t NETIFAPI_IPADDR_DEF(netmask); ip_addr_t NETIFAPI_IPADDR_DEF(gw); void *state; netif_init_fn init; netif_input_fn input; } add; struct { netifapi_void_fn voidfunc; netifapi_errt_fn errtfunc; } common; } msg; }; struct netifapi_msg { void (* function)(struct netifapi_msg_msg *msg); struct netifapi_msg_msg msg; }; /* API for application */ err_t netifapi_netif_add ( struct netif *netif, ip_addr_t *ipaddr, ip_addr_t *netmask, ip_addr_t *gw, void *state, netif_init_fn init, netif_input_fn input); err_t netifapi_netif_set_addr ( struct netif *netif, ip_addr_t *ipaddr, ip_addr_t *netmask, ip_addr_t *gw ); err_t netifapi_netif_common ( struct netif *netif, netifapi_void_fn voidfunc, netifapi_errt_fn errtfunc); #define netifapi_netif_remove(n) netifapi_netif_common(n, netif_remove, NULL) #define netifapi_netif_set_up(n) netifapi_netif_common(n, netif_set_up, NULL) #define netifapi_netif_set_down(n) netifapi_netif_common(n, netif_set_down, NULL) #define netifapi_netif_set_default(n) netifapi_netif_common(n, netif_set_default, NULL) #define netifapi_dhcp_start(n) netifapi_netif_common(n, NULL, dhcp_start) #define netifapi_dhcp_stop(n) netifapi_netif_common(n, dhcp_stop, NULL) #define netifapi_dhcp_inform(n) netifapi_netif_common(n, dhcp_inform, NULL) #define netifapi_dhcp_renew(n) netifapi_netif_common(n, NULL, dhcp_renew) #define netifapi_dhcp_release(n) netifapi_netif_common(n, NULL, dhcp_release) #define netifapi_autoip_start(n) netifapi_netif_common(n, NULL, autoip_start) #define netifapi_autoip_stop(n) netifapi_netif_common(n, NULL, autoip_stop) #ifdef __cplusplus } #endif #endif /* LWIP_NETIF_API */ #endif /* LWIP_HDR_NETIFAPI_H */ ocproxy-1.60/lwip/src/include/lwip/opt.h000066400000000000000000002223201303453231400202550ustar00rootroot00000000000000/** * @file * * lwIP Options Configuration */ /* * Copyright (c) 2001-2004 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #ifndef LWIP_HDR_OPT_H #define LWIP_HDR_OPT_H /* * Include user defined options first. Anything not defined in these files * will be set to standard values. Override anything you dont like! */ #include "lwipopts.h" #include "lwip/debug.h" /* ----------------------------------------------- ---------- Platform specific locking ---------- ----------------------------------------------- */ /** * SYS_LIGHTWEIGHT_PROT==1: if you want inter-task protection for certain * critical regions during buffer allocation, deallocation and memory * allocation and deallocation. */ #ifndef SYS_LIGHTWEIGHT_PROT #define SYS_LIGHTWEIGHT_PROT 0 #endif /** * NO_SYS==1: Provides VERY minimal functionality. Otherwise, * use lwIP facilities. */ #ifndef NO_SYS #define NO_SYS 0 #endif /** * NO_SYS_NO_TIMERS==1: Drop support for sys_timeout when NO_SYS==1 * Mainly for compatibility to old versions. */ #ifndef NO_SYS_NO_TIMERS #define NO_SYS_NO_TIMERS 0 #endif /** * MEMCPY: override this if you have a faster implementation at hand than the * one included in your C library */ #ifndef MEMCPY #define MEMCPY(dst,src,len) memcpy(dst,src,len) #endif /** * SMEMCPY: override this with care! Some compilers (e.g. gcc) can inline a * call to memcpy() if the length is known at compile time and is small. */ #ifndef SMEMCPY #define SMEMCPY(dst,src,len) memcpy(dst,src,len) #endif /** * LWIP_MPU_COMPATIBLE: enables special memory management mechanism * which makes lwip able to work on MPU (Memory Protection Unit) system * by not passing stack-pointers to other threads * (this decreases performance) */ #ifndef LWIP_MPU_COMPATIBLE #define LWIP_MPU_COMPATIBLE 0 #endif /* ------------------------------------ ---------- Memory options ---------- ------------------------------------ */ /** * MEM_LIBC_MALLOC==1: Use malloc/free/realloc provided by your C-library * instead of the lwip internal allocator. Can save code size if you * already use it. */ #ifndef MEM_LIBC_MALLOC #define MEM_LIBC_MALLOC 0 #endif /** * MEMP_MEM_MALLOC==1: Use mem_malloc/mem_free instead of the lwip pool allocator. * Especially useful with MEM_LIBC_MALLOC but handle with care regarding execution * speed and usage from interrupts! */ #ifndef MEMP_MEM_MALLOC #define MEMP_MEM_MALLOC 0 #endif /** * MEM_ALIGNMENT: should be set to the alignment of the CPU * 4 byte alignment -> #define MEM_ALIGNMENT 4 * 2 byte alignment -> #define MEM_ALIGNMENT 2 */ #ifndef MEM_ALIGNMENT #define MEM_ALIGNMENT 1 #endif /** * MEM_SIZE: the size of the heap memory. If the application will send * a lot of data that needs to be copied, this should be set high. */ #ifndef MEM_SIZE #define MEM_SIZE 1600 #endif /** * MEMP_SEPARATE_POOLS: if defined to 1, each pool is placed in its own array. * This can be used to individually change the location of each pool. * Default is one big array for all pools */ #ifndef MEMP_SEPARATE_POOLS #define MEMP_SEPARATE_POOLS 0 #endif /** * MEMP_OVERFLOW_CHECK: memp overflow protection reserves a configurable * amount of bytes before and after each memp element in every pool and fills * it with a prominent default value. * MEMP_OVERFLOW_CHECK == 0 no checking * MEMP_OVERFLOW_CHECK == 1 checks each element when it is freed * MEMP_OVERFLOW_CHECK >= 2 checks each element in every pool every time * memp_malloc() or memp_free() is called (useful but slow!) */ #ifndef MEMP_OVERFLOW_CHECK #define MEMP_OVERFLOW_CHECK 0 #endif /** * MEMP_SANITY_CHECK==1: run a sanity check after each memp_free() to make * sure that there are no cycles in the linked lists. */ #ifndef MEMP_SANITY_CHECK #define MEMP_SANITY_CHECK 0 #endif /** * MEM_USE_POOLS==1: Use an alternative to malloc() by allocating from a set * of memory pools of various sizes. When mem_malloc is called, an element of * the smallest pool that can provide the length needed is returned. * To use this, MEMP_USE_CUSTOM_POOLS also has to be enabled. */ #ifndef MEM_USE_POOLS #define MEM_USE_POOLS 0 #endif /** * MEM_USE_POOLS_TRY_BIGGER_POOL==1: if one malloc-pool is empty, try the next * bigger pool - WARNING: THIS MIGHT WASTE MEMORY but it can make a system more * reliable. */ #ifndef MEM_USE_POOLS_TRY_BIGGER_POOL #define MEM_USE_POOLS_TRY_BIGGER_POOL 0 #endif /** * MEMP_USE_CUSTOM_POOLS==1: whether to include a user file lwippools.h * that defines additional pools beyond the "standard" ones required * by lwIP. If you set this to 1, you must have lwippools.h in your * inlude path somewhere. */ #ifndef MEMP_USE_CUSTOM_POOLS #define MEMP_USE_CUSTOM_POOLS 0 #endif /** * Set this to 1 if you want to free PBUF_RAM pbufs (or call mem_free()) from * interrupt context (or another context that doesn't allow waiting for a * semaphore). * If set to 1, mem_malloc will be protected by a semaphore and SYS_ARCH_PROTECT, * while mem_free will only use SYS_ARCH_PROTECT. mem_malloc SYS_ARCH_UNPROTECTs * with each loop so that mem_free can run. * * ATTENTION: As you can see from the above description, this leads to dis-/ * enabling interrupts often, which can be slow! Also, on low memory, mem_malloc * can need longer. * * If you don't want that, at least for NO_SYS=0, you can still use the following * functions to enqueue a deallocation call which then runs in the tcpip_thread * context: * - pbuf_free_callback(p); * - mem_free_callback(m); */ #ifndef LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT #define LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT 0 #endif /* ------------------------------------------------ ---------- Internal Memory Pool Sizes ---------- ------------------------------------------------ */ /** * MEMP_NUM_PBUF: the number of memp struct pbufs (used for PBUF_ROM and PBUF_REF). * If the application sends a lot of data out of ROM (or other static memory), * this should be set high. */ #ifndef MEMP_NUM_PBUF #define MEMP_NUM_PBUF 16 #endif /** * MEMP_NUM_RAW_PCB: Number of raw connection PCBs * (requires the LWIP_RAW option) */ #ifndef MEMP_NUM_RAW_PCB #define MEMP_NUM_RAW_PCB 4 #endif /** * MEMP_NUM_UDP_PCB: the number of UDP protocol control blocks. One * per active UDP "connection". * (requires the LWIP_UDP option) */ #ifndef MEMP_NUM_UDP_PCB #define MEMP_NUM_UDP_PCB 4 #endif /** * MEMP_NUM_TCP_PCB: the number of simulatenously active TCP connections. * (requires the LWIP_TCP option) */ #ifndef MEMP_NUM_TCP_PCB #define MEMP_NUM_TCP_PCB 5 #endif /** * MEMP_NUM_TCP_PCB_LISTEN: the number of listening TCP connections. * (requires the LWIP_TCP option) */ #ifndef MEMP_NUM_TCP_PCB_LISTEN #define MEMP_NUM_TCP_PCB_LISTEN 8 #endif /** * MEMP_NUM_TCP_SEG: the number of simultaneously queued TCP segments. * (requires the LWIP_TCP option) */ #ifndef MEMP_NUM_TCP_SEG #define MEMP_NUM_TCP_SEG 16 #endif /** * MEMP_NUM_REASSDATA: the number of IP packets simultaneously queued for * reassembly (whole packets, not fragments!) */ #ifndef MEMP_NUM_REASSDATA #define MEMP_NUM_REASSDATA 5 #endif /** * MEMP_NUM_FRAG_PBUF: the number of IP fragments simultaneously sent * (fragments, not whole packets!). * This is only used with IP_FRAG_USES_STATIC_BUF==0 and * LWIP_NETIF_TX_SINGLE_PBUF==0 and only has to be > 1 with DMA-enabled MACs * where the packet is not yet sent when netif->output returns. */ #ifndef MEMP_NUM_FRAG_PBUF #define MEMP_NUM_FRAG_PBUF 15 #endif /** * MEMP_NUM_ARP_QUEUE: the number of simulateously queued outgoing * packets (pbufs) that are waiting for an ARP request (to resolve * their destination address) to finish. * (requires the ARP_QUEUEING option) */ #ifndef MEMP_NUM_ARP_QUEUE #define MEMP_NUM_ARP_QUEUE 30 #endif /** * MEMP_NUM_IGMP_GROUP: The number of multicast groups whose network interfaces * can be members et the same time (one per netif - allsystems group -, plus one * per netif membership). * (requires the LWIP_IGMP option) */ #ifndef MEMP_NUM_IGMP_GROUP #define MEMP_NUM_IGMP_GROUP 8 #endif /** * MEMP_NUM_SYS_TIMEOUT: the number of simulateously active timeouts. * (requires NO_SYS==0) * The default number of timeouts is calculated here for all enabled modules. * The formula expects settings to be either '0' or '1'. */ #ifndef MEMP_NUM_SYS_TIMEOUT #define MEMP_NUM_SYS_TIMEOUT (LWIP_TCP + IP_REASSEMBLY + LWIP_ARP + (2*LWIP_DHCP) + LWIP_AUTOIP + LWIP_IGMP + LWIP_DNS + (PPP_SUPPORT*6*MEMP_NUM_PPP_PCB) + (LWIP_IPV6 ? (1 + LWIP_IPV6_REASS + LWIP_IPV6_MLD) : 0)) #endif /** * MEMP_NUM_NETBUF: the number of struct netbufs. * (only needed if you use the sequential API, like api_lib.c) */ #ifndef MEMP_NUM_NETBUF #define MEMP_NUM_NETBUF 2 #endif /** * MEMP_NUM_NETCONN: the number of struct netconns. * (only needed if you use the sequential API, like api_lib.c) */ #ifndef MEMP_NUM_NETCONN #define MEMP_NUM_NETCONN 4 #endif /** * MEMP_NUM_TCPIP_MSG_API: the number of struct tcpip_msg, which are used * for callback/timeout API communication. * (only needed if you use tcpip.c) */ #ifndef MEMP_NUM_TCPIP_MSG_API #define MEMP_NUM_TCPIP_MSG_API 8 #endif /** * MEMP_NUM_TCPIP_MSG_INPKT: the number of struct tcpip_msg, which are used * for incoming packets. * (only needed if you use tcpip.c) */ #ifndef MEMP_NUM_TCPIP_MSG_INPKT #define MEMP_NUM_TCPIP_MSG_INPKT 8 #endif /** * MEMP_NUM_SNMP_NODE: the number of leafs in the SNMP tree. */ #ifndef MEMP_NUM_SNMP_NODE #define MEMP_NUM_SNMP_NODE 50 #endif /** * MEMP_NUM_SNMP_ROOTNODE: the number of branches in the SNMP tree. * Every branch has one leaf (MEMP_NUM_SNMP_NODE) at least! */ #ifndef MEMP_NUM_SNMP_ROOTNODE #define MEMP_NUM_SNMP_ROOTNODE 30 #endif /** * MEMP_NUM_SNMP_VARBIND: the number of concurrent requests (does not have to * be changed normally) - 2 of these are used per request (1 for input, * 1 for output) */ #ifndef MEMP_NUM_SNMP_VARBIND #define MEMP_NUM_SNMP_VARBIND 2 #endif /** * MEMP_NUM_SNMP_VALUE: the number of OID or values concurrently used * (does not have to be changed normally) - 3 of these are used per request * (1 for the value read and 2 for OIDs - input and output) */ #ifndef MEMP_NUM_SNMP_VALUE #define MEMP_NUM_SNMP_VALUE 3 #endif /** * MEMP_NUM_NETDB: the number of concurrently running lwip_addrinfo() calls * (before freeing the corresponding memory using lwip_freeaddrinfo()). */ #ifndef MEMP_NUM_NETDB #define MEMP_NUM_NETDB 1 #endif /** * MEMP_NUM_LOCALHOSTLIST: the number of host entries in the local host list * if DNS_LOCAL_HOSTLIST_IS_DYNAMIC==1. */ #ifndef MEMP_NUM_LOCALHOSTLIST #define MEMP_NUM_LOCALHOSTLIST 1 #endif /** * MEMP_NUM_PPP_PCB: the number of simultaneously active PPP * connections (requires the PPP_SUPPORT option) */ #ifndef MEMP_NUM_PPP_PCB #define MEMP_NUM_PPP_PCB 1 #endif /** * MEMP_NUM_PPPOE_INTERFACES: the number of concurrently active PPPoE * interfaces (only used with PPPOE_SUPPORT==1) */ #ifndef MEMP_NUM_PPPOE_INTERFACES #define MEMP_NUM_PPPOE_INTERFACES 1 #endif /** * MEMP_NUM_PPPOL2TP_INTERFACES: the number of concurrently active PPPoL2TP * interfaces (only used with PPPOL2TP_SUPPORT==1) */ #ifndef MEMP_NUM_PPPOL2TP_INTERFACES #define MEMP_NUM_PPPOL2TP_INTERFACES 1 #endif /** * PBUF_POOL_SIZE: the number of buffers in the pbuf pool. */ #ifndef PBUF_POOL_SIZE #define PBUF_POOL_SIZE 16 #endif /** MEMP_NUM_API_MSG: the number of concurrently active calls to various * socket, netconn, and tcpip functions */ #ifndef MEMP_NUM_API_MSG #define MEMP_NUM_API_MSG MEMP_NUM_TCPIP_MSG_API #endif /** MEMP_NUM_DNS_API_MSG: the number of concurrently active calls to netconn_gethostbyname */ #ifndef MEMP_NUM_DNS_API_MSG #define MEMP_NUM_DNS_API_MSG MEMP_NUM_TCPIP_MSG_API #endif /** MEMP_NUM_SOCKET_SETGETSOCKOPT_DATA: the number of concurrently active calls * to getsockopt/setsockopt */ #ifndef MEMP_NUM_SOCKET_SETGETSOCKOPT_DATA #define MEMP_NUM_SOCKET_SETGETSOCKOPT_DATA MEMP_NUM_TCPIP_MSG_API #endif /** MEMP_NUM_NETIFAPI_MSG: the number of concurrently active calls to the * netifapi functions */ #ifndef MEMP_NUM_NETIFAPI_MSG #define MEMP_NUM_NETIFAPI_MSG MEMP_NUM_TCPIP_MSG_API #endif /* --------------------------------- ---------- ARP options ---------- --------------------------------- */ /** * LWIP_ARP==1: Enable ARP functionality. */ #ifndef LWIP_ARP #define LWIP_ARP 1 #endif /** * ARP_TABLE_SIZE: Number of active MAC-IP address pairs cached. */ #ifndef ARP_TABLE_SIZE #define ARP_TABLE_SIZE 10 #endif /** * ARP_QUEUEING==1: Multiple outgoing packets are queued during hardware address * resolution. By default, only the most recent packet is queued per IP address. * This is sufficient for most protocols and mainly reduces TCP connection * startup time. Set this to 1 if you know your application sends more than one * packet in a row to an IP address that is not in the ARP cache. */ #ifndef ARP_QUEUEING #define ARP_QUEUEING 0 #endif /** The maximum number of packets which may be queued for each * unresolved address by other network layers. Defaults to 3, 0 means disabled. * Old packets are dropped, new packets are queued. */ #ifndef ARP_QUEUE_LEN #define ARP_QUEUE_LEN 3 #endif /** * ETHARP_TRUST_IP_MAC==1: Incoming IP packets cause the ARP table to be * updated with the source MAC and IP addresses supplied in the packet. * You may want to disable this if you do not trust LAN peers to have the * correct addresses, or as a limited approach to attempt to handle * spoofing. If disabled, lwIP will need to make a new ARP request if * the peer is not already in the ARP table, adding a little latency. * The peer *is* in the ARP table if it requested our address before. * Also notice that this slows down input processing of every IP packet! */ #ifndef ETHARP_TRUST_IP_MAC #define ETHARP_TRUST_IP_MAC 0 #endif /** * ETHARP_SUPPORT_VLAN==1: support receiving and sending ethernet packets with * VLAN header. See the description of LWIP_HOOK_VLAN_CHECK and * LWIP_HOOK_VLAN_SET hooks to check/set VLAN headers. * Additionally, you can define ETHARP_VLAN_CHECK to an u16_t VLAN ID to check. * If ETHARP_VLAN_CHECK is defined, only VLAN-traffic for this VLAN is accepted. * If ETHARP_VLAN_CHECK is not defined, all traffic is accepted. * Alternatively, define a function/define ETHARP_VLAN_CHECK_FN(eth_hdr, vlan) * that returns 1 to accept a packet or 0 to drop a packet. */ #ifndef ETHARP_SUPPORT_VLAN #define ETHARP_SUPPORT_VLAN 0 #endif /** LWIP_ETHERNET==1: enable ethernet support for PPPoE even though ARP * might be disabled */ #ifndef LWIP_ETHERNET #define LWIP_ETHERNET (LWIP_ARP || PPPOE_SUPPORT) #endif /** ETH_PAD_SIZE: number of bytes added before the ethernet header to ensure * alignment of payload after that header. Since the header is 14 bytes long, * without this padding e.g. addresses in the IP header will not be aligned * on a 32-bit boundary, so setting this to 2 can speed up 32-bit-platforms. */ #ifndef ETH_PAD_SIZE #define ETH_PAD_SIZE 0 #endif /** ETHARP_SUPPORT_STATIC_ENTRIES==1: enable code to support static ARP table * entries (using etharp_add_static_entry/etharp_remove_static_entry). */ #ifndef ETHARP_SUPPORT_STATIC_ENTRIES #define ETHARP_SUPPORT_STATIC_ENTRIES 0 #endif /* -------------------------------- ---------- IP options ---------- -------------------------------- */ /** * IP_FORWARD==1: Enables the ability to forward IP packets across network * interfaces. If you are going to run lwIP on a device with only one network * interface, define this to 0. */ #ifndef IP_FORWARD #define IP_FORWARD 0 #endif /** * IP_OPTIONS_ALLOWED: Defines the behavior for IP options. * IP_OPTIONS_ALLOWED==0: All packets with IP options are dropped. * IP_OPTIONS_ALLOWED==1: IP options are allowed (but not parsed). */ #ifndef IP_OPTIONS_ALLOWED #define IP_OPTIONS_ALLOWED 1 #endif /** * IP_REASSEMBLY==1: Reassemble incoming fragmented IP packets. Note that * this option does not affect outgoing packet sizes, which can be controlled * via IP_FRAG. */ #ifndef IP_REASSEMBLY #define IP_REASSEMBLY 1 #endif /** * IP_FRAG==1: Fragment outgoing IP packets if their size exceeds MTU. Note * that this option does not affect incoming packet sizes, which can be * controlled via IP_REASSEMBLY. */ #ifndef IP_FRAG #define IP_FRAG 1 #endif /** * IP_REASS_MAXAGE: Maximum time (in multiples of IP_TMR_INTERVAL - so seconds, normally) * a fragmented IP packet waits for all fragments to arrive. If not all fragments arrived * in this time, the whole packet is discarded. */ #ifndef IP_REASS_MAXAGE #define IP_REASS_MAXAGE 3 #endif /** * IP_REASS_MAX_PBUFS: Total maximum amount of pbufs waiting to be reassembled. * Since the received pbufs are enqueued, be sure to configure * PBUF_POOL_SIZE > IP_REASS_MAX_PBUFS so that the stack is still able to receive * packets even if the maximum amount of fragments is enqueued for reassembly! */ #ifndef IP_REASS_MAX_PBUFS #define IP_REASS_MAX_PBUFS 10 #endif /** * IP_FRAG_USES_STATIC_BUF==1: Use a static MTU-sized buffer for IP * fragmentation. Otherwise pbufs are allocated and reference the original * packet data to be fragmented (or with LWIP_NETIF_TX_SINGLE_PBUF==1, * new PBUF_RAM pbufs are used for fragments). * ATTENTION: IP_FRAG_USES_STATIC_BUF==1 may not be used for DMA-enabled MACs! */ #ifndef IP_FRAG_USES_STATIC_BUF #define IP_FRAG_USES_STATIC_BUF 0 #endif /** * IP_FRAG_MAX_MTU: Assumed max MTU on any interface for IP frag buffer * (requires IP_FRAG_USES_STATIC_BUF==1) */ #if IP_FRAG_USES_STATIC_BUF && !defined(IP_FRAG_MAX_MTU) #define IP_FRAG_MAX_MTU 1500 #endif /** * IP_DEFAULT_TTL: Default value for Time-To-Live used by transport layers. */ #ifndef IP_DEFAULT_TTL #define IP_DEFAULT_TTL 255 #endif /** * IP_SOF_BROADCAST=1: Use the SOF_BROADCAST field to enable broadcast * filter per pcb on udp and raw send operations. To enable broadcast filter * on recv operations, you also have to set IP_SOF_BROADCAST_RECV=1. */ #ifndef IP_SOF_BROADCAST #define IP_SOF_BROADCAST 0 #endif /** * IP_SOF_BROADCAST_RECV (requires IP_SOF_BROADCAST=1) enable the broadcast * filter on recv operations. */ #ifndef IP_SOF_BROADCAST_RECV #define IP_SOF_BROADCAST_RECV 0 #endif /** * IP_FORWARD_ALLOW_TX_ON_RX_NETIF==1: allow ip_forward() to send packets back * out on the netif where it was received. This should only be used for * wireless networks. * ATTENTION: When this is 1, make sure your netif driver correctly marks incoming * link-layer-broadcast/multicast packets as such using the corresponding pbuf flags! */ #ifndef IP_FORWARD_ALLOW_TX_ON_RX_NETIF #define IP_FORWARD_ALLOW_TX_ON_RX_NETIF 0 #endif /** * LWIP_RANDOMIZE_INITIAL_LOCAL_PORTS==1: randomize the local port for the first * local TCP/UDP pcb (default==0). This can prevent creating predictable port * numbers after booting a device. */ #ifndef LWIP_RANDOMIZE_INITIAL_LOCAL_PORTS #define LWIP_RANDOMIZE_INITIAL_LOCAL_PORTS 0 #endif /* ---------------------------------- ---------- ICMP options ---------- ---------------------------------- */ /** * LWIP_ICMP==1: Enable ICMP module inside the IP stack. * Be careful, disable that make your product non-compliant to RFC1122 */ #ifndef LWIP_ICMP #define LWIP_ICMP 1 #endif /** * ICMP_TTL: Default value for Time-To-Live used by ICMP packets. */ #ifndef ICMP_TTL #define ICMP_TTL (IP_DEFAULT_TTL) #endif /** * LWIP_BROADCAST_PING==1: respond to broadcast pings (default is unicast only) */ #ifndef LWIP_BROADCAST_PING #define LWIP_BROADCAST_PING 0 #endif /** * LWIP_MULTICAST_PING==1: respond to multicast pings (default is unicast only) */ #ifndef LWIP_MULTICAST_PING #define LWIP_MULTICAST_PING 0 #endif /* --------------------------------- ---------- RAW options ---------- --------------------------------- */ /** * LWIP_RAW==1: Enable application layer to hook into the IP layer itself. */ #ifndef LWIP_RAW #define LWIP_RAW 1 #endif /** * LWIP_RAW==1: Enable application layer to hook into the IP layer itself. */ #ifndef RAW_TTL #define RAW_TTL (IP_DEFAULT_TTL) #endif /* ---------------------------------- ---------- DHCP options ---------- ---------------------------------- */ /** * LWIP_DHCP==1: Enable DHCP module. */ #ifndef LWIP_DHCP #define LWIP_DHCP 0 #endif /** * DHCP_DOES_ARP_CHECK==1: Do an ARP check on the offered address. */ #ifndef DHCP_DOES_ARP_CHECK #define DHCP_DOES_ARP_CHECK ((LWIP_DHCP) && (LWIP_ARP)) #endif /* ------------------------------------ ---------- AUTOIP options ---------- ------------------------------------ */ /** * LWIP_AUTOIP==1: Enable AUTOIP module. */ #ifndef LWIP_AUTOIP #define LWIP_AUTOIP 0 #endif /** * LWIP_DHCP_AUTOIP_COOP==1: Allow DHCP and AUTOIP to be both enabled on * the same interface at the same time. */ #ifndef LWIP_DHCP_AUTOIP_COOP #define LWIP_DHCP_AUTOIP_COOP 0 #endif /** * LWIP_DHCP_AUTOIP_COOP_TRIES: Set to the number of DHCP DISCOVER probes * that should be sent before falling back on AUTOIP. This can be set * as low as 1 to get an AutoIP address very quickly, but you should * be prepared to handle a changing IP address when DHCP overrides * AutoIP. */ #ifndef LWIP_DHCP_AUTOIP_COOP_TRIES #define LWIP_DHCP_AUTOIP_COOP_TRIES 9 #endif /* ---------------------------------- ---------- SNMP options ---------- ---------------------------------- */ /** * LWIP_SNMP==1: Turn on SNMP module. UDP must be available for SNMP * transport. */ #ifndef LWIP_SNMP #define LWIP_SNMP 0 #endif /** * SNMP_CONCURRENT_REQUESTS: Number of concurrent requests the module will * allow. At least one request buffer is required. * Does not have to be changed unless external MIBs answer request asynchronously */ #ifndef SNMP_CONCURRENT_REQUESTS #define SNMP_CONCURRENT_REQUESTS 1 #endif /** * SNMP_TRAP_DESTINATIONS: Number of trap destinations. At least one trap * destination is required */ #ifndef SNMP_TRAP_DESTINATIONS #define SNMP_TRAP_DESTINATIONS 1 #endif /** * SNMP_PRIVATE_MIB: * When using a private MIB, you have to create a file 'private_mib.h' that contains * a 'struct mib_array_node mib_private' which contains your MIB. */ #ifndef SNMP_PRIVATE_MIB #define SNMP_PRIVATE_MIB 0 #endif /** * Only allow SNMP write actions that are 'safe' (e.g. disabeling netifs is not * a safe action and disabled when SNMP_SAFE_REQUESTS = 1). * Unsafe requests are disabled by default! */ #ifndef SNMP_SAFE_REQUESTS #define SNMP_SAFE_REQUESTS 1 #endif /** * The maximum length of strings used. This affects the size of * MEMP_SNMP_VALUE elements. */ #ifndef SNMP_MAX_OCTET_STRING_LEN #define SNMP_MAX_OCTET_STRING_LEN 127 #endif /** * The maximum depth of the SNMP tree. * With private MIBs enabled, this depends on your MIB! * This affects the size of MEMP_SNMP_VALUE elements. */ #ifndef SNMP_MAX_TREE_DEPTH #define SNMP_MAX_TREE_DEPTH 15 #endif /** * The size of the MEMP_SNMP_VALUE elements, normally calculated from * SNMP_MAX_OCTET_STRING_LEN and SNMP_MAX_TREE_DEPTH. */ #ifndef SNMP_MAX_VALUE_SIZE #define SNMP_MAX_VALUE_SIZE LWIP_MAX((SNMP_MAX_OCTET_STRING_LEN)+1, sizeof(s32_t)*(SNMP_MAX_TREE_DEPTH)) #endif /* ---------------------------------- ---------- IGMP options ---------- ---------------------------------- */ /** * LWIP_IGMP==1: Turn on IGMP module. */ #ifndef LWIP_IGMP #define LWIP_IGMP 0 #endif /* ---------------------------------- ---------- DNS options ----------- ---------------------------------- */ /** * LWIP_DNS==1: Turn on DNS module. UDP must be available for DNS * transport. */ #ifndef LWIP_DNS #define LWIP_DNS 0 #endif /** DNS maximum number of entries to maintain locally. */ #ifndef DNS_TABLE_SIZE #define DNS_TABLE_SIZE 4 #endif /** DNS maximum host name length supported in the name table. */ #ifndef DNS_MAX_NAME_LENGTH #define DNS_MAX_NAME_LENGTH 256 #endif /** The maximum of DNS servers */ #ifndef DNS_MAX_SERVERS #define DNS_MAX_SERVERS 2 #endif /** DNS do a name checking between the query and the response. */ #ifndef DNS_DOES_NAME_CHECK #define DNS_DOES_NAME_CHECK 1 #endif /** DNS message max. size. Default value is RFC compliant. */ #ifndef DNS_MSG_SIZE #define DNS_MSG_SIZE 512 #endif /** DNS_LOCAL_HOSTLIST: Implements a local host-to-address list. If enabled, * you have to define * #define DNS_LOCAL_HOSTLIST_INIT {{"host1", 0x123}, {"host2", 0x234}} * (an array of structs name/address, where address is an u32_t in network * byte order). * * Instead, you can also use an external function: * #define DNS_LOOKUP_LOCAL_EXTERN(x) extern u32_t my_lookup_function(const char *name) * that returns the IP address or INADDR_NONE if not found. */ #ifndef DNS_LOCAL_HOSTLIST #define DNS_LOCAL_HOSTLIST 0 #endif /* DNS_LOCAL_HOSTLIST */ /** If this is turned on, the local host-list can be dynamically changed * at runtime. */ #ifndef DNS_LOCAL_HOSTLIST_IS_DYNAMIC #define DNS_LOCAL_HOSTLIST_IS_DYNAMIC 0 #endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ /* --------------------------------- ---------- UDP options ---------- --------------------------------- */ /** * LWIP_UDP==1: Turn on UDP. */ #ifndef LWIP_UDP #define LWIP_UDP 1 #endif /** * LWIP_UDPLITE==1: Turn on UDP-Lite. (Requires LWIP_UDP) */ #ifndef LWIP_UDPLITE #define LWIP_UDPLITE 0 #endif /** * UDP_TTL: Default Time-To-Live value. */ #ifndef UDP_TTL #define UDP_TTL (IP_DEFAULT_TTL) #endif /** * LWIP_NETBUF_RECVINFO==1: append destination addr and port to every netbuf. */ #ifndef LWIP_NETBUF_RECVINFO #define LWIP_NETBUF_RECVINFO 0 #endif /* --------------------------------- ---------- TCP options ---------- --------------------------------- */ /** * LWIP_TCP==1: Turn on TCP. */ #ifndef LWIP_TCP #define LWIP_TCP 1 #endif /** * TCP_TTL: Default Time-To-Live value. */ #ifndef TCP_TTL #define TCP_TTL (IP_DEFAULT_TTL) #endif /** * TCP_WND: The size of a TCP window. This must be at least * (2 * TCP_MSS) for things to work well */ #ifndef TCP_WND #define TCP_WND (4 * TCP_MSS) #endif /** * TCP_MAXRTX: Maximum number of retransmissions of data segments. */ #ifndef TCP_MAXRTX #define TCP_MAXRTX 12 #endif /** * TCP_SYNMAXRTX: Maximum number of retransmissions of SYN segments. */ #ifndef TCP_SYNMAXRTX #define TCP_SYNMAXRTX 6 #endif /** * TCP_QUEUE_OOSEQ==1: TCP will queue segments that arrive out of order. * Define to 0 if your device is low on memory. */ #ifndef TCP_QUEUE_OOSEQ #define TCP_QUEUE_OOSEQ (LWIP_TCP) #endif /** * TCP_MSS: TCP Maximum segment size. (default is 536, a conservative default, * you might want to increase this.) * For the receive side, this MSS is advertised to the remote side * when opening a connection. For the transmit size, this MSS sets * an upper limit on the MSS advertised by the remote host. */ #ifndef TCP_MSS #define TCP_MSS 536 #endif /** * TCP_CALCULATE_EFF_SEND_MSS: "The maximum size of a segment that TCP really * sends, the 'effective send MSS,' MUST be the smaller of the send MSS (which * reflects the available reassembly buffer size at the remote host) and the * largest size permitted by the IP layer" (RFC 1122) * Setting this to 1 enables code that checks TCP_MSS against the MTU of the * netif used for a connection and limits the MSS if it would be too big otherwise. */ #ifndef TCP_CALCULATE_EFF_SEND_MSS #define TCP_CALCULATE_EFF_SEND_MSS 1 #endif /** * TCP_SND_BUF: TCP sender buffer space (bytes). * To achieve good performance, this should be at least 2 * TCP_MSS. */ #ifndef TCP_SND_BUF #define TCP_SND_BUF (2 * TCP_MSS) #endif /** * TCP_SND_QUEUELEN: TCP sender buffer space (pbufs). This must be at least * as much as (2 * TCP_SND_BUF/TCP_MSS) for things to work. */ #ifndef TCP_SND_QUEUELEN #define TCP_SND_QUEUELEN ((4 * (TCP_SND_BUF) + (TCP_MSS - 1))/(TCP_MSS)) #endif /** * TCP_SNDLOWAT: TCP writable space (bytes). This must be less than * TCP_SND_BUF. It is the amount of space which must be available in the * TCP snd_buf for select to return writable (combined with TCP_SNDQUEUELOWAT). */ #ifndef TCP_SNDLOWAT #define TCP_SNDLOWAT LWIP_MIN(LWIP_MAX(((TCP_SND_BUF)/2), (2 * TCP_MSS) + 1), (TCP_SND_BUF) - 1) #endif /** * TCP_SNDQUEUELOWAT: TCP writable bufs (pbuf count). This must be less * than TCP_SND_QUEUELEN. If the number of pbufs queued on a pcb drops below * this number, select returns writable (combined with TCP_SNDLOWAT). */ #ifndef TCP_SNDQUEUELOWAT #define TCP_SNDQUEUELOWAT LWIP_MAX(((TCP_SND_QUEUELEN)/2), 5) #endif /** * TCP_OOSEQ_MAX_BYTES: The maximum number of bytes queued on ooseq per pcb. * Default is 0 (no limit). Only valid for TCP_QUEUE_OOSEQ==0. */ #ifndef TCP_OOSEQ_MAX_BYTES #define TCP_OOSEQ_MAX_BYTES 0 #endif /** * TCP_OOSEQ_MAX_PBUFS: The maximum number of pbufs queued on ooseq per pcb. * Default is 0 (no limit). Only valid for TCP_QUEUE_OOSEQ==0. */ #ifndef TCP_OOSEQ_MAX_PBUFS #define TCP_OOSEQ_MAX_PBUFS 0 #endif /** * TCP_LISTEN_BACKLOG: Enable the backlog option for tcp listen pcb. */ #ifndef TCP_LISTEN_BACKLOG #define TCP_LISTEN_BACKLOG 0 #endif /** * The maximum allowed backlog for TCP listen netconns. * This backlog is used unless another is explicitly specified. * 0xff is the maximum (u8_t). */ #ifndef TCP_DEFAULT_LISTEN_BACKLOG #define TCP_DEFAULT_LISTEN_BACKLOG 0xff #endif /** * TCP_OVERSIZE: The maximum number of bytes that tcp_write may * allocate ahead of time in an attempt to create shorter pbuf chains * for transmission. The meaningful range is 0 to TCP_MSS. Some * suggested values are: * * 0: Disable oversized allocation. Each tcp_write() allocates a new pbuf (old behaviour). * 1: Allocate size-aligned pbufs with minimal excess. Use this if your * scatter-gather DMA requires aligned fragments. * 128: Limit the pbuf/memory overhead to 20%. * TCP_MSS: Try to create unfragmented TCP packets. * TCP_MSS/4: Try to create 4 fragments or less per TCP packet. */ #ifndef TCP_OVERSIZE #define TCP_OVERSIZE TCP_MSS #endif /** * LWIP_TCP_TIMESTAMPS==1: support the TCP timestamp option. * The timestamp option is currently only used to help remote hosts, it is not * really used locally. Therefore, it is only enabled when a TS option is * received in the initial SYN packet from a remote host. */ #ifndef LWIP_TCP_TIMESTAMPS #define LWIP_TCP_TIMESTAMPS 0 #endif /** * TCP_WND_UPDATE_THRESHOLD: difference in window to trigger an * explicit window update */ #ifndef TCP_WND_UPDATE_THRESHOLD #define TCP_WND_UPDATE_THRESHOLD (TCP_WND / 4) #endif /** * LWIP_EVENT_API and LWIP_CALLBACK_API: Only one of these should be set to 1. * LWIP_EVENT_API==1: The user defines lwip_tcp_event() to receive all * events (accept, sent, etc) that happen in the system. * LWIP_CALLBACK_API==1: The PCB callback function is called directly * for the event. This is the default. */ #if !defined(LWIP_EVENT_API) && !defined(LWIP_CALLBACK_API) #define LWIP_EVENT_API 0 #define LWIP_CALLBACK_API 1 #endif /** * LWIP_WND_SCALE and TCP_RCV_SCALE: * Set LWIP_WND_SCALE to 1 to enable window scaling. * Set TCP_RCV_SCALE to the desired scaling factor (shift count in the * range of [0..14]). * When LWIP_WND_SCALE is enabled but TCP_RCV_SCALE is 0, we can use a large * send window while having a small receive window only. */ #ifndef LWIP_WND_SCALE #define LWIP_WND_SCALE 0 #define TCP_RCV_SCALE 0 #endif /* ---------------------------------- ---------- Pbuf options ---------- ---------------------------------- */ /** * PBUF_LINK_HLEN: the number of bytes that should be allocated for a * link level header. The default is 14, the standard value for * Ethernet. */ #ifndef PBUF_LINK_HLEN #ifdef LWIP_HOOK_VLAN_SET #define PBUF_LINK_HLEN (18 + ETH_PAD_SIZE) #else /* LWIP_HOOK_VLAN_SET */ #define PBUF_LINK_HLEN (14 + ETH_PAD_SIZE) #endif /* LWIP_HOOK_VLAN_SET */ #endif /** * PBUF_POOL_BUFSIZE: the size of each pbuf in the pbuf pool. The default is * designed to accomodate single full size TCP frame in one pbuf, including * TCP_MSS, IP header, and link header. */ #ifndef PBUF_POOL_BUFSIZE #define PBUF_POOL_BUFSIZE LWIP_MEM_ALIGN_SIZE(TCP_MSS+40+PBUF_LINK_HLEN) #endif /* ------------------------------------------------ ---------- Network Interfaces options ---------- ------------------------------------------------ */ /** * LWIP_NETIF_HOSTNAME==1: use DHCP_OPTION_HOSTNAME with netif's hostname * field. */ #ifndef LWIP_NETIF_HOSTNAME #define LWIP_NETIF_HOSTNAME 0 #endif /** * LWIP_NETIF_API==1: Support netif api (in netifapi.c) */ #ifndef LWIP_NETIF_API #define LWIP_NETIF_API 0 #endif /** * LWIP_NETIF_STATUS_CALLBACK==1: Support a callback function whenever an interface * changes its up/down status (i.e., due to DHCP IP acquistion) */ #ifndef LWIP_NETIF_STATUS_CALLBACK #define LWIP_NETIF_STATUS_CALLBACK 0 #endif /** * LWIP_NETIF_LINK_CALLBACK==1: Support a callback function from an interface * whenever the link changes (i.e., link down) */ #ifndef LWIP_NETIF_LINK_CALLBACK #define LWIP_NETIF_LINK_CALLBACK 0 #endif /** * LWIP_NETIF_REMOVE_CALLBACK==1: Support a callback function that is called * when a netif has been removed */ #ifndef LWIP_NETIF_REMOVE_CALLBACK #define LWIP_NETIF_REMOVE_CALLBACK 0 #endif /** * LWIP_NETIF_HWADDRHINT==1: Cache link-layer-address hints (e.g. table * indices) in struct netif. TCP and UDP can make use of this to prevent * scanning the ARP table for every sent packet. While this is faster for big * ARP tables or many concurrent connections, it might be counterproductive * if you have a tiny ARP table or if there never are concurrent connections. */ #ifndef LWIP_NETIF_HWADDRHINT #define LWIP_NETIF_HWADDRHINT 0 #endif /** * LWIP_NETIF_LOOPBACK==1: Support sending packets with a destination IP * address equal to the netif IP address, looping them back up the stack. */ #ifndef LWIP_NETIF_LOOPBACK #define LWIP_NETIF_LOOPBACK 0 #endif /** * LWIP_LOOPBACK_MAX_PBUFS: Maximum number of pbufs on queue for loopback * sending for each netif (0 = disabled) */ #ifndef LWIP_LOOPBACK_MAX_PBUFS #define LWIP_LOOPBACK_MAX_PBUFS 0 #endif /** * LWIP_NETIF_LOOPBACK_MULTITHREADING: Indicates whether threading is enabled in * the system, as netifs must change how they behave depending on this setting * for the LWIP_NETIF_LOOPBACK option to work. * Setting this is needed to avoid reentering non-reentrant functions like * tcp_input(). * LWIP_NETIF_LOOPBACK_MULTITHREADING==1: Indicates that the user is using a * multithreaded environment like tcpip.c. In this case, netif->input() * is called directly. * LWIP_NETIF_LOOPBACK_MULTITHREADING==0: Indicates a polling (or NO_SYS) setup. * The packets are put on a list and netif_poll() must be called in * the main application loop. */ #ifndef LWIP_NETIF_LOOPBACK_MULTITHREADING #define LWIP_NETIF_LOOPBACK_MULTITHREADING (!NO_SYS) #endif /** * LWIP_NETIF_TX_SINGLE_PBUF: if this is set to 1, lwIP tries to put all data * to be sent into one single pbuf. This is for compatibility with DMA-enabled * MACs that do not support scatter-gather. * Beware that this might involve CPU-memcpy before transmitting that would not * be needed without this flag! Use this only if you need to! * * @todo: TCP and IP-frag do not work with this, yet: */ #ifndef LWIP_NETIF_TX_SINGLE_PBUF #define LWIP_NETIF_TX_SINGLE_PBUF 0 #endif /* LWIP_NETIF_TX_SINGLE_PBUF */ /* ------------------------------------ ---------- LOOPIF options ---------- ------------------------------------ */ /** * LWIP_HAVE_LOOPIF==1: Support loop interface (127.0.0.1) */ #ifndef LWIP_HAVE_LOOPIF #define LWIP_HAVE_LOOPIF 0 #endif /* ------------------------------------ ---------- SLIPIF options ---------- ------------------------------------ */ /** * LWIP_HAVE_SLIPIF==1: Support slip interface and slipif.c */ #ifndef LWIP_HAVE_SLIPIF #define LWIP_HAVE_SLIPIF 0 #endif /* ------------------------------------ ---------- Thread options ---------- ------------------------------------ */ /** * TCPIP_THREAD_NAME: The name assigned to the main tcpip thread. */ #ifndef TCPIP_THREAD_NAME #define TCPIP_THREAD_NAME "tcpip_thread" #endif /** * TCPIP_THREAD_STACKSIZE: The stack size used by the main tcpip thread. * The stack size value itself is platform-dependent, but is passed to * sys_thread_new() when the thread is created. */ #ifndef TCPIP_THREAD_STACKSIZE #define TCPIP_THREAD_STACKSIZE 0 #endif /** * TCPIP_THREAD_PRIO: The priority assigned to the main tcpip thread. * The priority value itself is platform-dependent, but is passed to * sys_thread_new() when the thread is created. */ #ifndef TCPIP_THREAD_PRIO #define TCPIP_THREAD_PRIO 1 #endif /** * TCPIP_MBOX_SIZE: The mailbox size for the tcpip thread messages * The queue size value itself is platform-dependent, but is passed to * sys_mbox_new() when tcpip_init is called. */ #ifndef TCPIP_MBOX_SIZE #define TCPIP_MBOX_SIZE 0 #endif /** * SLIPIF_THREAD_NAME: The name assigned to the slipif_loop thread. */ #ifndef SLIPIF_THREAD_NAME #define SLIPIF_THREAD_NAME "slipif_loop" #endif /** * SLIP_THREAD_STACKSIZE: The stack size used by the slipif_loop thread. * The stack size value itself is platform-dependent, but is passed to * sys_thread_new() when the thread is created. */ #ifndef SLIPIF_THREAD_STACKSIZE #define SLIPIF_THREAD_STACKSIZE 0 #endif /** * SLIPIF_THREAD_PRIO: The priority assigned to the slipif_loop thread. * The priority value itself is platform-dependent, but is passed to * sys_thread_new() when the thread is created. */ #ifndef SLIPIF_THREAD_PRIO #define SLIPIF_THREAD_PRIO 1 #endif /** * DEFAULT_THREAD_NAME: The name assigned to any other lwIP thread. */ #ifndef DEFAULT_THREAD_NAME #define DEFAULT_THREAD_NAME "lwIP" #endif /** * DEFAULT_THREAD_STACKSIZE: The stack size used by any other lwIP thread. * The stack size value itself is platform-dependent, but is passed to * sys_thread_new() when the thread is created. */ #ifndef DEFAULT_THREAD_STACKSIZE #define DEFAULT_THREAD_STACKSIZE 0 #endif /** * DEFAULT_THREAD_PRIO: The priority assigned to any other lwIP thread. * The priority value itself is platform-dependent, but is passed to * sys_thread_new() when the thread is created. */ #ifndef DEFAULT_THREAD_PRIO #define DEFAULT_THREAD_PRIO 1 #endif /** * DEFAULT_RAW_RECVMBOX_SIZE: The mailbox size for the incoming packets on a * NETCONN_RAW. The queue size value itself is platform-dependent, but is passed * to sys_mbox_new() when the recvmbox is created. */ #ifndef DEFAULT_RAW_RECVMBOX_SIZE #define DEFAULT_RAW_RECVMBOX_SIZE 0 #endif /** * DEFAULT_UDP_RECVMBOX_SIZE: The mailbox size for the incoming packets on a * NETCONN_UDP. The queue size value itself is platform-dependent, but is passed * to sys_mbox_new() when the recvmbox is created. */ #ifndef DEFAULT_UDP_RECVMBOX_SIZE #define DEFAULT_UDP_RECVMBOX_SIZE 0 #endif /** * DEFAULT_TCP_RECVMBOX_SIZE: The mailbox size for the incoming packets on a * NETCONN_TCP. The queue size value itself is platform-dependent, but is passed * to sys_mbox_new() when the recvmbox is created. */ #ifndef DEFAULT_TCP_RECVMBOX_SIZE #define DEFAULT_TCP_RECVMBOX_SIZE 0 #endif /** * DEFAULT_ACCEPTMBOX_SIZE: The mailbox size for the incoming connections. * The queue size value itself is platform-dependent, but is passed to * sys_mbox_new() when the acceptmbox is created. */ #ifndef DEFAULT_ACCEPTMBOX_SIZE #define DEFAULT_ACCEPTMBOX_SIZE 0 #endif /* ---------------------------------------------- ---------- Sequential layer options ---------- ---------------------------------------------- */ /** * LWIP_TCPIP_CORE_LOCKING: (EXPERIMENTAL!) * Don't use it if you're not an active lwIP project member */ #ifndef LWIP_TCPIP_CORE_LOCKING #define LWIP_TCPIP_CORE_LOCKING 0 #endif /** * LWIP_TCPIP_CORE_LOCKING_INPUT: (EXPERIMENTAL!) * Don't use it if you're not an active lwIP project member */ #ifndef LWIP_TCPIP_CORE_LOCKING_INPUT #define LWIP_TCPIP_CORE_LOCKING_INPUT 0 #endif /** * LWIP_NETCONN==1: Enable Netconn API (require to use api_lib.c) */ #ifndef LWIP_NETCONN #define LWIP_NETCONN 1 #endif /** LWIP_TCPIP_TIMEOUT==1: Enable tcpip_timeout/tcpip_untimeout tod create * timers running in tcpip_thread from another thread. */ #ifndef LWIP_TCPIP_TIMEOUT #define LWIP_TCPIP_TIMEOUT 1 #endif /* ------------------------------------ ---------- Socket options ---------- ------------------------------------ */ /** * LWIP_SOCKET==1: Enable Socket API (require to use sockets.c) */ #ifndef LWIP_SOCKET #define LWIP_SOCKET 1 #endif /* LWIP_SOCKET_SET_ERRNO==1: Set errno when socket functions cannot complete * successfully, as required by POSIX. Default is POSIX-compliant. */ #ifndef LWIP_SOCKET_SET_ERRNO #define LWIP_SOCKET_SET_ERRNO 1 #endif /** * LWIP_COMPAT_SOCKETS==1: Enable BSD-style sockets functions names. * (only used if you use sockets.c) */ #ifndef LWIP_COMPAT_SOCKETS #define LWIP_COMPAT_SOCKETS 1 #endif /** * LWIP_POSIX_SOCKETS_IO_NAMES==1: Enable POSIX-style sockets functions names. * Disable this option if you use a POSIX operating system that uses the same * names (read, write & close). (only used if you use sockets.c) */ #ifndef LWIP_POSIX_SOCKETS_IO_NAMES #define LWIP_POSIX_SOCKETS_IO_NAMES 1 #endif /** * LWIP_TCP_KEEPALIVE==1: Enable TCP_KEEPIDLE, TCP_KEEPINTVL and TCP_KEEPCNT * options processing. Note that TCP_KEEPIDLE and TCP_KEEPINTVL have to be set * in seconds. (does not require sockets.c, and will affect tcp.c) */ #ifndef LWIP_TCP_KEEPALIVE #define LWIP_TCP_KEEPALIVE 0 #endif /** * LWIP_SO_SNDTIMEO==1: Enable send timeout for sockets/netconns and * SO_SNDTIMEO processing. */ #ifndef LWIP_SO_SNDTIMEO #define LWIP_SO_SNDTIMEO 0 #endif /** * LWIP_SO_RCVTIMEO==1: Enable receive timeout for sockets/netconns and * SO_RCVTIMEO processing. */ #ifndef LWIP_SO_RCVTIMEO #define LWIP_SO_RCVTIMEO 0 #endif /** * LWIP_SO_RCVBUF==1: Enable SO_RCVBUF processing. */ #ifndef LWIP_SO_RCVBUF #define LWIP_SO_RCVBUF 0 #endif /** * If LWIP_SO_RCVBUF is used, this is the default value for recv_bufsize. */ #ifndef RECV_BUFSIZE_DEFAULT #define RECV_BUFSIZE_DEFAULT INT_MAX #endif /** * SO_REUSE==1: Enable SO_REUSEADDR option. */ #ifndef SO_REUSE #define SO_REUSE 0 #endif /** * SO_REUSE_RXTOALL==1: Pass a copy of incoming broadcast/multicast packets * to all local matches if SO_REUSEADDR is turned on. * WARNING: Adds a memcpy for every packet if passing to more than one pcb! */ #ifndef SO_REUSE_RXTOALL #define SO_REUSE_RXTOALL 0 #endif /** * LWIP_FIONREAD_LINUXMODE==0 (default): ioctl/FIONREAD returns the amount of * pending data in the network buffer. This is the way windows does it. It's * the default for lwIP since it is smaller. * LWIP_FIONREAD_LINUXMODE==1: ioctl/FIONREAD returns the size of the next * pending datagram in bytes. This is the way linux does it. This code is only * here for compatibility. */ #ifndef LWIP_FIONREAD_LINUXMODE #define LWIP_FIONREAD_LINUXMODE 0 #endif /* ---------------------------------------- ---------- Statistics options ---------- ---------------------------------------- */ /** * LWIP_STATS==1: Enable statistics collection in lwip_stats. */ #ifndef LWIP_STATS #define LWIP_STATS 1 #endif #if LWIP_STATS /** * LWIP_STATS_DISPLAY==1: Compile in the statistics output functions. */ #ifndef LWIP_STATS_DISPLAY #define LWIP_STATS_DISPLAY 0 #endif /** * LINK_STATS==1: Enable link stats. */ #ifndef LINK_STATS #define LINK_STATS 1 #endif /** * ETHARP_STATS==1: Enable etharp stats. */ #ifndef ETHARP_STATS #define ETHARP_STATS (LWIP_ARP) #endif /** * IP_STATS==1: Enable IP stats. */ #ifndef IP_STATS #define IP_STATS 1 #endif /** * IPFRAG_STATS==1: Enable IP fragmentation stats. Default is * on if using either frag or reass. */ #ifndef IPFRAG_STATS #define IPFRAG_STATS (IP_REASSEMBLY || IP_FRAG) #endif /** * ICMP_STATS==1: Enable ICMP stats. */ #ifndef ICMP_STATS #define ICMP_STATS 1 #endif /** * IGMP_STATS==1: Enable IGMP stats. */ #ifndef IGMP_STATS #define IGMP_STATS (LWIP_IGMP) #endif /** * UDP_STATS==1: Enable UDP stats. Default is on if * UDP enabled, otherwise off. */ #ifndef UDP_STATS #define UDP_STATS (LWIP_UDP) #endif /** * TCP_STATS==1: Enable TCP stats. Default is on if TCP * enabled, otherwise off. */ #ifndef TCP_STATS #define TCP_STATS (LWIP_TCP) #endif /** * MEM_STATS==1: Enable mem.c stats. */ #ifndef MEM_STATS #define MEM_STATS ((MEM_LIBC_MALLOC == 0) && (MEM_USE_POOLS == 0)) #endif /** * MEMP_STATS==1: Enable memp.c pool stats. */ #ifndef MEMP_STATS #define MEMP_STATS (MEMP_MEM_MALLOC == 0) #endif /** * SYS_STATS==1: Enable system stats (sem and mbox counts, etc). */ #ifndef SYS_STATS #define SYS_STATS (NO_SYS == 0) #endif /** * IP6_STATS==1: Enable IPv6 stats. */ #ifndef IP6_STATS #define IP6_STATS (LWIP_IPV6) #endif /** * ICMP6_STATS==1: Enable ICMP for IPv6 stats. */ #ifndef ICMP6_STATS #define ICMP6_STATS (LWIP_IPV6 && LWIP_ICMP6) #endif /** * IP6_FRAG_STATS==1: Enable IPv6 fragmentation stats. */ #ifndef IP6_FRAG_STATS #define IP6_FRAG_STATS (LWIP_IPV6 && (LWIP_IPV6_FRAG || LWIP_IPV6_REASS)) #endif /** * MLD6_STATS==1: Enable MLD for IPv6 stats. */ #ifndef MLD6_STATS #define MLD6_STATS (LWIP_IPV6 && LWIP_IPV6_MLD) #endif /** * ND6_STATS==1: Enable Neighbor discovery for IPv6 stats. */ #ifndef ND6_STATS #define ND6_STATS (LWIP_IPV6) #endif #else #define LINK_STATS 0 #define ETHARP_STATS 0 #define IP_STATS 0 #define IPFRAG_STATS 0 #define ICMP_STATS 0 #define IGMP_STATS 0 #define UDP_STATS 0 #define TCP_STATS 0 #define MEM_STATS 0 #define MEMP_STATS 0 #define SYS_STATS 0 #define LWIP_STATS_DISPLAY 0 #define IP6_STATS 0 #define ICMP6_STATS 0 #define IP6_FRAG_STATS 0 #define MLD6_STATS 0 #define ND6_STATS 0 #endif /* LWIP_STATS */ /* --------------------------------- ---------- PPP options ---------- --------------------------------- */ /** * PPP_SUPPORT==1: Enable PPP. */ #ifndef PPP_SUPPORT #define PPP_SUPPORT 0 #endif /** * PPPOE_SUPPORT==1: Enable PPP Over Ethernet */ #ifndef PPPOE_SUPPORT #define PPPOE_SUPPORT 0 #endif /** * PPPOL2TP_SUPPORT==1: Enable PPP Over L2TP */ #ifndef PPPOL2TP_SUPPORT #define PPPOL2TP_SUPPORT 0 #endif /** * PPPOL2TP_AUTH_SUPPORT==1: Enable PPP Over L2TP Auth (enable MD5 support) */ #ifndef PPPOL2TP_AUTH_SUPPORT #define PPPOL2TP_AUTH_SUPPORT PPPOL2TP_SUPPORT #endif /** * PPPOS_SUPPORT==1: Enable PPP Over Serial */ #ifndef PPPOS_SUPPORT #define PPPOS_SUPPORT PPP_SUPPORT #endif #if PPP_SUPPORT /** * PPP_INPROC_MULTITHREADED==1 call ppp_input() using tcpip_callback(). * Set this to 0 if pppos_input() is called inside tcpip_thread or with NO_SYS==1. * Default is 1 for NO_SYS==0 (multithreaded) and 0 for NO_SYS==1 (single-threaded). */ #ifndef PPP_INPROC_MULTITHREADED #define PPP_INPROC_MULTITHREADED (NO_SYS==0) #endif /** * LWIP_PPP_API==1: Support PPP API (in pppapi.c) */ #ifndef LWIP_PPP_API #define LWIP_PPP_API 0 #endif /** * pbuf_type PPP is using for LCP, PAP, CHAP, EAP, IPCP and IP6CP packets. * * Memory allocated must be single buffered for PPP to works, it requires pbuf * that are not going to be chained when allocated. This requires setting * PBUF_POOL_BUFSIZE to at least 512 bytes, which is quite huge for small systems. * * Setting PPP_USE_PBUF_RAM to 1 makes PPP use memory from heap where continuous * buffers are required, allowing you to use a smaller PBUF_POOL_BUFSIZE. */ #ifndef PPP_USE_PBUF_RAM #define PPP_USE_PBUF_RAM 0 #endif /** * PPP_FCS_TABLE: Keep a 256*2 byte table to speed up FCS calculation */ #ifndef PPP_FCS_TABLE #define PPP_FCS_TABLE 1 #endif /** * PAP_SUPPORT==1: Support PAP. */ #ifndef PAP_SUPPORT #define PAP_SUPPORT 0 #endif /** * CHAP_SUPPORT==1: Support CHAP. */ #ifndef CHAP_SUPPORT #define CHAP_SUPPORT 0 #endif /** * MSCHAP_SUPPORT==1: Support MSCHAP. */ #ifndef MSCHAP_SUPPORT #define MSCHAP_SUPPORT 0 #endif #if MSCHAP_SUPPORT #undef CHAP_SUPPORT #define CHAP_SUPPORT 1 /* MSCHAP require CHAP support */ #endif /* MSCHAP_SUPPORT */ /** * CBCP_SUPPORT==1: Support CBCP. CURRENTLY NOT SUPPORTED! DO NOT SET! */ #ifndef CBCP_SUPPORT #define CBCP_SUPPORT 0 #endif /** * CCP_SUPPORT==1: Support CCP. CURRENTLY NOT SUPPORTED! DO NOT SET! */ #ifndef CCP_SUPPORT #define CCP_SUPPORT 0 #endif /** * ECP_SUPPORT==1: Support ECP. CURRENTLY NOT SUPPORTED! DO NOT SET! */ #ifndef ECP_SUPPORT #define ECP_SUPPORT 0 #endif /** * LQR_SUPPORT==1: Support Link Quality Report. Do nothing except exchanging some LCP packets. */ #ifndef LQR_SUPPORT #define LQR_SUPPORT 0 #endif /** * VJ_SUPPORT==1: Support VJ header compression. */ #ifndef VJ_SUPPORT #define VJ_SUPPORT 1 #endif #if !PPPOS_SUPPORT #undef VJ_SUPPORT #define VJ_SUPPORT 0 /* Only PPPoS may need VJ compression */ #endif /* !PPPOS_SUPPORT */ /** * PPP_MD5_RANDM==1: Use MD5 for better randomness. Automatically enabled if CHAP or L2TP AUTH support is enabled. */ #ifndef PPP_MD5_RANDM #define PPP_MD5_RANDM 0 #endif #if CHAP_SUPPORT || PPPOL2TP_AUTH_SUPPORT #undef PPP_MD5_RANDM #define PPP_MD5_RANDM 1 /* MD5 Random is required for CHAP and L2TP AUTH */ #endif /* CHAP_SUPPORT || PPPOL2TP_AUTH_SUPPORT */ /** * PolarSSL library, used if necessary and not previously disabled * * * lwIP contains some files fetched from the latest BSD release of * the PolarSSL project for ciphers and encryption methods we need for lwIP * PPP support. * * The PolarSSL files were cleaned to contain only the necessary struct * fields and functions needed for lwIP. * * The PolarSSL API was not changed at all, so if you are already using * PolarSSL you can choose to skip the compilation of the included PolarSSL * library into lwIP: * * The following defines are available for flexibility: * * LWIP_INCLUDED_POLARSSL_MD4 ; Use lwIP internal PolarSSL for MD4 * LWIP_INCLUDED_POLARSSL_MD5 ; Use lwIP internal PolarSSL for MD5 * LWIP_INCLUDED_POLARSSL_SHA1 ; Use lwIP internal PolarSSL for SHA1 * LWIP_INCLUDED_POLARSSL_DES ; Use lwIP internal PolarSSL for DES * * If set (=1), the default if required by another enabled PPP feature unless * explicitly set to 0, using included lwIP PolarSSL. * * If clear (=0), using external PolarSSL. * * Undefined if not needed. * * Beware of the stack requirements which can be a lot larger if you are not * using our cleaned PolarSSL library. */ #if CHAP_SUPPORT || EAP_SUPPORT || PPPOL2TP_AUTH_SUPPORT || PPP_MD5_RANDM #ifndef LWIP_INCLUDED_POLARSSL_MD5 #define LWIP_INCLUDED_POLARSSL_MD5 1 /* CHAP, EAP, L2TP AUTH and MD5 Random require MD5 support */ #endif /* LWIP_INCLUDED_POLARSSL_MD5 */ #endif /* CHAP_SUPPORT || EAP_SUPPORT || PPPOL2TP_AUTH_SUPPORT || PPP_MD5_RANDM */ #if MSCHAP_SUPPORT #ifndef LWIP_INCLUDED_POLARSSL_MD4 #define LWIP_INCLUDED_POLARSSL_MD4 1 /* MSCHAP require MD4 support */ #endif /* LWIP_INCLUDED_POLARSSL_MD4 */ #ifndef LWIP_INCLUDED_POLARSSL_SHA1 #define LWIP_INCLUDED_POLARSSL_SHA1 1 /* MSCHAP require SHA1 support */ #endif /* LWIP_INCLUDED_POLARSSL_SHA1 */ #ifndef LWIP_INCLUDED_POLARSSL_DES #define LWIP_INCLUDED_POLARSSL_DES 1 /* MSCHAP require DES support */ #endif /* LWIP_INCLUDED_POLARSSL_DES */ #endif /* MSCHAP_SUPPORT */ /* * Timeouts */ #ifndef FSM_DEFTIMEOUT #define FSM_DEFTIMEOUT 6 /* Timeout time in seconds */ #endif #ifndef FSM_DEFMAXTERMREQS #define FSM_DEFMAXTERMREQS 2 /* Maximum Terminate-Request transmissions */ #endif #ifndef FSM_DEFMAXCONFREQS #define FSM_DEFMAXCONFREQS 10 /* Maximum Configure-Request transmissions */ #endif #ifndef FSM_DEFMAXNAKLOOPS #define FSM_DEFMAXNAKLOOPS 5 /* Maximum number of nak loops */ #endif #ifndef UPAP_DEFTIMEOUT #define UPAP_DEFTIMEOUT 6 /* Timeout (seconds) for retransmitting req */ #endif #ifndef UPAP_DEFTRANSMITS #define UPAP_DEFTRANSMITS 10 /* Maximum number of auth-reqs to send */ #endif #if PPP_SERVER #ifndef UPAP_DEFREQTIME #define UPAP_DEFREQTIME 30 /* Time to wait for auth-req from peer */ #endif #endif /* PPP_SERVER */ #ifndef CHAP_DEFTIMEOUT #define CHAP_DEFTIMEOUT 6 /* Timeout (seconds) for retransmitting req */ #endif #ifndef CHAP_DEFTRANSMITS #define CHAP_DEFTRANSMITS 10 /* max # times to send challenge */ #endif #if PPP_SERVER #ifndef CHAP_DEFREQTIME #define CHAP_DEFREQTIME 30 /* Time to wait for auth-req from peer */ #endif #endif /* PPP_SERVER */ #ifndef EAP_DEFREQTIME #define EAP_DEFREQTIME 6 /* Time to wait for peer request */ #endif #ifndef EAP_DEFALLOWREQ #define EAP_DEFALLOWREQ 10 /* max # times to accept requests */ #endif #if PPP_SERVER #ifndef EAP_DEFTIMEOUT #define EAP_DEFTIMEOUT 6 /* Timeout (seconds) for rexmit */ #endif #ifndef EAP_DEFTRANSMITS #define EAP_DEFTRANSMITS 10 /* max # times to transmit */ #endif #endif /* PPP_SERVER */ /* Default number of times we receive our magic number from the peer before deciding the link is looped-back. */ #ifndef LCP_DEFLOOPBACKFAIL #define LCP_DEFLOOPBACKFAIL 10 #endif /* Interval in seconds between keepalive echo requests, 0 to disable. */ #ifndef LCP_ECHOINTERVAL #define LCP_ECHOINTERVAL 0 #endif /* Number of unanswered echo requests before failure. */ #ifndef LCP_MAXECHOFAILS #define LCP_MAXECHOFAILS 3 #endif /* Max Xmit idle time (in jiffies) before resend flag char. */ #ifndef PPP_MAXIDLEFLAG #define PPP_MAXIDLEFLAG 100 #endif /* * Packet sizes * * Note - lcp shouldn't be allowed to negotiate stuff outside these * limits. See lcp.h in the pppd directory. * (XXX - these constants should simply be shared by lcp.c instead * of living in lcp.h) */ #define PPP_MTU 1500 /* Default MTU (size of Info field) */ #ifndef PPP_MAXMTU /* #define PPP_MAXMTU 65535 - (PPP_HDRLEN + PPP_FCSLEN) */ #define PPP_MAXMTU 1500 /* Largest MTU we allow */ #endif #define PPP_MINMTU 64 #define PPP_MRU 1500 /* default MRU = max length of info field */ #define PPP_MAXMRU 1500 /* Largest MRU we allow */ #ifndef PPP_DEFMRU #define PPP_DEFMRU 296 /* Try for this */ #endif #define PPP_MINMRU 128 /* No MRUs below this */ #ifndef MAXNAMELEN #define MAXNAMELEN 256 /* max length of hostname or name for auth */ #endif #ifndef MAXSECRETLEN #define MAXSECRETLEN 256 /* max length of password or secret */ #endif #endif /* PPP_SUPPORT */ /* -------------------------------------- ---------- Checksum options ---------- -------------------------------------- */ /** * CHECKSUM_GEN_IP==1: Generate checksums in software for outgoing IP packets. */ #ifndef CHECKSUM_GEN_IP #define CHECKSUM_GEN_IP 1 #endif /** * CHECKSUM_GEN_UDP==1: Generate checksums in software for outgoing UDP packets. */ #ifndef CHECKSUM_GEN_UDP #define CHECKSUM_GEN_UDP 1 #endif /** * CHECKSUM_GEN_TCP==1: Generate checksums in software for outgoing TCP packets. */ #ifndef CHECKSUM_GEN_TCP #define CHECKSUM_GEN_TCP 1 #endif /** * CHECKSUM_GEN_ICMP==1: Generate checksums in software for outgoing ICMP packets. */ #ifndef CHECKSUM_GEN_ICMP #define CHECKSUM_GEN_ICMP 1 #endif /** * CHECKSUM_GEN_ICMP6==1: Generate checksums in software for outgoing ICMP6 packets. */ #ifndef CHECKSUM_GEN_ICMP6 #define CHECKSUM_GEN_ICMP6 1 #endif /** * CHECKSUM_CHECK_IP==1: Check checksums in software for incoming IP packets. */ #ifndef CHECKSUM_CHECK_IP #define CHECKSUM_CHECK_IP 1 #endif /** * CHECKSUM_CHECK_UDP==1: Check checksums in software for incoming UDP packets. */ #ifndef CHECKSUM_CHECK_UDP #define CHECKSUM_CHECK_UDP 1 #endif /** * CHECKSUM_CHECK_TCP==1: Check checksums in software for incoming TCP packets. */ #ifndef CHECKSUM_CHECK_TCP #define CHECKSUM_CHECK_TCP 1 #endif /** * CHECKSUM_CHECK_ICMP==1: Check checksums in software for incoming ICMP packets. */ #ifndef CHECKSUM_CHECK_ICMP #define CHECKSUM_CHECK_ICMP 1 #endif /** * CHECKSUM_CHECK_ICMP6==1: Check checksums in software for incoming ICMPv6 packets */ #ifndef CHECKSUM_CHECK_ICMP6 #define CHECKSUM_CHECK_ICMP6 1 #endif /** * LWIP_CHECKSUM_ON_COPY==1: Calculate checksum when copying data from * application buffers to pbufs. */ #ifndef LWIP_CHECKSUM_ON_COPY #define LWIP_CHECKSUM_ON_COPY 0 #endif /* --------------------------------------- ---------- IPv6 options --------------- --------------------------------------- */ /** * LWIP_IPV6==1: Enable IPv6 */ #ifndef LWIP_IPV6 #define LWIP_IPV6 0 #endif /** * LWIP_IPV6_NUM_ADDRESSES: Number of IPv6 addresses per netif. */ #ifndef LWIP_IPV6_NUM_ADDRESSES #define LWIP_IPV6_NUM_ADDRESSES 3 #endif /** * LWIP_IPV6_FORWARD==1: Forward IPv6 packets across netifs */ #ifndef LWIP_IPV6_FORWARD #define LWIP_IPV6_FORWARD 0 #endif /** * LWIP_ICMP6==1: Enable ICMPv6 (mandatory per RFC) */ #ifndef LWIP_ICMP6 #define LWIP_ICMP6 (LWIP_IPV6) #endif /** * LWIP_ICMP6_DATASIZE: bytes from original packet to send back in * ICMPv6 error messages. */ #ifndef LWIP_ICMP6_DATASIZE #define LWIP_ICMP6_DATASIZE 8 #endif /** * LWIP_ICMP6_HL: default hop limit for ICMPv6 messages */ #ifndef LWIP_ICMP6_HL #define LWIP_ICMP6_HL 255 #endif /** * LWIP_IPV6_MLD==1: Enable multicast listener discovery protocol. */ #ifndef LWIP_IPV6_MLD #define LWIP_IPV6_MLD (LWIP_IPV6) #endif /** * MEMP_NUM_MLD6_GROUP: Max number of IPv6 multicast that can be joined. */ #ifndef MEMP_NUM_MLD6_GROUP #define MEMP_NUM_MLD6_GROUP 4 #endif /** * LWIP_IPV6_FRAG==1: Fragment outgoing IPv6 packets that are too big. */ #ifndef LWIP_IPV6_FRAG #define LWIP_IPV6_FRAG 0 #endif /** * LWIP_IPV6_REASS==1: reassemble incoming IPv6 packets that fragmented */ #ifndef LWIP_IPV6_REASS #define LWIP_IPV6_REASS (LWIP_IPV6) #endif /** * LWIP_ND6_QUEUEING==1: queue outgoing IPv6 packets while MAC address * is being resolved. */ #ifndef LWIP_ND6_QUEUEING #define LWIP_ND6_QUEUEING (LWIP_IPV6) #endif /** * MEMP_NUM_ND6_QUEUE: Max number of IPv6 packets to queue during MAC resolution. */ #ifndef MEMP_NUM_ND6_QUEUE #define MEMP_NUM_ND6_QUEUE 20 #endif /** * LWIP_ND6_NUM_NEIGHBORS: Number of entries in IPv6 neighbor cache */ #ifndef LWIP_ND6_NUM_NEIGHBORS #define LWIP_ND6_NUM_NEIGHBORS 10 #endif /** * LWIP_ND6_NUM_DESTINATIONS: number of entries in IPv6 destination cache */ #ifndef LWIP_ND6_NUM_DESTINATIONS #define LWIP_ND6_NUM_DESTINATIONS 10 #endif /** * LWIP_ND6_NUM_PREFIXES: number of entries in IPv6 on-link prefixes cache */ #ifndef LWIP_ND6_NUM_PREFIXES #define LWIP_ND6_NUM_PREFIXES 5 #endif /** * LWIP_ND6_NUM_ROUTERS: number of entries in IPv6 default router cache */ #ifndef LWIP_ND6_NUM_ROUTERS #define LWIP_ND6_NUM_ROUTERS 3 #endif /** * LWIP_ND6_MAX_MULTICAST_SOLICIT: max number of multicast solicit messages to send * (neighbor solicit and router solicit) */ #ifndef LWIP_ND6_MAX_MULTICAST_SOLICIT #define LWIP_ND6_MAX_MULTICAST_SOLICIT 3 #endif /** * LWIP_ND6_MAX_UNICAST_SOLICIT: max number of unicast neighbor solicitation messages * to send during neighbor reachability detection. */ #ifndef LWIP_ND6_MAX_UNICAST_SOLICIT #define LWIP_ND6_MAX_UNICAST_SOLICIT 3 #endif /** * Unused: See ND RFC (time in milliseconds). */ #ifndef LWIP_ND6_MAX_ANYCAST_DELAY_TIME #define LWIP_ND6_MAX_ANYCAST_DELAY_TIME 1000 #endif /** * Unused: See ND RFC */ #ifndef LWIP_ND6_MAX_NEIGHBOR_ADVERTISEMENT #define LWIP_ND6_MAX_NEIGHBOR_ADVERTISEMENT 3 #endif /** * LWIP_ND6_REACHABLE_TIME: default neighbor reachable time (in milliseconds). * May be updated by router advertisement messages. */ #ifndef LWIP_ND6_REACHABLE_TIME #define LWIP_ND6_REACHABLE_TIME 30000 #endif /** * LWIP_ND6_RETRANS_TIMER: default retransmission timer for solicitation messages */ #ifndef LWIP_ND6_RETRANS_TIMER #define LWIP_ND6_RETRANS_TIMER 1000 #endif /** * LWIP_ND6_DELAY_FIRST_PROBE_TIME: Delay before first unicast neighbor solicitation * message is sent, during neighbor reachability detection. */ #ifndef LWIP_ND6_DELAY_FIRST_PROBE_TIME #define LWIP_ND6_DELAY_FIRST_PROBE_TIME 5000 #endif /** * LWIP_ND6_ALLOW_RA_UPDATES==1: Allow Router Advertisement messages to update * Reachable time and retransmission timers, and netif MTU. */ #ifndef LWIP_ND6_ALLOW_RA_UPDATES #define LWIP_ND6_ALLOW_RA_UPDATES 1 #endif /** * LWIP_IPV6_SEND_ROUTER_SOLICIT==1: Send router solicitation messages during * network startup. */ #ifndef LWIP_IPV6_SEND_ROUTER_SOLICIT #define LWIP_IPV6_SEND_ROUTER_SOLICIT 1 #endif /** * LWIP_ND6_TCP_REACHABILITY_HINTS==1: Allow TCP to provide Neighbor Discovery * with reachability hints for connected destinations. This helps avoid sending * unicast neighbor solicitation messages. */ #ifndef LWIP_ND6_TCP_REACHABILITY_HINTS #define LWIP_ND6_TCP_REACHABILITY_HINTS 1 #endif /** * LWIP_IPV6_AUTOCONFIG==1: Enable stateless address autoconfiguration as per RFC 4862. */ #ifndef LWIP_IPV6_AUTOCONFIG #define LWIP_IPV6_AUTOCONFIG (LWIP_IPV6) #endif /** * LWIP_IPV6_DUP_DETECT_ATTEMPTS: Number of duplicate address detection attempts. */ #ifndef LWIP_IPV6_DUP_DETECT_ATTEMPTS #define LWIP_IPV6_DUP_DETECT_ATTEMPTS 1 #endif /** * LWIP_IPV6_DHCP6==1: enable DHCPv6 stateful address autoconfiguration. */ #ifndef LWIP_IPV6_DHCP6 #define LWIP_IPV6_DHCP6 0 #endif /* --------------------------------------- ---------- Hook options --------------- --------------------------------------- */ /* Hooks are undefined by default, define them to a function if you need them. */ /** * LWIP_HOOK_IP4_INPUT(pbuf, input_netif): * - called from ip_input() (IPv4) * - pbuf: received struct pbuf passed to ip_input() * - input_netif: struct netif on which the packet has been received * Return values: * - 0: Hook has not consumed the packet, packet is processed as normal * - != 0: Hook has consumed the packet. * If the hook consumed the packet, 'pbuf' is in the responsibility of the hook * (i.e. free it when done). */ /** * LWIP_HOOK_IP4_ROUTE(dest): * - called from ip_route() (IPv4) * - dest: destination IPv4 address * Returns the destination netif or NULL if no destination netif is found. In * that case, ip_route() continues as normal. */ /** * LWIP_HOOK_ETHARP_GET_GW(netif, dest): * - called from etharp_output() (IPv4) * - netif: the netif used for sending * - dest: the destination IPv4 address * Returns the IPv4 address of the gateway to handle the specified destination * IPv4 address. If NULL is returned, the netif's default gateway is used. * The returned address MUST be reachable on the specified netif! * This function is meant to implement advanced IPv4 routing together with * LWIP_HOOK_IP4_ROUTE(). The actual routing/gateway table implementation is * not part of lwIP but can e.g. be hidden in the netif's state argument. */ /** * LWIP_HOOK_VLAN_CHECK(netif, eth_hdr, vlan_hdr): * - called from ethernet_input() if VLAN support is enabled * - netif: struct netif on which the packet has been received * - eth_hdr: struct eth_hdr of the packet * - vlan_hdr: struct eth_vlan_hdr of the packet * Return values: * - 0: Packet must be dropped. * - != 0: Packet must be accepted. */ /** * LWIP_HOOK_VLAN_SET(netif, eth_hdr, vlan_hdr): * - called from etharp_raw() and etharp_send_ip() if VLAN support is enabled * - netif: struct netif that the packet will be sent through * - eth_hdr: struct eth_hdr of the packet * - vlan_hdr: struct eth_vlan_hdr of the packet * Return values: * - 0: Packet shall not contain VLAN header. * - != 0: Packet shall contain VLAN header. * Hook can be used to set prio_vid field of vlan_hdr. */ /* --------------------------------------- ---------- Debugging options ---------- --------------------------------------- */ /** * LWIP_DBG_MIN_LEVEL: After masking, the value of the debug is * compared against this value. If it is smaller, then debugging * messages are written. */ #ifndef LWIP_DBG_MIN_LEVEL #define LWIP_DBG_MIN_LEVEL LWIP_DBG_LEVEL_ALL #endif /** * LWIP_DBG_TYPES_ON: A mask that can be used to globally enable/disable * debug messages of certain types. */ #ifndef LWIP_DBG_TYPES_ON #define LWIP_DBG_TYPES_ON LWIP_DBG_ON #endif /** * ETHARP_DEBUG: Enable debugging in etharp.c. */ #ifndef ETHARP_DEBUG #define ETHARP_DEBUG LWIP_DBG_OFF #endif /** * NETIF_DEBUG: Enable debugging in netif.c. */ #ifndef NETIF_DEBUG #define NETIF_DEBUG LWIP_DBG_OFF #endif /** * PBUF_DEBUG: Enable debugging in pbuf.c. */ #ifndef PBUF_DEBUG #define PBUF_DEBUG LWIP_DBG_OFF #endif /** * API_LIB_DEBUG: Enable debugging in api_lib.c. */ #ifndef API_LIB_DEBUG #define API_LIB_DEBUG LWIP_DBG_OFF #endif /** * API_MSG_DEBUG: Enable debugging in api_msg.c. */ #ifndef API_MSG_DEBUG #define API_MSG_DEBUG LWIP_DBG_OFF #endif /** * SOCKETS_DEBUG: Enable debugging in sockets.c. */ #ifndef SOCKETS_DEBUG #define SOCKETS_DEBUG LWIP_DBG_OFF #endif /** * ICMP_DEBUG: Enable debugging in icmp.c. */ #ifndef ICMP_DEBUG #define ICMP_DEBUG LWIP_DBG_OFF #endif /** * IGMP_DEBUG: Enable debugging in igmp.c. */ #ifndef IGMP_DEBUG #define IGMP_DEBUG LWIP_DBG_OFF #endif /** * INET_DEBUG: Enable debugging in inet.c. */ #ifndef INET_DEBUG #define INET_DEBUG LWIP_DBG_OFF #endif /** * IP_DEBUG: Enable debugging for IP. */ #ifndef IP_DEBUG #define IP_DEBUG LWIP_DBG_OFF #endif /** * IP_REASS_DEBUG: Enable debugging in ip_frag.c for both frag & reass. */ #ifndef IP_REASS_DEBUG #define IP_REASS_DEBUG LWIP_DBG_OFF #endif /** * RAW_DEBUG: Enable debugging in raw.c. */ #ifndef RAW_DEBUG #define RAW_DEBUG LWIP_DBG_OFF #endif /** * MEM_DEBUG: Enable debugging in mem.c. */ #ifndef MEM_DEBUG #define MEM_DEBUG LWIP_DBG_OFF #endif /** * MEMP_DEBUG: Enable debugging in memp.c. */ #ifndef MEMP_DEBUG #define MEMP_DEBUG LWIP_DBG_OFF #endif /** * SYS_DEBUG: Enable debugging in sys.c. */ #ifndef SYS_DEBUG #define SYS_DEBUG LWIP_DBG_OFF #endif /** * TIMERS_DEBUG: Enable debugging in timers.c. */ #ifndef TIMERS_DEBUG #define TIMERS_DEBUG LWIP_DBG_OFF #endif /** * TCP_DEBUG: Enable debugging for TCP. */ #ifndef TCP_DEBUG #define TCP_DEBUG LWIP_DBG_OFF #endif /** * TCP_INPUT_DEBUG: Enable debugging in tcp_in.c for incoming debug. */ #ifndef TCP_INPUT_DEBUG #define TCP_INPUT_DEBUG LWIP_DBG_OFF #endif /** * TCP_FR_DEBUG: Enable debugging in tcp_in.c for fast retransmit. */ #ifndef TCP_FR_DEBUG #define TCP_FR_DEBUG LWIP_DBG_OFF #endif /** * TCP_RTO_DEBUG: Enable debugging in TCP for retransmit * timeout. */ #ifndef TCP_RTO_DEBUG #define TCP_RTO_DEBUG LWIP_DBG_OFF #endif /** * TCP_CWND_DEBUG: Enable debugging for TCP congestion window. */ #ifndef TCP_CWND_DEBUG #define TCP_CWND_DEBUG LWIP_DBG_OFF #endif /** * TCP_WND_DEBUG: Enable debugging in tcp_in.c for window updating. */ #ifndef TCP_WND_DEBUG #define TCP_WND_DEBUG LWIP_DBG_OFF #endif /** * TCP_OUTPUT_DEBUG: Enable debugging in tcp_out.c output functions. */ #ifndef TCP_OUTPUT_DEBUG #define TCP_OUTPUT_DEBUG LWIP_DBG_OFF #endif /** * TCP_RST_DEBUG: Enable debugging for TCP with the RST message. */ #ifndef TCP_RST_DEBUG #define TCP_RST_DEBUG LWIP_DBG_OFF #endif /** * TCP_QLEN_DEBUG: Enable debugging for TCP queue lengths. */ #ifndef TCP_QLEN_DEBUG #define TCP_QLEN_DEBUG LWIP_DBG_OFF #endif /** * UDP_DEBUG: Enable debugging in UDP. */ #ifndef UDP_DEBUG #define UDP_DEBUG LWIP_DBG_OFF #endif /** * TCPIP_DEBUG: Enable debugging in tcpip.c. */ #ifndef TCPIP_DEBUG #define TCPIP_DEBUG LWIP_DBG_OFF #endif /** * PPP_DEBUG: Enable debugging for PPP. */ #ifndef PPP_DEBUG #define PPP_DEBUG LWIP_DBG_OFF #endif /** * SLIP_DEBUG: Enable debugging in slipif.c. */ #ifndef SLIP_DEBUG #define SLIP_DEBUG LWIP_DBG_OFF #endif /** * DHCP_DEBUG: Enable debugging in dhcp.c. */ #ifndef DHCP_DEBUG #define DHCP_DEBUG LWIP_DBG_OFF #endif /** * AUTOIP_DEBUG: Enable debugging in autoip.c. */ #ifndef AUTOIP_DEBUG #define AUTOIP_DEBUG LWIP_DBG_OFF #endif /** * SNMP_MSG_DEBUG: Enable debugging for SNMP messages. */ #ifndef SNMP_MSG_DEBUG #define SNMP_MSG_DEBUG LWIP_DBG_OFF #endif /** * SNMP_MIB_DEBUG: Enable debugging for SNMP MIBs. */ #ifndef SNMP_MIB_DEBUG #define SNMP_MIB_DEBUG LWIP_DBG_OFF #endif /** * DNS_DEBUG: Enable debugging for DNS. */ #ifndef DNS_DEBUG #define DNS_DEBUG LWIP_DBG_OFF #endif /** * IP6_DEBUG: Enable debugging for IPv6. */ #ifndef IP6_DEBUG #define IP6_DEBUG LWIP_DBG_OFF #endif #endif /* LWIP_HDR_OPT_H */ ocproxy-1.60/lwip/src/include/lwip/pbuf.h000066400000000000000000000153631303453231400204160ustar00rootroot00000000000000/* * Copyright (c) 2001-2004 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #ifndef LWIP_HDR_PBUF_H #define LWIP_HDR_PBUF_H #include "lwip/opt.h" #include "lwip/err.h" #ifdef __cplusplus extern "C" { #endif /** Currently, the pbuf_custom code is only needed for one specific configuration * of IP_FRAG */ #define LWIP_SUPPORT_CUSTOM_PBUF (IP_FRAG && !IP_FRAG_USES_STATIC_BUF && !LWIP_NETIF_TX_SINGLE_PBUF) /* @todo: We need a mechanism to prevent wasting memory in every pbuf (TCP vs. UDP, IPv4 vs. IPv6: UDP/IPv4 packets may waste up to 28 bytes) */ #define PBUF_TRANSPORT_HLEN 20 #if LWIP_IPV6 #define PBUF_IP_HLEN 40 #else #define PBUF_IP_HLEN 20 #endif typedef enum { PBUF_TRANSPORT, PBUF_IP, PBUF_LINK, PBUF_RAW } pbuf_layer; typedef enum { PBUF_RAM, /* pbuf data is stored in RAM */ PBUF_ROM, /* pbuf data is stored in ROM */ PBUF_REF, /* pbuf comes from the pbuf pool */ PBUF_POOL /* pbuf payload refers to RAM */ } pbuf_type; /** indicates this packet's data should be immediately passed to the application */ #define PBUF_FLAG_PUSH 0x01U /** indicates this is a custom pbuf: pbuf_free and pbuf_header handle such a a pbuf differently */ #define PBUF_FLAG_IS_CUSTOM 0x02U /** indicates this pbuf is UDP multicast to be looped back */ #define PBUF_FLAG_MCASTLOOP 0x04U /** indicates this pbuf was received as link-level broadcast */ #define PBUF_FLAG_LLBCAST 0x08U /** indicates this pbuf was received as link-level multicast */ #define PBUF_FLAG_LLMCAST 0x10U /** indicates this pbuf includes a TCP FIN flag */ #define PBUF_FLAG_TCP_FIN 0x20U struct pbuf { /** next pbuf in singly linked pbuf chain */ struct pbuf *next; /** pointer to the actual data in the buffer */ void *payload; /** * total length of this buffer and all next buffers in chain * belonging to the same packet. * * For non-queue packet chains this is the invariant: * p->tot_len == p->len + (p->next? p->next->tot_len: 0) */ u16_t tot_len; /** length of this buffer */ u16_t len; /** pbuf_type as u8_t instead of enum to save space */ u8_t /*pbuf_type*/ type; /** misc flags */ u8_t flags; /** * the reference count always equals the number of pointers * that refer to this pbuf. This can be pointers from an application, * the stack itself, or pbuf->next pointers from a chain. */ u16_t ref; }; #if LWIP_SUPPORT_CUSTOM_PBUF /** Prototype for a function to free a custom pbuf */ typedef void (*pbuf_free_custom_fn)(struct pbuf *p); /** A custom pbuf: like a pbuf, but following a function pointer to free it. */ struct pbuf_custom { /** The actual pbuf */ struct pbuf pbuf; /** This function is called when pbuf_free deallocates this pbuf(_custom) */ pbuf_free_custom_fn custom_free_function; }; #endif /* LWIP_SUPPORT_CUSTOM_PBUF */ #if LWIP_TCP && TCP_QUEUE_OOSEQ /** Define this to 0 to prevent freeing ooseq pbufs when the PBUF_POOL is empty */ #ifndef PBUF_POOL_FREE_OOSEQ #define PBUF_POOL_FREE_OOSEQ 1 #endif /* PBUF_POOL_FREE_OOSEQ */ #if NO_SYS && PBUF_POOL_FREE_OOSEQ extern volatile u8_t pbuf_free_ooseq_pending; void pbuf_free_ooseq(void); /** When not using sys_check_timeouts(), call PBUF_CHECK_FREE_OOSEQ() at regular intervals from main level to check if ooseq pbufs need to be freed! */ #define PBUF_CHECK_FREE_OOSEQ() do { if(pbuf_free_ooseq_pending) { \ /* pbuf_alloc() reported PBUF_POOL to be empty -> try to free some \ ooseq queued pbufs now */ \ pbuf_free_ooseq(); }}while(0) #endif /* NO_SYS && PBUF_POOL_FREE_OOSEQ*/ #endif /* LWIP_TCP && TCP_QUEUE_OOSEQ */ /* Initializes the pbuf module. This call is empty for now, but may not be in future. */ #define pbuf_init() struct pbuf *pbuf_alloc(pbuf_layer l, u16_t length, pbuf_type type); #if LWIP_SUPPORT_CUSTOM_PBUF struct pbuf *pbuf_alloced_custom(pbuf_layer l, u16_t length, pbuf_type type, struct pbuf_custom *p, void *payload_mem, u16_t payload_mem_len); #endif /* LWIP_SUPPORT_CUSTOM_PBUF */ void pbuf_realloc(struct pbuf *p, u16_t size); u8_t pbuf_header(struct pbuf *p, s16_t header_size); void pbuf_ref(struct pbuf *p); u8_t pbuf_free(struct pbuf *p); u8_t pbuf_clen(struct pbuf *p); void pbuf_cat(struct pbuf *head, struct pbuf *tail); void pbuf_chain(struct pbuf *head, struct pbuf *tail); struct pbuf *pbuf_dechain(struct pbuf *p); err_t pbuf_copy(struct pbuf *p_to, struct pbuf *p_from); u16_t pbuf_copy_partial(struct pbuf *p, void *dataptr, u16_t len, u16_t offset); err_t pbuf_take(struct pbuf *buf, const void *dataptr, u16_t len); struct pbuf *pbuf_coalesce(struct pbuf *p, pbuf_layer layer); #if LWIP_CHECKSUM_ON_COPY err_t pbuf_fill_chksum(struct pbuf *p, u16_t start_offset, const void *dataptr, u16_t len, u16_t *chksum); #endif /* LWIP_CHECKSUM_ON_COPY */ #if LWIP_TCP && TCP_QUEUE_OOSEQ && LWIP_WND_SCALE void pbuf_split_64k(struct pbuf *p, struct pbuf **rest); #endif /* LWIP_TCP && TCP_QUEUE_OOSEQ && LWIP_WND_SCALE */ u8_t pbuf_get_at(struct pbuf* p, u16_t offset); u16_t pbuf_memcmp(struct pbuf* p, u16_t offset, const void* s2, u16_t n); u16_t pbuf_memfind(struct pbuf* p, const void* mem, u16_t mem_len, u16_t start_offset); u16_t pbuf_strstr(struct pbuf* p, const char* substr); #ifdef __cplusplus } #endif #endif /* LWIP_HDR_PBUF_H */ ocproxy-1.60/lwip/src/include/lwip/pppapi.h000066400000000000000000000114021303453231400207410ustar00rootroot00000000000000/* * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * */ #ifndef __LWIP_PPPAPI_H__ #define __LWIP_PPPAPI_H__ #include "lwip/opt.h" #if LWIP_PPP_API /* don't build if not configured for use in lwipopts.h */ #include "lwip/sys.h" #include "netif/ppp/ppp.h" #ifdef __cplusplus extern "C" { #endif struct pppapi_msg_msg { #if !LWIP_TCPIP_CORE_LOCKING sys_sem_t sem; #endif /* !LWIP_TCPIP_CORE_LOCKING */ int err; ppp_pcb *ppp; union { struct { u8_t authtype; char *user; char *passwd; } setauth; #if PPP_NOTIFY_PHASE struct { ppp_notify_phase_cb_fn notify_phase_cb; } setnotifyphasecb; #endif /* PPP_NOTIFY_PHASE */ #if PPPOS_SUPPORT struct { sio_fd_t fd; ppp_link_status_cb_fn link_status_cb; void *ctx_cb; } serialcreate; #endif /* PPPOS_SUPPORT */ #if PPPOE_SUPPORT struct { struct netif *ethif; const char *service_name; const char *concentrator_name; ppp_link_status_cb_fn link_status_cb; void *ctx_cb; } ethernetcreate; #endif /* PPPOE_SUPPORT */ #if PPPOL2TP_SUPPORT struct { struct netif *netif; ip_addr_t *ipaddr; u16_t port; #if PPPOL2TP_AUTH_SUPPORT u8_t *secret; u8_t secret_len; #endif /* PPPOL2TP_AUTH_SUPPORT */ ppp_link_status_cb_fn link_status_cb; void *ctx_cb; } l2tpcreate; #endif /* PPPOL2TP_SUPPORT */ struct { u16_t holdoff; } open; struct { int cmd; void *arg; } ioctl; #if LWIP_NETIF_STATUS_CALLBACK struct { netif_status_callback_fn status_callback; } netifstatuscallback; #endif /* LWIP_NETIF_STATUS_CALLBACK */ #if LWIP_NETIF_LINK_CALLBACK struct { netif_status_callback_fn link_callback; } netiflinkcallback; #endif /* LWIP_NETIF_LINK_CALLBACK */ } msg; }; struct pppapi_msg { void (* function)(struct pppapi_msg_msg *msg); struct pppapi_msg_msg msg; }; /* API for application */ ppp_pcb *pppapi_new(void); void pppapi_set_default(ppp_pcb *pcb); void pppapi_set_auth(ppp_pcb *pcb, u8_t authtype, char *user, char *passwd); #if PPP_NOTIFY_PHASE void pppapi_set_notify_phase_callback(ppp_pcb *pcb, ppp_notify_phase_cb_fn notify_phase_cb); #endif /* PPP_NOTIFY_PHASE */ #if PPPOS_SUPPORT int pppapi_over_serial_create(ppp_pcb *pcb, sio_fd_t fd, ppp_link_status_cb_fn link_status_cb, void *ctx_cb); #endif /* PPPOS_SUPPORT */ #if PPPOE_SUPPORT int pppapi_over_ethernet_create(ppp_pcb *pcb, struct netif *ethif, const char *service_name, const char *concentrator_name, ppp_link_status_cb_fn link_status_cb, void *ctx_cb); #endif /* PPPOE_SUPPORT */ #if PPPOL2TP_SUPPORT int pppapi_over_l2tp_create(ppp_pcb *pcb, struct netif *netif, ip_addr_t *ipaddr, u16_t port, u8_t *secret, u8_t secret_len, ppp_link_status_cb_fn link_status_cb, void *ctx_cb); #endif /* PPPOL2TP_SUPPORT */ int pppapi_open(ppp_pcb *pcb, u16_t holdoff); int pppapi_close(ppp_pcb *pcb); void pppapi_sighup(ppp_pcb *pcb); int pppapi_delete(ppp_pcb *pcb); int pppapi_ioctl(ppp_pcb *pcb, int cmd, void *arg); #if LWIP_NETIF_STATUS_CALLBACK void pppapi_set_netif_statuscallback(ppp_pcb *pcb, netif_status_callback_fn status_callback); #endif /* LWIP_NETIF_STATUS_CALLBACK */ #if LWIP_NETIF_LINK_CALLBACK void pppapi_set_netif_linkcallback(ppp_pcb *pcb, netif_status_callback_fn link_callback); #endif /* LWIP_NETIF_LINK_CALLBACK */ #ifdef __cplusplus } #endif #endif /* LWIP_PPP_API */ #endif /* __LWIP_PPPAPI_H__ */ ocproxy-1.60/lwip/src/include/lwip/raw.h000066400000000000000000000115361303453231400202510ustar00rootroot00000000000000/* * Copyright (c) 2001-2004 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #ifndef LWIP_HDR_RAW_H #define LWIP_HDR_RAW_H #include "lwip/opt.h" #if LWIP_RAW /* don't build if not configured for use in lwipopts.h */ #include "lwip/pbuf.h" #include "lwip/def.h" #include "lwip/ip.h" #include "lwip/ip_addr.h" #include "lwip/ip6_addr.h" #ifdef __cplusplus extern "C" { #endif struct raw_pcb; /** Function prototype for raw pcb receive callback functions. * @param arg user supplied argument (raw_pcb.recv_arg) * @param pcb the raw_pcb which received data * @param p the packet buffer that was received * @param addr the remote IP address from which the packet was received * @return 1 if the packet was 'eaten' (aka. deleted), * 0 if the packet lives on * If returning 1, the callback is responsible for freeing the pbuf * if it's not used any more. */ typedef u8_t (*raw_recv_fn)(void *arg, struct raw_pcb *pcb, struct pbuf *p, ip_addr_t *addr); #if LWIP_IPV6 /** Function prototype for raw pcb IPv6 receive callback functions. * @param arg user supplied argument (raw_pcb.recv_arg) * @param pcb the raw_pcb which received data * @param p the packet buffer that was received * @param addr the remote IPv6 address from which the packet was received * @return 1 if the packet was 'eaten' (aka. deleted), * 0 if the packet lives on * If returning 1, the callback is responsible for freeing the pbuf * if it's not used any more. */ typedef u8_t (*raw_recv_ip6_fn)(void *arg, struct raw_pcb *pcb, struct pbuf *p, ip6_addr_t *addr); #endif /* LWIP_IPV6 */ #if LWIP_IPV6 #define RAW_PCB_RECV_IP6 raw_recv_ip6_fn ip6; #else #define RAW_PCB_RECV_IP6 #endif /* LWIP_IPV6 */ struct raw_pcb { /* Common members of all PCB types */ IP_PCB; struct raw_pcb *next; u8_t protocol; /** receive callback function */ union { raw_recv_fn ip4; RAW_PCB_RECV_IP6 } recv; /* user-supplied argument for the recv callback */ void *recv_arg; #if LWIP_IPV6 /* fields for handling checksum computations as per RFC3542. */ u16_t chksum_offset; u8_t chksum_reqd; #endif }; /* The following functions is the application layer interface to the RAW code. */ struct raw_pcb * raw_new (u8_t proto); void raw_remove (struct raw_pcb *pcb); err_t raw_bind (struct raw_pcb *pcb, ip_addr_t *ipaddr); err_t raw_connect (struct raw_pcb *pcb, ip_addr_t *ipaddr); void raw_recv (struct raw_pcb *pcb, raw_recv_fn recv, void *recv_arg); err_t raw_sendto (struct raw_pcb *pcb, struct pbuf *p, ip_addr_t *ipaddr); err_t raw_send (struct raw_pcb *pcb, struct pbuf *p); #if LWIP_IPV6 struct raw_pcb * raw_new_ip6 (u8_t proto); #define raw_bind_ip6(pcb, ip6addr) raw_bind(pcb, ip6_2_ip(ip6addr)) #define raw_connect_ip6(pcb, ip6addr) raw_connect(pcb, ip6_2_ip(ip6addr)) #define raw_recv_ip6(pcb, recv_ip6_fn, recv_arg) raw_recv(pcb, (raw_recv_fn)recv_ip6_fn, recv_arg) #define raw_sendto_ip6(pcb, pbuf, ip6addr) raw_sendto(pcb, pbuf, ip6_2_ip(ip6addr)) #endif /* LWIP_IPV6 */ /* The following functions are the lower layer interface to RAW. */ u8_t raw_input (struct pbuf *p, struct netif *inp); #define raw_init() /* Compatibility define, not init needed. */ #ifdef __cplusplus } #endif #endif /* LWIP_RAW */ #endif /* LWIP_HDR_RAW_H */ ocproxy-1.60/lwip/src/include/lwip/sio.h000066400000000000000000000101741303453231400202470ustar00rootroot00000000000000/* * Copyright (c) 2001-2004 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. */ /* * This is the interface to the platform specific serial IO module * It needs to be implemented by those platforms which need SLIP or PPP */ #ifndef SIO_H #define SIO_H #include "lwip/arch.h" #ifdef __cplusplus extern "C" { #endif /* If you want to define sio_fd_t elsewhere or differently, define this in your cc.h file. */ #ifndef __sio_fd_t_defined typedef void * sio_fd_t; #endif /* The following functions can be defined to something else in your cc.h file or be implemented in your custom sio.c file. */ #ifndef sio_open /** * Opens a serial device for communication. * * @param devnum device number * @return handle to serial device if successful, NULL otherwise */ sio_fd_t sio_open(u8_t devnum); #endif #ifndef sio_send /** * Sends a single character to the serial device. * * @param c character to send * @param fd serial device handle * * @note This function will block until the character can be sent. */ void sio_send(u8_t c, sio_fd_t fd); #endif #ifndef sio_recv /** * Receives a single character from the serial device. * * @param fd serial device handle * * @note This function will block until a character is received. */ u8_t sio_recv(sio_fd_t fd); #endif #ifndef sio_read /** * Reads from the serial device. * * @param fd serial device handle * @param data pointer to data buffer for receiving * @param len maximum length (in bytes) of data to receive * @return number of bytes actually received - may be 0 if aborted by sio_read_abort * * @note This function will block until data can be received. The blocking * can be cancelled by calling sio_read_abort(). */ u32_t sio_read(sio_fd_t fd, u8_t *data, u32_t len); #endif #ifndef sio_tryread /** * Tries to read from the serial device. Same as sio_read but returns * immediately if no data is available and never blocks. * * @param fd serial device handle * @param data pointer to data buffer for receiving * @param len maximum length (in bytes) of data to receive * @return number of bytes actually received */ u32_t sio_tryread(sio_fd_t fd, u8_t *data, u32_t len); #endif #ifndef sio_write /** * Writes to the serial device. * * @param fd serial device handle * @param data pointer to data to send * @param len length (in bytes) of data to send * @return number of bytes actually sent * * @note This function will block until all data can be sent. */ u32_t sio_write(sio_fd_t fd, u8_t *data, u32_t len); #endif #ifndef sio_read_abort /** * Aborts a blocking sio_read() call. * * @param fd serial device handle */ void sio_read_abort(sio_fd_t fd); #endif #ifdef __cplusplus } #endif #endif /* SIO_H */ ocproxy-1.60/lwip/src/include/lwip/snmp.h000066400000000000000000000302441303453231400204320ustar00rootroot00000000000000/* * Copyright (c) 2001, 2002 Leon Woestenberg * Copyright (c) 2001, 2002 Axon Digital Design B.V., The Netherlands. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Leon Woestenberg * */ #ifndef LWIP_HDR_SNMP_H #define LWIP_HDR_SNMP_H #include "lwip/opt.h" #ifdef __cplusplus extern "C" { #endif #include "lwip/ip_addr.h" struct udp_pcb; struct netif; /** * @see RFC1213, "MIB-II, 6. Definitions" */ enum snmp_ifType { snmp_ifType_other=1, /* none of the following */ snmp_ifType_regular1822, snmp_ifType_hdh1822, snmp_ifType_ddn_x25, snmp_ifType_rfc877_x25, snmp_ifType_ethernet_csmacd, snmp_ifType_iso88023_csmacd, snmp_ifType_iso88024_tokenBus, snmp_ifType_iso88025_tokenRing, snmp_ifType_iso88026_man, snmp_ifType_starLan, snmp_ifType_proteon_10Mbit, snmp_ifType_proteon_80Mbit, snmp_ifType_hyperchannel, snmp_ifType_fddi, snmp_ifType_lapb, snmp_ifType_sdlc, snmp_ifType_ds1, /* T-1 */ snmp_ifType_e1, /* european equiv. of T-1 */ snmp_ifType_basicISDN, snmp_ifType_primaryISDN, /* proprietary serial */ snmp_ifType_propPointToPointSerial, snmp_ifType_ppp, snmp_ifType_softwareLoopback, snmp_ifType_eon, /* CLNP over IP [11] */ snmp_ifType_ethernet_3Mbit, snmp_ifType_nsip, /* XNS over IP */ snmp_ifType_slip, /* generic SLIP */ snmp_ifType_ultra, /* ULTRA technologies */ snmp_ifType_ds3, /* T-3 */ snmp_ifType_sip, /* SMDS */ snmp_ifType_frame_relay }; #if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */ /** SNMP "sysuptime" Interval */ #define SNMP_SYSUPTIME_INTERVAL 10 /** fixed maximum length for object identifier type */ #define LWIP_SNMP_OBJ_ID_LEN 32 /** internal object identifier representation */ struct snmp_obj_id { u8_t len; s32_t id[LWIP_SNMP_OBJ_ID_LEN]; }; /* system */ void snmp_set_sysdescr(const u8_t* str, const u8_t* len); void snmp_set_sysobjid(const struct snmp_obj_id *oid); void snmp_get_sysobjid_ptr(const struct snmp_obj_id **oid); void snmp_inc_sysuptime(void); void snmp_add_sysuptime(u32_t value); void snmp_get_sysuptime(u32_t *value); void snmp_set_syscontact(u8_t *ocstr, u8_t *ocstrlen); void snmp_set_sysname(u8_t *ocstr, u8_t *ocstrlen); void snmp_set_syslocation(u8_t *ocstr, u8_t *ocstrlen); /* network interface */ void snmp_add_ifinoctets(struct netif *ni, u32_t value); void snmp_inc_ifinucastpkts(struct netif *ni); void snmp_inc_ifinnucastpkts(struct netif *ni); void snmp_inc_ifindiscards(struct netif *ni); void snmp_add_ifoutoctets(struct netif *ni, u32_t value); void snmp_inc_ifoutucastpkts(struct netif *ni); void snmp_inc_ifoutnucastpkts(struct netif *ni); void snmp_inc_ifoutdiscards(struct netif *ni); void snmp_inc_iflist(void); void snmp_dec_iflist(void); /* ARP (for atTable and ipNetToMediaTable) */ void snmp_insert_arpidx_tree(struct netif *ni, ip_addr_t *ip); void snmp_delete_arpidx_tree(struct netif *ni, ip_addr_t *ip); /* IP */ void snmp_inc_ipinreceives(void); void snmp_inc_ipinhdrerrors(void); void snmp_inc_ipinaddrerrors(void); void snmp_inc_ipforwdatagrams(void); void snmp_inc_ipinunknownprotos(void); void snmp_inc_ipindiscards(void); void snmp_inc_ipindelivers(void); void snmp_inc_ipoutrequests(void); void snmp_inc_ipoutdiscards(void); void snmp_inc_ipoutnoroutes(void); void snmp_inc_ipreasmreqds(void); void snmp_inc_ipreasmoks(void); void snmp_inc_ipreasmfails(void); void snmp_inc_ipfragoks(void); void snmp_inc_ipfragfails(void); void snmp_inc_ipfragcreates(void); void snmp_inc_iproutingdiscards(void); void snmp_insert_ipaddridx_tree(struct netif *ni); void snmp_delete_ipaddridx_tree(struct netif *ni); void snmp_insert_iprteidx_tree(u8_t dflt, struct netif *ni); void snmp_delete_iprteidx_tree(u8_t dflt, struct netif *ni); /* ICMP */ void snmp_inc_icmpinmsgs(void); void snmp_inc_icmpinerrors(void); void snmp_inc_icmpindestunreachs(void); void snmp_inc_icmpintimeexcds(void); void snmp_inc_icmpinparmprobs(void); void snmp_inc_icmpinsrcquenchs(void); void snmp_inc_icmpinredirects(void); void snmp_inc_icmpinechos(void); void snmp_inc_icmpinechoreps(void); void snmp_inc_icmpintimestamps(void); void snmp_inc_icmpintimestampreps(void); void snmp_inc_icmpinaddrmasks(void); void snmp_inc_icmpinaddrmaskreps(void); void snmp_inc_icmpoutmsgs(void); void snmp_inc_icmpouterrors(void); void snmp_inc_icmpoutdestunreachs(void); void snmp_inc_icmpouttimeexcds(void); void snmp_inc_icmpoutparmprobs(void); void snmp_inc_icmpoutsrcquenchs(void); void snmp_inc_icmpoutredirects(void); void snmp_inc_icmpoutechos(void); void snmp_inc_icmpoutechoreps(void); void snmp_inc_icmpouttimestamps(void); void snmp_inc_icmpouttimestampreps(void); void snmp_inc_icmpoutaddrmasks(void); void snmp_inc_icmpoutaddrmaskreps(void); /* TCP */ void snmp_inc_tcpactiveopens(void); void snmp_inc_tcppassiveopens(void); void snmp_inc_tcpattemptfails(void); void snmp_inc_tcpestabresets(void); void snmp_inc_tcpinsegs(void); void snmp_inc_tcpoutsegs(void); void snmp_inc_tcpretranssegs(void); void snmp_inc_tcpinerrs(void); void snmp_inc_tcpoutrsts(void); /* UDP */ void snmp_inc_udpindatagrams(void); void snmp_inc_udpnoports(void); void snmp_inc_udpinerrors(void); void snmp_inc_udpoutdatagrams(void); void snmp_insert_udpidx_tree(struct udp_pcb *pcb); void snmp_delete_udpidx_tree(struct udp_pcb *pcb); /* SNMP */ void snmp_inc_snmpinpkts(void); void snmp_inc_snmpoutpkts(void); void snmp_inc_snmpinbadversions(void); void snmp_inc_snmpinbadcommunitynames(void); void snmp_inc_snmpinbadcommunityuses(void); void snmp_inc_snmpinasnparseerrs(void); void snmp_inc_snmpintoobigs(void); void snmp_inc_snmpinnosuchnames(void); void snmp_inc_snmpinbadvalues(void); void snmp_inc_snmpinreadonlys(void); void snmp_inc_snmpingenerrs(void); void snmp_add_snmpintotalreqvars(u8_t value); void snmp_add_snmpintotalsetvars(u8_t value); void snmp_inc_snmpingetrequests(void); void snmp_inc_snmpingetnexts(void); void snmp_inc_snmpinsetrequests(void); void snmp_inc_snmpingetresponses(void); void snmp_inc_snmpintraps(void); void snmp_inc_snmpouttoobigs(void); void snmp_inc_snmpoutnosuchnames(void); void snmp_inc_snmpoutbadvalues(void); void snmp_inc_snmpoutgenerrs(void); void snmp_inc_snmpoutgetrequests(void); void snmp_inc_snmpoutgetnexts(void); void snmp_inc_snmpoutsetrequests(void); void snmp_inc_snmpoutgetresponses(void); void snmp_inc_snmpouttraps(void); void snmp_get_snmpgrpid_ptr(struct snmp_obj_id **oid); void snmp_set_snmpenableauthentraps(u8_t *value); void snmp_get_snmpenableauthentraps(u8_t *value); /* LWIP_SNMP support not available */ /* define everything to be empty */ #else /* system */ #define snmp_set_sysdescr(str, len) #define snmp_set_sysobjid(oid); #define snmp_get_sysobjid_ptr(oid) #define snmp_inc_sysuptime() #define snmp_add_sysuptime(value) #define snmp_get_sysuptime(value) #define snmp_set_syscontact(ocstr, ocstrlen); #define snmp_set_sysname(ocstr, ocstrlen); #define snmp_set_syslocation(ocstr, ocstrlen); /* network interface */ #define snmp_add_ifinoctets(ni,value) #define snmp_inc_ifinucastpkts(ni) #define snmp_inc_ifinnucastpkts(ni) #define snmp_inc_ifindiscards(ni) #define snmp_add_ifoutoctets(ni,value) #define snmp_inc_ifoutucastpkts(ni) #define snmp_inc_ifoutnucastpkts(ni) #define snmp_inc_ifoutdiscards(ni) #define snmp_inc_iflist() #define snmp_dec_iflist() /* ARP */ #define snmp_insert_arpidx_tree(ni,ip) #define snmp_delete_arpidx_tree(ni,ip) /* IP */ #define snmp_inc_ipinreceives() #define snmp_inc_ipinhdrerrors() #define snmp_inc_ipinaddrerrors() #define snmp_inc_ipforwdatagrams() #define snmp_inc_ipinunknownprotos() #define snmp_inc_ipindiscards() #define snmp_inc_ipindelivers() #define snmp_inc_ipoutrequests() #define snmp_inc_ipoutdiscards() #define snmp_inc_ipoutnoroutes() #define snmp_inc_ipreasmreqds() #define snmp_inc_ipreasmoks() #define snmp_inc_ipreasmfails() #define snmp_inc_ipfragoks() #define snmp_inc_ipfragfails() #define snmp_inc_ipfragcreates() #define snmp_inc_iproutingdiscards() #define snmp_insert_ipaddridx_tree(ni) #define snmp_delete_ipaddridx_tree(ni) #define snmp_insert_iprteidx_tree(dflt, ni) #define snmp_delete_iprteidx_tree(dflt, ni) /* ICMP */ #define snmp_inc_icmpinmsgs() #define snmp_inc_icmpinerrors() #define snmp_inc_icmpindestunreachs() #define snmp_inc_icmpintimeexcds() #define snmp_inc_icmpinparmprobs() #define snmp_inc_icmpinsrcquenchs() #define snmp_inc_icmpinredirects() #define snmp_inc_icmpinechos() #define snmp_inc_icmpinechoreps() #define snmp_inc_icmpintimestamps() #define snmp_inc_icmpintimestampreps() #define snmp_inc_icmpinaddrmasks() #define snmp_inc_icmpinaddrmaskreps() #define snmp_inc_icmpoutmsgs() #define snmp_inc_icmpouterrors() #define snmp_inc_icmpoutdestunreachs() #define snmp_inc_icmpouttimeexcds() #define snmp_inc_icmpoutparmprobs() #define snmp_inc_icmpoutsrcquenchs() #define snmp_inc_icmpoutredirects() #define snmp_inc_icmpoutechos() #define snmp_inc_icmpoutechoreps() #define snmp_inc_icmpouttimestamps() #define snmp_inc_icmpouttimestampreps() #define snmp_inc_icmpoutaddrmasks() #define snmp_inc_icmpoutaddrmaskreps() /* TCP */ #define snmp_inc_tcpactiveopens() #define snmp_inc_tcppassiveopens() #define snmp_inc_tcpattemptfails() #define snmp_inc_tcpestabresets() #define snmp_inc_tcpinsegs() #define snmp_inc_tcpoutsegs() #define snmp_inc_tcpretranssegs() #define snmp_inc_tcpinerrs() #define snmp_inc_tcpoutrsts() /* UDP */ #define snmp_inc_udpindatagrams() #define snmp_inc_udpnoports() #define snmp_inc_udpinerrors() #define snmp_inc_udpoutdatagrams() #define snmp_insert_udpidx_tree(pcb) #define snmp_delete_udpidx_tree(pcb) /* SNMP */ #define snmp_inc_snmpinpkts() #define snmp_inc_snmpoutpkts() #define snmp_inc_snmpinbadversions() #define snmp_inc_snmpinbadcommunitynames() #define snmp_inc_snmpinbadcommunityuses() #define snmp_inc_snmpinasnparseerrs() #define snmp_inc_snmpintoobigs() #define snmp_inc_snmpinnosuchnames() #define snmp_inc_snmpinbadvalues() #define snmp_inc_snmpinreadonlys() #define snmp_inc_snmpingenerrs() #define snmp_add_snmpintotalreqvars(value) #define snmp_add_snmpintotalsetvars(value) #define snmp_inc_snmpingetrequests() #define snmp_inc_snmpingetnexts() #define snmp_inc_snmpinsetrequests() #define snmp_inc_snmpingetresponses() #define snmp_inc_snmpintraps() #define snmp_inc_snmpouttoobigs() #define snmp_inc_snmpoutnosuchnames() #define snmp_inc_snmpoutbadvalues() #define snmp_inc_snmpoutgenerrs() #define snmp_inc_snmpoutgetrequests() #define snmp_inc_snmpoutgetnexts() #define snmp_inc_snmpoutsetrequests() #define snmp_inc_snmpoutgetresponses() #define snmp_inc_snmpouttraps() #define snmp_get_snmpgrpid_ptr(oid) #define snmp_set_snmpenableauthentraps(value) #define snmp_get_snmpenableauthentraps(value) #endif /* LWIP_SNMP */ #ifdef __cplusplus } #endif #endif /* LWIP_HDR_SNMP_H */ ocproxy-1.60/lwip/src/include/lwip/snmp_asn1.h000066400000000000000000000077111303453231400213570ustar00rootroot00000000000000/** * @file * Abstract Syntax Notation One (ISO 8824, 8825) codec. */ /* * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * Author: Christiaan Simons */ #ifndef LWIP_HDR_SNMP_ASN1_H #define LWIP_HDR_SNMP_ASN1_H #include "lwip/opt.h" #include "lwip/err.h" #include "lwip/pbuf.h" #include "lwip/snmp.h" #if LWIP_SNMP #ifdef __cplusplus extern "C" { #endif #define SNMP_ASN1_UNIV (0) /* (!0x80 | !0x40) */ #define SNMP_ASN1_APPLIC (0x40) /* (!0x80 | 0x40) */ #define SNMP_ASN1_CONTXT (0x80) /* ( 0x80 | !0x40) */ #define SNMP_ASN1_CONSTR (0x20) /* ( 0x20) */ #define SNMP_ASN1_PRIMIT (0) /* (!0x20) */ /* universal tags */ #define SNMP_ASN1_INTEG 2 #define SNMP_ASN1_OC_STR 4 #define SNMP_ASN1_NUL 5 #define SNMP_ASN1_OBJ_ID 6 #define SNMP_ASN1_SEQ 16 /* application specific (SNMP) tags */ #define SNMP_ASN1_IPADDR 0 /* octet string size(4) */ #define SNMP_ASN1_COUNTER 1 /* u32_t */ #define SNMP_ASN1_GAUGE 2 /* u32_t */ #define SNMP_ASN1_TIMETICKS 3 /* u32_t */ #define SNMP_ASN1_OPAQUE 4 /* octet string */ /* context specific (SNMP) tags */ #define SNMP_ASN1_PDU_GET_REQ 0 #define SNMP_ASN1_PDU_GET_NEXT_REQ 1 #define SNMP_ASN1_PDU_GET_RESP 2 #define SNMP_ASN1_PDU_SET_REQ 3 #define SNMP_ASN1_PDU_TRAP 4 err_t snmp_asn1_dec_type(struct pbuf *p, u16_t ofs, u8_t *type); err_t snmp_asn1_dec_length(struct pbuf *p, u16_t ofs, u8_t *octets_used, u16_t *length); err_t snmp_asn1_dec_u32t(struct pbuf *p, u16_t ofs, u16_t len, u32_t *value); err_t snmp_asn1_dec_s32t(struct pbuf *p, u16_t ofs, u16_t len, s32_t *value); err_t snmp_asn1_dec_oid(struct pbuf *p, u16_t ofs, u16_t len, struct snmp_obj_id *oid); err_t snmp_asn1_dec_raw(struct pbuf *p, u16_t ofs, u16_t len, u16_t raw_len, u8_t *raw); void snmp_asn1_enc_length_cnt(u16_t length, u8_t *octets_needed); void snmp_asn1_enc_u32t_cnt(u32_t value, u16_t *octets_needed); void snmp_asn1_enc_s32t_cnt(s32_t value, u16_t *octets_needed); void snmp_asn1_enc_oid_cnt(u8_t ident_len, s32_t *ident, u16_t *octets_needed); err_t snmp_asn1_enc_type(struct pbuf *p, u16_t ofs, u8_t type); err_t snmp_asn1_enc_length(struct pbuf *p, u16_t ofs, u16_t length); err_t snmp_asn1_enc_u32t(struct pbuf *p, u16_t ofs, u16_t octets_needed, u32_t value); err_t snmp_asn1_enc_s32t(struct pbuf *p, u16_t ofs, u16_t octets_needed, s32_t value); err_t snmp_asn1_enc_oid(struct pbuf *p, u16_t ofs, u8_t ident_len, s32_t *ident); err_t snmp_asn1_enc_raw(struct pbuf *p, u16_t ofs, u16_t raw_len, u8_t *raw); #ifdef __cplusplus } #endif #endif /* LWIP_SNMP */ #endif /* LWIP_HDR_SNMP_ASN1_H */ ocproxy-1.60/lwip/src/include/lwip/snmp_msg.h000066400000000000000000000224601303453231400213010ustar00rootroot00000000000000/** * @file * SNMP Agent message handling structures. */ /* * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * Author: Christiaan Simons */ #ifndef LWIP_HDR_SNMP_MSG_H #define LWIP_HDR_SNMP_MSG_H #include "lwip/opt.h" #include "lwip/snmp.h" #include "lwip/snmp_structs.h" #include "lwip/ip_addr.h" #include "lwip/err.h" #if LWIP_SNMP #if SNMP_PRIVATE_MIB /* When using a private MIB, you have to create a file 'private_mib.h' that contains * a 'struct mib_array_node mib_private' which contains your MIB. */ #include "private_mib.h" #endif #ifdef __cplusplus extern "C" { #endif /* The listen port of the SNMP agent. Clients have to make their requests to this port. Most standard clients won't work if you change this! */ #ifndef SNMP_IN_PORT #define SNMP_IN_PORT 161 #endif /* The remote port the SNMP agent sends traps to. Most standard trap sinks won't work if you change this! */ #ifndef SNMP_TRAP_PORT #define SNMP_TRAP_PORT 162 #endif #define SNMP_ES_NOERROR 0 #define SNMP_ES_TOOBIG 1 #define SNMP_ES_NOSUCHNAME 2 #define SNMP_ES_BADVALUE 3 #define SNMP_ES_READONLY 4 #define SNMP_ES_GENERROR 5 #define SNMP_GENTRAP_COLDSTART 0 #define SNMP_GENTRAP_WARMSTART 1 #define SNMP_GENTRAP_AUTHFAIL 4 #define SNMP_GENTRAP_ENTERPRISESPC 6 struct snmp_varbind { /* next pointer, NULL for last in list */ struct snmp_varbind *next; /* previous pointer, NULL for first in list */ struct snmp_varbind *prev; /* object identifier length (in s32_t) */ u8_t ident_len; /* object identifier array */ s32_t *ident; /* object value ASN1 type */ u8_t value_type; /* object value length (in u8_t) */ u8_t value_len; /* object value */ void *value; /* encoding varbind seq length length */ u8_t seqlenlen; /* encoding object identifier length length */ u8_t olenlen; /* encoding object value length length */ u8_t vlenlen; /* encoding varbind seq length */ u16_t seqlen; /* encoding object identifier length */ u16_t olen; /* encoding object value length */ u16_t vlen; }; struct snmp_varbind_root { struct snmp_varbind *head; struct snmp_varbind *tail; /* number of variable bindings in list */ u8_t count; /* encoding varbind-list seq length length */ u8_t seqlenlen; /* encoding varbind-list seq length */ u16_t seqlen; }; /** output response message header length fields */ struct snmp_resp_header_lengths { /* encoding error-index length length */ u8_t erridxlenlen; /* encoding error-status length length */ u8_t errstatlenlen; /* encoding request id length length */ u8_t ridlenlen; /* encoding pdu length length */ u8_t pdulenlen; /* encoding community length length */ u8_t comlenlen; /* encoding version length length */ u8_t verlenlen; /* encoding sequence length length */ u8_t seqlenlen; /* encoding error-index length */ u16_t erridxlen; /* encoding error-status length */ u16_t errstatlen; /* encoding request id length */ u16_t ridlen; /* encoding pdu length */ u16_t pdulen; /* encoding community length */ u16_t comlen; /* encoding version length */ u16_t verlen; /* encoding sequence length */ u16_t seqlen; }; /** output response message header length fields */ struct snmp_trap_header_lengths { /* encoding timestamp length length */ u8_t tslenlen; /* encoding specific-trap length length */ u8_t strplenlen; /* encoding generic-trap length length */ u8_t gtrplenlen; /* encoding agent-addr length length */ u8_t aaddrlenlen; /* encoding enterprise-id length length */ u8_t eidlenlen; /* encoding pdu length length */ u8_t pdulenlen; /* encoding community length length */ u8_t comlenlen; /* encoding version length length */ u8_t verlenlen; /* encoding sequence length length */ u8_t seqlenlen; /* encoding timestamp length */ u16_t tslen; /* encoding specific-trap length */ u16_t strplen; /* encoding generic-trap length */ u16_t gtrplen; /* encoding agent-addr length */ u16_t aaddrlen; /* encoding enterprise-id length */ u16_t eidlen; /* encoding pdu length */ u16_t pdulen; /* encoding community length */ u16_t comlen; /* encoding version length */ u16_t verlen; /* encoding sequence length */ u16_t seqlen; }; /* Accepting new SNMP messages. */ #define SNMP_MSG_EMPTY 0 /* Search for matching object for variable binding. */ #define SNMP_MSG_SEARCH_OBJ 1 /* Perform SNMP operation on in-memory object. Pass-through states, for symmetry only. */ #define SNMP_MSG_INTERNAL_GET_OBJDEF 2 #define SNMP_MSG_INTERNAL_GET_VALUE 3 #define SNMP_MSG_INTERNAL_SET_TEST 4 #define SNMP_MSG_INTERNAL_GET_OBJDEF_S 5 #define SNMP_MSG_INTERNAL_SET_VALUE 6 /* Perform SNMP operation on object located externally. In theory this could be used for building a proxy agent. Practical use is for an enterprise spc. app. gateway. */ #define SNMP_MSG_EXTERNAL_GET_OBJDEF 7 #define SNMP_MSG_EXTERNAL_GET_VALUE 8 #define SNMP_MSG_EXTERNAL_SET_TEST 9 #define SNMP_MSG_EXTERNAL_GET_OBJDEF_S 10 #define SNMP_MSG_EXTERNAL_SET_VALUE 11 #define SNMP_COMMUNITY_STR_LEN 64 struct snmp_msg_pstat { /* lwIP local port (161) binding */ struct udp_pcb *pcb; /* source IP address */ ip_addr_t sip; /* source UDP port */ u16_t sp; /* request type */ u8_t rt; /* request ID */ s32_t rid; /* error status */ s32_t error_status; /* error index */ s32_t error_index; /* community name (zero terminated) */ u8_t community[SNMP_COMMUNITY_STR_LEN + 1]; /* community string length (exclusive zero term) */ u8_t com_strlen; /* one out of MSG_EMPTY, MSG_DEMUX, MSG_INTERNAL, MSG_EXTERNAL_x */ u8_t state; /* saved arguments for MSG_EXTERNAL_x */ struct mib_external_node *ext_mib_node; struct snmp_name_ptr ext_name_ptr; struct obj_def ext_object_def; struct snmp_obj_id ext_oid; /* index into input variable binding list */ u8_t vb_idx; /* ptr into input variable binding list */ struct snmp_varbind *vb_ptr; /* list of variable bindings from input */ struct snmp_varbind_root invb; /* list of variable bindings to output */ struct snmp_varbind_root outvb; /* output response lengths used in ASN encoding */ struct snmp_resp_header_lengths rhl; }; struct snmp_msg_trap { /* lwIP local port (161) binding */ struct udp_pcb *pcb; /* destination IP address in network order */ ip_addr_t dip; /* source enterprise ID (sysObjectID) */ struct snmp_obj_id *enterprise; /* source IP address, raw network order format */ u8_t sip_raw[4]; /* generic trap code */ u32_t gen_trap; /* specific trap code */ u32_t spc_trap; /* timestamp */ u32_t ts; /* list of variable bindings to output */ struct snmp_varbind_root outvb; /* output trap lengths used in ASN encoding */ struct snmp_trap_header_lengths thl; }; /** Agent Version constant, 0 = v1 oddity */ extern const s32_t snmp_version; /** Agent default "public" community string */ extern const char snmp_publiccommunity[7]; extern struct snmp_msg_trap trap_msg; /** Agent setup, start listening to port 161. */ void snmp_init(void); void snmp_trap_dst_enable(u8_t dst_idx, u8_t enable); void snmp_trap_dst_ip_set(u8_t dst_idx, ip_addr_t *dst); /** Varbind-list functions. */ struct snmp_varbind* snmp_varbind_alloc(struct snmp_obj_id *oid, u8_t type, u8_t len); void snmp_varbind_free(struct snmp_varbind *vb); void snmp_varbind_list_free(struct snmp_varbind_root *root); void snmp_varbind_tail_add(struct snmp_varbind_root *root, struct snmp_varbind *vb); struct snmp_varbind* snmp_varbind_tail_remove(struct snmp_varbind_root *root); /** Handle an internal (recv) or external (private response) event. */ void snmp_msg_event(u8_t request_id); err_t snmp_send_response(struct snmp_msg_pstat *m_stat); err_t snmp_send_trap(s8_t generic_trap, struct snmp_obj_id *eoid, s32_t specific_trap); void snmp_coldstart_trap(void); void snmp_authfail_trap(void); #ifdef __cplusplus } #endif #endif /* LWIP_SNMP */ #endif /* LWIP_HDR_SNMP_MSG_H */ ocproxy-1.60/lwip/src/include/lwip/snmp_structs.h000066400000000000000000000232211303453231400222160ustar00rootroot00000000000000/** * @file * Generic MIB tree structures. * * @todo namespace prefixes */ /* * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * Author: Christiaan Simons */ #ifndef LWIP_HDR_SNMP_STRUCTS_H #define LWIP_HDR_SNMP_STRUCTS_H #include "lwip/opt.h" #if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */ #include "lwip/snmp.h" #if SNMP_PRIVATE_MIB /* When using a private MIB, you have to create a file 'private_mib.h' that contains * a 'struct mib_array_node mib_private' which contains your MIB. */ #include "private_mib.h" #endif #ifdef __cplusplus extern "C" { #endif /* MIB object instance */ #define MIB_OBJECT_NONE 0 #define MIB_OBJECT_SCALAR 1 #define MIB_OBJECT_TAB 2 /* MIB access types */ #define MIB_ACCESS_READ 1 #define MIB_ACCESS_WRITE 2 /* MIB object access */ #define MIB_OBJECT_READ_ONLY MIB_ACCESS_READ #define MIB_OBJECT_READ_WRITE (MIB_ACCESS_READ | MIB_ACCESS_WRITE) #define MIB_OBJECT_WRITE_ONLY MIB_ACCESS_WRITE #define MIB_OBJECT_NOT_ACCESSIBLE 0 /** object definition returned by (get_object_def)() */ struct obj_def { /* MIB_OBJECT_NONE (0), MIB_OBJECT_SCALAR (1), MIB_OBJECT_TAB (2) */ u8_t instance; /* 0 read-only, 1 read-write, 2 write-only, 3 not-accessible */ u8_t access; /* ASN type for this object */ u8_t asn_type; /* value length (host length) */ u16_t v_len; /* length of instance part of supplied object identifier */ u8_t id_inst_len; /* instance part of supplied object identifier */ s32_t *id_inst_ptr; }; struct snmp_name_ptr { u8_t ident_len; s32_t *ident; }; /** MIB const scalar (.0) node */ #define MIB_NODE_SC 0x01 /** MIB const array node */ #define MIB_NODE_AR 0x02 /** MIB array node (mem_malloced from RAM) */ #define MIB_NODE_RA 0x03 /** MIB list root node (mem_malloced from RAM) */ #define MIB_NODE_LR 0x04 /** MIB node for external objects */ #define MIB_NODE_EX 0x05 /** node "base class" layout, the mandatory fields for a node */ struct mib_node { /** returns struct obj_def for the given object identifier */ void (*get_object_def)(u8_t ident_len, s32_t *ident, struct obj_def *od); /** returns object value for the given object identifier, @note the caller must allocate at least len bytes for the value */ void (*get_value)(struct obj_def *od, u16_t len, void *value); /** tests length and/or range BEFORE setting */ u8_t (*set_test)(struct obj_def *od, u16_t len, void *value); /** sets object value, only to be called when set_test() */ void (*set_value)(struct obj_def *od, u16_t len, void *value); /** One out of MIB_NODE_AR, MIB_NODE_LR or MIB_NODE_EX */ u8_t node_type; /* array or max list length */ u16_t maxlength; }; /** derived node for scalars .0 index */ typedef struct mib_node mib_scalar_node; /** derived node, points to a fixed size const array of sub-identifiers plus a 'child' pointer */ struct mib_array_node { /* inherited "base class" members */ void (*get_object_def)(u8_t ident_len, s32_t *ident, struct obj_def *od); void (*get_value)(struct obj_def *od, u16_t len, void *value); u8_t (*set_test)(struct obj_def *od, u16_t len, void *value); void (*set_value)(struct obj_def *od, u16_t len, void *value); u8_t node_type; u16_t maxlength; /* additional struct members */ const s32_t *objid; struct mib_node* const *nptr; }; /** derived node, points to a fixed size mem_malloced array of sub-identifiers plus a 'child' pointer */ struct mib_ram_array_node { /* inherited "base class" members */ void (*get_object_def)(u8_t ident_len, s32_t *ident, struct obj_def *od); void (*get_value)(struct obj_def *od, u16_t len, void *value); u8_t (*set_test)(struct obj_def *od, u16_t len, void *value); void (*set_value)(struct obj_def *od, u16_t len, void *value); u8_t node_type; u16_t maxlength; /* aditional struct members */ s32_t *objid; struct mib_node **nptr; }; struct mib_list_node { struct mib_list_node *prev; struct mib_list_node *next; s32_t objid; struct mib_node *nptr; }; /** derived node, points to a doubly linked list of sub-identifiers plus a 'child' pointer */ struct mib_list_rootnode { /* inherited "base class" members */ void (*get_object_def)(u8_t ident_len, s32_t *ident, struct obj_def *od); void (*get_value)(struct obj_def *od, u16_t len, void *value); u8_t (*set_test)(struct obj_def *od, u16_t len, void *value); void (*set_value)(struct obj_def *od, u16_t len, void *value); u8_t node_type; u16_t maxlength; /* additional struct members */ struct mib_list_node *head; struct mib_list_node *tail; /* counts list nodes in list */ u16_t count; }; /** derived node, has access functions for mib object in external memory or device using 'tree_level' and 'idx', with a range 0 .. (level_length() - 1) */ struct mib_external_node { /* inherited "base class" members */ void (*get_object_def)(u8_t ident_len, s32_t *ident, struct obj_def *od); void (*get_value)(struct obj_def *od, u16_t len, void *value); u8_t (*set_test)(struct obj_def *od, u16_t len, void *value); void (*set_value)(struct obj_def *od, u16_t len, void *value); u8_t node_type; u16_t maxlength; /* additional struct members */ /** points to an external (in memory) record of some sort of addressing information, passed to and interpreted by the funtions below */ void* addr_inf; /** tree levels under this node */ u8_t tree_levels; /** number of objects at this level */ u16_t (*level_length)(void* addr_inf, u8_t level); /** compares object sub identifier with external id return zero when equal, nonzero when unequal */ s32_t (*ident_cmp)(void* addr_inf, u8_t level, u16_t idx, s32_t sub_id); void (*get_objid)(void* addr_inf, u8_t level, u16_t idx, s32_t *sub_id); /** async Questions */ void (*get_object_def_q)(void* addr_inf, u8_t rid, u8_t ident_len, s32_t *ident); void (*get_value_q)(u8_t rid, struct obj_def *od); void (*set_test_q)(u8_t rid, struct obj_def *od); void (*set_value_q)(u8_t rid, struct obj_def *od, u16_t len, void *value); /** async Answers */ void (*get_object_def_a)(u8_t rid, u8_t ident_len, s32_t *ident, struct obj_def *od); void (*get_value_a)(u8_t rid, struct obj_def *od, u16_t len, void *value); u8_t (*set_test_a)(u8_t rid, struct obj_def *od, u16_t len, void *value); void (*set_value_a)(u8_t rid, struct obj_def *od, u16_t len, void *value); /** async Panic Close (agent returns error reply, e.g. used for external transaction cleanup) */ void (*get_object_def_pc)(u8_t rid, u8_t ident_len, s32_t *ident); void (*get_value_pc)(u8_t rid, struct obj_def *od); void (*set_test_pc)(u8_t rid, struct obj_def *od); void (*set_value_pc)(u8_t rid, struct obj_def *od); }; /** export MIB tree from mib2.c */ extern const struct mib_array_node internet; /** dummy function pointers for non-leaf MIB nodes from mib2.c */ void noleafs_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od); void noleafs_get_value(struct obj_def *od, u16_t len, void *value); u8_t noleafs_set_test(struct obj_def *od, u16_t len, void *value); void noleafs_set_value(struct obj_def *od, u16_t len, void *value); void snmp_oidtoip(s32_t *ident, ip_addr_t *ip); void snmp_iptooid(ip_addr_t *ip, s32_t *ident); void snmp_ifindextonetif(s32_t ifindex, struct netif **netif); void snmp_netiftoifindex(struct netif *netif, s32_t *ifidx); struct mib_list_node* snmp_mib_ln_alloc(s32_t id); void snmp_mib_ln_free(struct mib_list_node *ln); struct mib_list_rootnode* snmp_mib_lrn_alloc(void); void snmp_mib_lrn_free(struct mib_list_rootnode *lrn); s8_t snmp_mib_node_insert(struct mib_list_rootnode *rn, s32_t objid, struct mib_list_node **insn); s8_t snmp_mib_node_find(struct mib_list_rootnode *rn, s32_t objid, struct mib_list_node **fn); struct mib_list_rootnode *snmp_mib_node_delete(struct mib_list_rootnode *rn, struct mib_list_node *n); struct mib_node* snmp_search_tree(struct mib_node *node, u8_t ident_len, s32_t *ident, struct snmp_name_ptr *np); struct mib_node* snmp_expand_tree(struct mib_node *node, u8_t ident_len, s32_t *ident, struct snmp_obj_id *oidret); u8_t snmp_iso_prefix_tst(u8_t ident_len, s32_t *ident); u8_t snmp_iso_prefix_expand(u8_t ident_len, s32_t *ident, struct snmp_obj_id *oidret); #ifdef __cplusplus } #endif #endif /* LWIP_SNMP */ #endif /* LWIP_HDR_SNMP_STRUCTS_H */ ocproxy-1.60/lwip/src/include/lwip/sockets.h000066400000000000000000000422541303453231400211340ustar00rootroot00000000000000/* * Copyright (c) 2001-2004 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #ifndef LWIP_HDR_SOCKETS_H #define LWIP_HDR_SOCKETS_H #include "lwip/opt.h" #if LWIP_SOCKET /* don't build if not configured for use in lwipopts.h */ #include /* for size_t */ #include "lwip/ip_addr.h" #include "lwip/err.h" #include "lwip/inet.h" #include "lwip/inet6.h" #ifdef __cplusplus extern "C" { #endif /* If your port already typedef's sa_family_t, define SA_FAMILY_T_DEFINED to prevent this code from redefining it. */ #if !defined(sa_family_t) && !defined(SA_FAMILY_T_DEFINED) typedef u8_t sa_family_t; #endif /* If your port already typedef's in_port_t, define IN_PORT_T_DEFINED to prevent this code from redefining it. */ #if !defined(in_port_t) && !defined(IN_PORT_T_DEFINED) typedef u16_t in_port_t; #endif /* members are in network byte order */ struct sockaddr_in { u8_t sin_len; sa_family_t sin_family; in_port_t sin_port; struct in_addr sin_addr; #define SIN_ZERO_LEN 8 char sin_zero[SIN_ZERO_LEN]; }; #if LWIP_IPV6 struct sockaddr_in6 { u8_t sin6_len; /* length of this structure */ sa_family_t sin6_family; /* AF_INET6 */ in_port_t sin6_port; /* Transport layer port # */ u32_t sin6_flowinfo; /* IPv6 flow information */ struct in6_addr sin6_addr; /* IPv6 address */ }; #endif /* LWIP_IPV6 */ struct sockaddr { u8_t sa_len; sa_family_t sa_family; #if LWIP_IPV6 char sa_data[22]; #else /* LWIP_IPV6 */ char sa_data[14]; #endif /* LWIP_IPV6 */ }; struct sockaddr_storage { u8_t s2_len; sa_family_t ss_family; char s2_data1[2]; u32_t s2_data2[3]; #if LWIP_IPV6 u32_t s2_data3[2]; #endif /* LWIP_IPV6 */ }; /* If your port already typedef's socklen_t, define SOCKLEN_T_DEFINED to prevent this code from redefining it. */ #if !defined(socklen_t) && !defined(SOCKLEN_T_DEFINED) typedef u32_t socklen_t; #endif struct lwip_sock; /** This struct is used to pass data to the set/getsockopt_internal * functions running in tcpip_thread context (only a void* is allowed) */ struct lwip_setgetsockopt_data { /** socket struct for which to change options */ struct lwip_sock *sock; #ifdef LWIP_DEBUG /** socket index for which to change options */ int s; #endif /* LWIP_DEBUG */ /** level of the option to process */ int level; /** name of the option to process */ int optname; /** set: value to set the option to * get: value of the option is stored here */ void *optval; /** size of *optval */ socklen_t *optlen; /** if an error occures, it is temporarily stored here */ err_t err; }; /* Socket protocol types (TCP/UDP/RAW) */ #define SOCK_STREAM 1 #define SOCK_DGRAM 2 #define SOCK_RAW 3 /* * Option flags per-socket. These must match the SOF_ flags in ip.h (checked in init.c) */ #define SO_DEBUG 0x0001 /* Unimplemented: turn on debugging info recording */ #define SO_ACCEPTCONN 0x0002 /* socket has had listen() */ #define SO_REUSEADDR 0x0004 /* Allow local address reuse */ #define SO_KEEPALIVE 0x0008 /* keep connections alive */ #define SO_DONTROUTE 0x0010 /* Unimplemented: just use interface addresses */ #define SO_BROADCAST 0x0020 /* permit to send and to receive broadcast messages (see IP_SOF_BROADCAST option) */ #define SO_USELOOPBACK 0x0040 /* Unimplemented: bypass hardware when possible */ #define SO_LINGER 0x0080 /* linger on close if data present */ #define SO_OOBINLINE 0x0100 /* Unimplemented: leave received OOB data in line */ #define SO_REUSEPORT 0x0200 /* Unimplemented: allow local address & port reuse */ #define SO_DONTLINGER ((int)(~SO_LINGER)) /* * Additional options, not kept in so_options. */ #define SO_SNDBUF 0x1001 /* Unimplemented: send buffer size */ #define SO_RCVBUF 0x1002 /* receive buffer size */ #define SO_SNDLOWAT 0x1003 /* Unimplemented: send low-water mark */ #define SO_RCVLOWAT 0x1004 /* Unimplemented: receive low-water mark */ #define SO_SNDTIMEO 0x1005 /* Unimplemented: send timeout */ #define SO_RCVTIMEO 0x1006 /* receive timeout */ #define SO_ERROR 0x1007 /* get error status and clear */ #define SO_TYPE 0x1008 /* get socket type */ #define SO_CONTIMEO 0x1009 /* Unimplemented: connect timeout */ #define SO_NO_CHECK 0x100a /* don't create UDP checksum */ /* * Structure used for manipulating linger option. */ struct linger { int l_onoff; /* option on/off */ int l_linger; /* linger time */ }; /* * Level number for (get/set)sockopt() to apply to socket itself. */ #define SOL_SOCKET 0xfff /* options for socket level */ #define AF_UNSPEC 0 #define AF_INET 2 #if LWIP_IPV6 #define AF_INET6 10 #else /* LWIP_IPV6 */ #define AF_INET6 AF_UNSPEC #endif /* LWIP_IPV6 */ #define PF_INET AF_INET #define PF_INET6 AF_INET6 #define PF_UNSPEC AF_UNSPEC #define IPPROTO_IP 0 #define IPPROTO_ICMP 1 #define IPPROTO_TCP 6 #define IPPROTO_UDP 17 #if LWIP_IPV6 #define IPPROTO_IPV6 41 #define IPPROTO_ICMPV6 58 #endif /* LWIP_IPV6 */ #define IPPROTO_UDPLITE 136 #define IPPROTO_RAW 255 /* Flags we can use with send and recv. */ #define MSG_PEEK 0x01 /* Peeks at an incoming message */ #define MSG_WAITALL 0x02 /* Unimplemented: Requests that the function block until the full amount of data requested can be returned */ #define MSG_OOB 0x04 /* Unimplemented: Requests out-of-band data. The significance and semantics of out-of-band data are protocol-specific */ #define MSG_DONTWAIT 0x08 /* Nonblocking i/o for this operation only */ #define MSG_MORE 0x10 /* Sender will send more */ /* * Options for level IPPROTO_IP */ #define IP_TOS 1 #define IP_TTL 2 #if LWIP_TCP /* * Options for level IPPROTO_TCP */ #define TCP_NODELAY 0x01 /* don't delay send to coalesce packets */ #define TCP_KEEPALIVE 0x02 /* send KEEPALIVE probes when idle for pcb->keep_idle milliseconds */ #define TCP_KEEPIDLE 0x03 /* set pcb->keep_idle - Same as TCP_KEEPALIVE, but use seconds for get/setsockopt */ #define TCP_KEEPINTVL 0x04 /* set pcb->keep_intvl - Use seconds for get/setsockopt */ #define TCP_KEEPCNT 0x05 /* set pcb->keep_cnt - Use number of probes sent for get/setsockopt */ #endif /* LWIP_TCP */ #if LWIP_IPV6 /* * Options for level IPPROTO_IPV6 */ #define IPV6_CHECKSUM 7 /* RFC3542: calculate and insert the ICMPv6 checksum for raw sockets. */ #define IPV6_V6ONLY 27 /* RFC3493: boolean control to restrict AF_INET6 sockets to IPv6 communications only. */ #endif /* LWIP_IPV6 */ #if LWIP_UDP && LWIP_UDPLITE /* * Options for level IPPROTO_UDPLITE */ #define UDPLITE_SEND_CSCOV 0x01 /* sender checksum coverage */ #define UDPLITE_RECV_CSCOV 0x02 /* minimal receiver checksum coverage */ #endif /* LWIP_UDP && LWIP_UDPLITE*/ #if LWIP_IGMP /* * Options and types for UDP multicast traffic handling */ #define IP_ADD_MEMBERSHIP 3 #define IP_DROP_MEMBERSHIP 4 #define IP_MULTICAST_TTL 5 #define IP_MULTICAST_IF 6 #define IP_MULTICAST_LOOP 7 typedef struct ip_mreq { struct in_addr imr_multiaddr; /* IP multicast address of group */ struct in_addr imr_interface; /* local IP address of interface */ } ip_mreq; #endif /* LWIP_IGMP */ /* * The Type of Service provides an indication of the abstract * parameters of the quality of service desired. These parameters are * to be used to guide the selection of the actual service parameters * when transmitting a datagram through a particular network. Several * networks offer service precedence, which somehow treats high * precedence traffic as more important than other traffic (generally * by accepting only traffic above a certain precedence at time of high * load). The major choice is a three way tradeoff between low-delay, * high-reliability, and high-throughput. * The use of the Delay, Throughput, and Reliability indications may * increase the cost (in some sense) of the service. In many networks * better performance for one of these parameters is coupled with worse * performance on another. Except for very unusual cases at most two * of these three indications should be set. */ #define IPTOS_TOS_MASK 0x1E #define IPTOS_TOS(tos) ((tos) & IPTOS_TOS_MASK) #define IPTOS_LOWDELAY 0x10 #define IPTOS_THROUGHPUT 0x08 #define IPTOS_RELIABILITY 0x04 #define IPTOS_LOWCOST 0x02 #define IPTOS_MINCOST IPTOS_LOWCOST /* * The Network Control precedence designation is intended to be used * within a network only. The actual use and control of that * designation is up to each network. The Internetwork Control * designation is intended for use by gateway control originators only. * If the actual use of these precedence designations is of concern to * a particular network, it is the responsibility of that network to * control the access to, and use of, those precedence designations. */ #define IPTOS_PREC_MASK 0xe0 #define IPTOS_PREC(tos) ((tos) & IPTOS_PREC_MASK) #define IPTOS_PREC_NETCONTROL 0xe0 #define IPTOS_PREC_INTERNETCONTROL 0xc0 #define IPTOS_PREC_CRITIC_ECP 0xa0 #define IPTOS_PREC_FLASHOVERRIDE 0x80 #define IPTOS_PREC_FLASH 0x60 #define IPTOS_PREC_IMMEDIATE 0x40 #define IPTOS_PREC_PRIORITY 0x20 #define IPTOS_PREC_ROUTINE 0x00 /* * Commands for ioctlsocket(), taken from the BSD file fcntl.h. * lwip_ioctl only supports FIONREAD and FIONBIO, for now * * Ioctl's have the command encoded in the lower word, * and the size of any in or out parameters in the upper * word. The high 2 bits of the upper word are used * to encode the in/out status of the parameter; for now * we restrict parameters to at most 128 bytes. */ #if !defined(FIONREAD) || !defined(FIONBIO) #define IOCPARM_MASK 0x7fU /* parameters must be < 128 bytes */ #define IOC_VOID 0x20000000UL /* no parameters */ #define IOC_OUT 0x40000000UL /* copy out parameters */ #define IOC_IN 0x80000000UL /* copy in parameters */ #define IOC_INOUT (IOC_IN|IOC_OUT) /* 0x20000000 distinguishes new & old ioctl's */ #define _IO(x,y) (IOC_VOID|((x)<<8)|(y)) #define _IOR(x,y,t) (IOC_OUT|(((long)sizeof(t)&IOCPARM_MASK)<<16)|((x)<<8)|(y)) #define _IOW(x,y,t) (IOC_IN|(((long)sizeof(t)&IOCPARM_MASK)<<16)|((x)<<8)|(y)) #endif /* !defined(FIONREAD) || !defined(FIONBIO) */ #ifndef FIONREAD #define FIONREAD _IOR('f', 127, unsigned long) /* get # bytes to read */ #endif #ifndef FIONBIO #define FIONBIO _IOW('f', 126, unsigned long) /* set/clear non-blocking i/o */ #endif /* Socket I/O Controls: unimplemented */ #ifndef SIOCSHIWAT #define SIOCSHIWAT _IOW('s', 0, unsigned long) /* set high watermark */ #define SIOCGHIWAT _IOR('s', 1, unsigned long) /* get high watermark */ #define SIOCSLOWAT _IOW('s', 2, unsigned long) /* set low watermark */ #define SIOCGLOWAT _IOR('s', 3, unsigned long) /* get low watermark */ #define SIOCATMARK _IOR('s', 7, unsigned long) /* at oob mark? */ #endif /* commands for fnctl */ #ifndef F_GETFL #define F_GETFL 3 #endif #ifndef F_SETFL #define F_SETFL 4 #endif /* File status flags and file access modes for fnctl, these are bits in an int. */ #ifndef O_NONBLOCK #define O_NONBLOCK 1 /* nonblocking I/O */ #endif #ifndef O_NDELAY #define O_NDELAY 1 /* same as O_NONBLOCK, for compatibility */ #endif #ifndef SHUT_RD #define SHUT_RD 0 #define SHUT_WR 1 #define SHUT_RDWR 2 #endif /* FD_SET used for lwip_select */ #ifndef FD_SET #undef FD_SETSIZE /* Make FD_SETSIZE match NUM_SOCKETS in socket.c */ #define FD_SETSIZE MEMP_NUM_NETCONN #define FD_SET(n, p) ((p)->fd_bits[(n)/8] |= (1 << ((n) & 7))) #define FD_CLR(n, p) ((p)->fd_bits[(n)/8] &= ~(1 << ((n) & 7))) #define FD_ISSET(n,p) ((p)->fd_bits[(n)/8] & (1 << ((n) & 7))) #define FD_ZERO(p) memset((void*)(p),0,sizeof(*(p))) typedef struct fd_set { unsigned char fd_bits [(FD_SETSIZE+7)/8]; } fd_set; #endif /* FD_SET */ /** LWIP_TIMEVAL_PRIVATE: if you want to use the struct timeval provided * by your system, set this to 0 and include in cc.h */ #ifndef LWIP_TIMEVAL_PRIVATE #define LWIP_TIMEVAL_PRIVATE 1 #endif #if LWIP_TIMEVAL_PRIVATE struct timeval { long tv_sec; /* seconds */ long tv_usec; /* and microseconds */ }; #endif /* LWIP_TIMEVAL_PRIVATE */ void lwip_socket_init(void); int lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen); int lwip_bind(int s, const struct sockaddr *name, socklen_t namelen); int lwip_shutdown(int s, int how); int lwip_getpeername (int s, struct sockaddr *name, socklen_t *namelen); int lwip_getsockname (int s, struct sockaddr *name, socklen_t *namelen); int lwip_getsockopt (int s, int level, int optname, void *optval, socklen_t *optlen); int lwip_setsockopt (int s, int level, int optname, const void *optval, socklen_t optlen); int lwip_close(int s); int lwip_connect(int s, const struct sockaddr *name, socklen_t namelen); int lwip_listen(int s, int backlog); int lwip_recv(int s, void *mem, size_t len, int flags); int lwip_read(int s, void *mem, size_t len); int lwip_recvfrom(int s, void *mem, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen); int lwip_send(int s, const void *dataptr, size_t size, int flags); int lwip_sendto(int s, const void *dataptr, size_t size, int flags, const struct sockaddr *to, socklen_t tolen); int lwip_socket(int domain, int type, int protocol); int lwip_write(int s, const void *dataptr, size_t size); int lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset, struct timeval *timeout); int lwip_ioctl(int s, long cmd, void *argp); int lwip_fcntl(int s, int cmd, int val); #if LWIP_COMPAT_SOCKETS #define accept(a,b,c) lwip_accept(a,b,c) #define bind(a,b,c) lwip_bind(a,b,c) #define shutdown(a,b) lwip_shutdown(a,b) #define closesocket(s) lwip_close(s) #define connect(a,b,c) lwip_connect(a,b,c) #define getsockname(a,b,c) lwip_getsockname(a,b,c) #define getpeername(a,b,c) lwip_getpeername(a,b,c) #define setsockopt(a,b,c,d,e) lwip_setsockopt(a,b,c,d,e) #define getsockopt(a,b,c,d,e) lwip_getsockopt(a,b,c,d,e) #define listen(a,b) lwip_listen(a,b) #define recv(a,b,c,d) lwip_recv(a,b,c,d) #define recvfrom(a,b,c,d,e,f) lwip_recvfrom(a,b,c,d,e,f) #define send(a,b,c,d) lwip_send(a,b,c,d) #define sendto(a,b,c,d,e,f) lwip_sendto(a,b,c,d,e,f) #define socket(a,b,c) lwip_socket(a,b,c) #define select(a,b,c,d,e) lwip_select(a,b,c,d,e) #define ioctlsocket(a,b,c) lwip_ioctl(a,b,c) #if LWIP_POSIX_SOCKETS_IO_NAMES #define read(a,b,c) lwip_read(a,b,c) #define write(a,b,c) lwip_write(a,b,c) #define close(s) lwip_close(s) #define fcntl(a,b,c) lwip_fcntl(a,b,c) #endif /* LWIP_POSIX_SOCKETS_IO_NAMES */ #if LWIP_IPV6 #define inet_ntop(af,src,dst,size) \ (((af) == AF_INET6) ? ip6addr_ntoa_r((src),(dst),(size)) \ : (((af) == AF_INET) ? ipaddr_ntoa_r((src),(dst),(size)) : NULL)) #define inet_pton(af,src,dst) \ (((af) == AF_INET6) ? inet6_aton((src),(dst)) \ : (((af) == AF_INET) ? inet_aton((src),(dst)) : 0)) #else /* LWIP_IPV6 */ #define inet_ntop(af,src,dst,size) \ (((af) == AF_INET) ? ipaddr_ntoa_r((src),(dst),(size)) : NULL) #define inet_pton(af,src,dst) \ (((af) == AF_INET) ? inet_aton((src),(dst)) : 0) #endif /* LWIP_IPV6 */ #endif /* LWIP_COMPAT_SOCKETS */ #ifdef __cplusplus } #endif #endif /* LWIP_SOCKET */ #endif /* LWIP_HDR_SOCKETS_H */ ocproxy-1.60/lwip/src/include/lwip/stats.h000066400000000000000000000231741303453231400206170ustar00rootroot00000000000000/* * Copyright (c) 2001-2004 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #ifndef LWIP_HDR_STATS_H #define LWIP_HDR_STATS_H #include "lwip/opt.h" #include "lwip/mem.h" #include "lwip/memp.h" #ifdef __cplusplus extern "C" { #endif #if LWIP_STATS #ifndef LWIP_STATS_LARGE #define LWIP_STATS_LARGE 0 #endif #if LWIP_STATS_LARGE #define STAT_COUNTER u32_t #define STAT_COUNTER_F U32_F #else #define STAT_COUNTER u16_t #define STAT_COUNTER_F U16_F #endif struct stats_proto { STAT_COUNTER xmit; /* Transmitted packets. */ STAT_COUNTER recv; /* Received packets. */ STAT_COUNTER fw; /* Forwarded packets. */ STAT_COUNTER drop; /* Dropped packets. */ STAT_COUNTER chkerr; /* Checksum error. */ STAT_COUNTER lenerr; /* Invalid length error. */ STAT_COUNTER memerr; /* Out of memory error. */ STAT_COUNTER rterr; /* Routing error. */ STAT_COUNTER proterr; /* Protocol error. */ STAT_COUNTER opterr; /* Error in options. */ STAT_COUNTER err; /* Misc error. */ STAT_COUNTER cachehit; }; struct stats_igmp { STAT_COUNTER xmit; /* Transmitted packets. */ STAT_COUNTER recv; /* Received packets. */ STAT_COUNTER drop; /* Dropped packets. */ STAT_COUNTER chkerr; /* Checksum error. */ STAT_COUNTER lenerr; /* Invalid length error. */ STAT_COUNTER memerr; /* Out of memory error. */ STAT_COUNTER proterr; /* Protocol error. */ STAT_COUNTER rx_v1; /* Received v1 frames. */ STAT_COUNTER rx_group; /* Received group-specific queries. */ STAT_COUNTER rx_general; /* Received general queries. */ STAT_COUNTER rx_report; /* Received reports. */ STAT_COUNTER tx_join; /* Sent joins. */ STAT_COUNTER tx_leave; /* Sent leaves. */ STAT_COUNTER tx_report; /* Sent reports. */ }; struct stats_mem { #ifdef LWIP_DEBUG const char *name; #endif /* LWIP_DEBUG */ mem_size_t avail; mem_size_t used; mem_size_t max; STAT_COUNTER err; STAT_COUNTER illegal; }; struct stats_syselem { STAT_COUNTER used; STAT_COUNTER max; STAT_COUNTER err; }; struct stats_sys { struct stats_syselem sem; struct stats_syselem mutex; struct stats_syselem mbox; }; struct stats_ { #if LINK_STATS struct stats_proto link; #endif #if ETHARP_STATS struct stats_proto etharp; #endif #if IPFRAG_STATS struct stats_proto ip_frag; #endif #if IP_STATS struct stats_proto ip; #endif #if ICMP_STATS struct stats_proto icmp; #endif #if IGMP_STATS struct stats_igmp igmp; #endif #if UDP_STATS struct stats_proto udp; #endif #if TCP_STATS struct stats_proto tcp; #endif #if MEM_STATS struct stats_mem mem; #endif #if MEMP_STATS struct stats_mem memp[MEMP_MAX]; #endif #if SYS_STATS struct stats_sys sys; #endif #if IP6_STATS struct stats_proto ip6; #endif #if ICMP6_STATS struct stats_proto icmp6; #endif #if IP6_FRAG_STATS struct stats_proto ip6_frag; #endif #if MLD6_STATS struct stats_igmp mld6; #endif #if ND6_STATS struct stats_proto nd6; #endif }; extern struct stats_ lwip_stats; void stats_init(void); #define STATS_INC(x) ++lwip_stats.x #define STATS_DEC(x) --lwip_stats.x #define STATS_INC_USED(x, y) do { lwip_stats.x.used += y; \ if (lwip_stats.x.max < lwip_stats.x.used) { \ lwip_stats.x.max = lwip_stats.x.used; \ } \ } while(0) #else /* LWIP_STATS */ #define stats_init() #define STATS_INC(x) #define STATS_DEC(x) #define STATS_INC_USED(x) #endif /* LWIP_STATS */ #if TCP_STATS #define TCP_STATS_INC(x) STATS_INC(x) #define TCP_STATS_DISPLAY() stats_display_proto(&lwip_stats.tcp, "TCP") #else #define TCP_STATS_INC(x) #define TCP_STATS_DISPLAY() #endif #if UDP_STATS #define UDP_STATS_INC(x) STATS_INC(x) #define UDP_STATS_DISPLAY() stats_display_proto(&lwip_stats.udp, "UDP") #else #define UDP_STATS_INC(x) #define UDP_STATS_DISPLAY() #endif #if ICMP_STATS #define ICMP_STATS_INC(x) STATS_INC(x) #define ICMP_STATS_DISPLAY() stats_display_proto(&lwip_stats.icmp, "ICMP") #else #define ICMP_STATS_INC(x) #define ICMP_STATS_DISPLAY() #endif #if IGMP_STATS #define IGMP_STATS_INC(x) STATS_INC(x) #define IGMP_STATS_DISPLAY() stats_display_igmp(&lwip_stats.igmp, "IGMP") #else #define IGMP_STATS_INC(x) #define IGMP_STATS_DISPLAY() #endif #if IP_STATS #define IP_STATS_INC(x) STATS_INC(x) #define IP_STATS_DISPLAY() stats_display_proto(&lwip_stats.ip, "IP") #else #define IP_STATS_INC(x) #define IP_STATS_DISPLAY() #endif #if IPFRAG_STATS #define IPFRAG_STATS_INC(x) STATS_INC(x) #define IPFRAG_STATS_DISPLAY() stats_display_proto(&lwip_stats.ip_frag, "IP_FRAG") #else #define IPFRAG_STATS_INC(x) #define IPFRAG_STATS_DISPLAY() #endif #if ETHARP_STATS #define ETHARP_STATS_INC(x) STATS_INC(x) #define ETHARP_STATS_DISPLAY() stats_display_proto(&lwip_stats.etharp, "ETHARP") #else #define ETHARP_STATS_INC(x) #define ETHARP_STATS_DISPLAY() #endif #if LINK_STATS #define LINK_STATS_INC(x) STATS_INC(x) #define LINK_STATS_DISPLAY() stats_display_proto(&lwip_stats.link, "LINK") #else #define LINK_STATS_INC(x) #define LINK_STATS_DISPLAY() #endif #if MEM_STATS #define MEM_STATS_AVAIL(x, y) lwip_stats.mem.x = y #define MEM_STATS_INC(x) STATS_INC(mem.x) #define MEM_STATS_INC_USED(x, y) STATS_INC_USED(mem, y) #define MEM_STATS_DEC_USED(x, y) lwip_stats.mem.x -= y #define MEM_STATS_DISPLAY() stats_display_mem(&lwip_stats.mem, "HEAP") #else #define MEM_STATS_AVAIL(x, y) #define MEM_STATS_INC(x) #define MEM_STATS_INC_USED(x, y) #define MEM_STATS_DEC_USED(x, y) #define MEM_STATS_DISPLAY() #endif #if MEMP_STATS #define MEMP_STATS_AVAIL(x, i, y) lwip_stats.memp[i].x = y #define MEMP_STATS_INC(x, i) STATS_INC(memp[i].x) #define MEMP_STATS_DEC(x, i) STATS_DEC(memp[i].x) #define MEMP_STATS_INC_USED(x, i) STATS_INC_USED(memp[i], 1) #define MEMP_STATS_DISPLAY(i) stats_display_memp(&lwip_stats.memp[i], i) #else #define MEMP_STATS_AVAIL(x, i, y) #define MEMP_STATS_INC(x, i) #define MEMP_STATS_DEC(x, i) #define MEMP_STATS_INC_USED(x, i) #define MEMP_STATS_DISPLAY(i) #endif #if SYS_STATS #define SYS_STATS_INC(x) STATS_INC(sys.x) #define SYS_STATS_DEC(x) STATS_DEC(sys.x) #define SYS_STATS_INC_USED(x) STATS_INC_USED(sys.x, 1) #define SYS_STATS_DISPLAY() stats_display_sys(&lwip_stats.sys) #else #define SYS_STATS_INC(x) #define SYS_STATS_DEC(x) #define SYS_STATS_INC_USED(x) #define SYS_STATS_DISPLAY() #endif #if IP6_STATS #define IP6_STATS_INC(x) STATS_INC(x) #define IP6_STATS_DISPLAY() stats_display_proto(&lwip_stats.ip6, "IPv6") #else #define IP6_STATS_INC(x) #define IP6_STATS_DISPLAY() #endif #if ICMP6_STATS #define ICMP6_STATS_INC(x) STATS_INC(x) #define ICMP6_STATS_DISPLAY() stats_display_proto(&lwip_stats.icmp6, "ICMPv6") #else #define ICMP6_STATS_INC(x) #define ICMP6_STATS_DISPLAY() #endif #if IP6_FRAG_STATS #define IP6_FRAG_STATS_INC(x) STATS_INC(x) #define IP6_FRAG_STATS_DISPLAY() stats_display_proto(&lwip_stats.ip6_frag, "IPv6 FRAG") #else #define IP6_FRAG_STATS_INC(x) #define IP6_FRAG_STATS_DISPLAY() #endif #if MLD6_STATS #define MLD6_STATS_INC(x) STATS_INC(x) #define MLD6_STATS_DISPLAY() stats_display_igmp(&lwip_stats.mld6, "MLDv1") #else #define MLD6_STATS_INC(x) #define MLD6_STATS_DISPLAY() #endif #if ND6_STATS #define ND6_STATS_INC(x) STATS_INC(x) #define ND6_STATS_DISPLAY() stats_display_proto(&lwip_stats.nd6, "ND") #else #define ND6_STATS_INC(x) #define ND6_STATS_DISPLAY() #endif /* Display of statistics */ #if LWIP_STATS_DISPLAY void stats_display(void); void stats_display_proto(struct stats_proto *proto, const char *name); void stats_display_igmp(struct stats_igmp *igmp, const char *name); void stats_display_mem(struct stats_mem *mem, const char *name); void stats_display_memp(struct stats_mem *mem, int index); void stats_display_sys(struct stats_sys *sys); #else /* LWIP_STATS_DISPLAY */ #define stats_display() #define stats_display_proto(proto, name) #define stats_display_igmp(igmp, name) #define stats_display_mem(mem, name) #define stats_display_memp(mem, index) #define stats_display_sys(sys) #endif /* LWIP_STATS_DISPLAY */ #ifdef __cplusplus } #endif #endif /* LWIP_HDR_STATS_H */ ocproxy-1.60/lwip/src/include/lwip/sys.h000066400000000000000000000307421303453231400202760ustar00rootroot00000000000000/* * Copyright (c) 2001-2004 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #ifndef LWIP_HDR_SYS_H #define LWIP_HDR_SYS_H #include "lwip/opt.h" #ifdef __cplusplus extern "C" { #endif #if NO_SYS /* For a totally minimal and standalone system, we provide null definitions of the sys_ functions. */ typedef u8_t sys_sem_t; typedef u8_t sys_mutex_t; typedef u8_t sys_mbox_t; #define sys_sem_new(s, c) ERR_OK #define sys_sem_signal(s) #define sys_sem_wait(s) #define sys_arch_sem_wait(s,t) #define sys_sem_free(s) #define sys_sem_valid(s) 0 #define sys_sem_set_invalid(s) #define sys_mutex_new(mu) ERR_OK #define sys_mutex_lock(mu) #define sys_mutex_unlock(mu) #define sys_mutex_free(mu) #define sys_mutex_valid(mu) 0 #define sys_mutex_set_invalid(mu) #define sys_mbox_new(m, s) ERR_OK #define sys_mbox_fetch(m,d) #define sys_mbox_tryfetch(m,d) #define sys_mbox_post(m,d) #define sys_mbox_trypost(m,d) #define sys_mbox_free(m) #define sys_mbox_valid(m) #define sys_mbox_set_invalid(m) #define sys_thread_new(n,t,a,s,p) #define sys_msleep(t) #else /* NO_SYS */ /** Return code for timeouts from sys_arch_mbox_fetch and sys_arch_sem_wait */ #define SYS_ARCH_TIMEOUT 0xffffffffUL /** sys_mbox_tryfetch() returns SYS_MBOX_EMPTY if appropriate. * For now we use the same magic value, but we allow this to change in future. */ #define SYS_MBOX_EMPTY SYS_ARCH_TIMEOUT #include "lwip/err.h" #include "arch/sys_arch.h" /** Function prototype for thread functions */ typedef void (*lwip_thread_fn)(void *arg); /* Function prototypes for functions to be implemented by platform ports (in sys_arch.c) */ /* Mutex functions: */ /** Define LWIP_COMPAT_MUTEX if the port has no mutexes and binary semaphores should be used instead */ #if LWIP_COMPAT_MUTEX /* for old ports that don't have mutexes: define them to binary semaphores */ #define sys_mutex_t sys_sem_t #define sys_mutex_new(mutex) sys_sem_new(mutex, 1) #define sys_mutex_lock(mutex) sys_sem_wait(mutex) #define sys_mutex_unlock(mutex) sys_sem_signal(mutex) #define sys_mutex_free(mutex) sys_sem_free(mutex) #define sys_mutex_valid(mutex) sys_sem_valid(mutex) #define sys_mutex_set_invalid(mutex) sys_sem_set_invalid(mutex) #else /* LWIP_COMPAT_MUTEX */ /** Create a new mutex * @param mutex pointer to the mutex to create * @return a new mutex */ err_t sys_mutex_new(sys_mutex_t *mutex); /** Lock a mutex * @param mutex the mutex to lock */ void sys_mutex_lock(sys_mutex_t *mutex); /** Unlock a mutex * @param mutex the mutex to unlock */ void sys_mutex_unlock(sys_mutex_t *mutex); /** Delete a semaphore * @param mutex the mutex to delete */ void sys_mutex_free(sys_mutex_t *mutex); #ifndef sys_mutex_valid /** Check if a mutex is valid/allocated: return 1 for valid, 0 for invalid */ int sys_mutex_valid(sys_mutex_t *mutex); #endif #ifndef sys_mutex_set_invalid /** Set a mutex invalid so that sys_mutex_valid returns 0 */ void sys_mutex_set_invalid(sys_mutex_t *mutex); #endif #endif /* LWIP_COMPAT_MUTEX */ /* Semaphore functions: */ /** Create a new semaphore * @param sem pointer to the semaphore to create * @param count initial count of the semaphore * @return ERR_OK if successful, another err_t otherwise */ err_t sys_sem_new(sys_sem_t *sem, u8_t count); /** Signals a semaphore * @param sem the semaphore to signal */ void sys_sem_signal(sys_sem_t *sem); /** Wait for a semaphore for the specified timeout * @param sem the semaphore to wait for * @param timeout timeout in milliseconds to wait (0 = wait forever) * @return time (in milliseconds) waited for the semaphore * or SYS_ARCH_TIMEOUT on timeout */ u32_t sys_arch_sem_wait(sys_sem_t *sem, u32_t timeout); /** Delete a semaphore * @param sem semaphore to delete */ void sys_sem_free(sys_sem_t *sem); /** Wait for a semaphore - forever/no timeout */ #define sys_sem_wait(sem) sys_arch_sem_wait(sem, 0) #ifndef sys_sem_valid /** Check if a sempahore is valid/allocated: return 1 for valid, 0 for invalid */ int sys_sem_valid(sys_sem_t *sem); #endif #ifndef sys_sem_set_invalid /** Set a semaphore invalid so that sys_sem_valid returns 0 */ void sys_sem_set_invalid(sys_sem_t *sem); #endif /* Time functions. */ #ifndef sys_msleep void sys_msleep(u32_t ms); /* only has a (close to) 1 jiffy resolution. */ #endif /* Mailbox functions. */ /** Create a new mbox of specified size * @param mbox pointer to the mbox to create * @param size (miminum) number of messages in this mbox * @return ERR_OK if successful, another err_t otherwise */ err_t sys_mbox_new(sys_mbox_t *mbox, int size); /** Post a message to an mbox - may not fail * -> blocks if full, only used from tasks not from ISR * @param mbox mbox to posts the message * @param msg message to post (ATTENTION: can be NULL) */ void sys_mbox_post(sys_mbox_t *mbox, void *msg); /** Try to post a message to an mbox - may fail if full or ISR * @param mbox mbox to posts the message * @param msg message to post (ATTENTION: can be NULL) */ err_t sys_mbox_trypost(sys_mbox_t *mbox, void *msg); /** Wait for a new message to arrive in the mbox * @param mbox mbox to get a message from * @param msg pointer where the message is stored * @param timeout maximum time (in milliseconds) to wait for a message (0 = wait forever) * @return time (in milliseconds) waited for a message, may be 0 if not waited or SYS_ARCH_TIMEOUT on timeout * The returned time has to be accurate to prevent timer jitter! */ u32_t sys_arch_mbox_fetch(sys_mbox_t *mbox, void **msg, u32_t timeout); /* Allow port to override with a macro, e.g. special timout for sys_arch_mbox_fetch() */ #ifndef sys_arch_mbox_tryfetch /** Wait for a new message to arrive in the mbox * @param mbox mbox to get a message from * @param msg pointer where the message is stored * @return 0 (milliseconds) if a message has been received * or SYS_MBOX_EMPTY if the mailbox is empty */ u32_t sys_arch_mbox_tryfetch(sys_mbox_t *mbox, void **msg); #endif /** For now, we map straight to sys_arch implementation. */ #define sys_mbox_tryfetch(mbox, msg) sys_arch_mbox_tryfetch(mbox, msg) /** Delete an mbox * @param mbox mbox to delete */ void sys_mbox_free(sys_mbox_t *mbox); #define sys_mbox_fetch(mbox, msg) sys_arch_mbox_fetch(mbox, msg, 0) #ifndef sys_mbox_valid /** Check if an mbox is valid/allocated: return 1 for valid, 0 for invalid */ int sys_mbox_valid(sys_mbox_t *mbox); #endif #ifndef sys_mbox_set_invalid /** Set an mbox invalid so that sys_mbox_valid returns 0 */ void sys_mbox_set_invalid(sys_mbox_t *mbox); #endif /** The only thread function: * Creates a new thread * @param name human-readable name for the thread (used for debugging purposes) * @param thread thread-function * @param arg parameter passed to 'thread' * @param stacksize stack size in bytes for the new thread (may be ignored by ports) * @param prio priority of the new thread (may be ignored by ports) */ sys_thread_t sys_thread_new(const char *name, lwip_thread_fn thread, void *arg, int stacksize, int prio); #endif /* NO_SYS */ /* sys_init() must be called before anthing else. */ void sys_init(void); #ifndef sys_jiffies /** Ticks/jiffies since power up. */ u32_t sys_jiffies(void); #endif /** Returns the current time in milliseconds, * may be the same as sys_jiffies or at least based on it. */ u32_t sys_now(void); /* Critical Region Protection */ /* These functions must be implemented in the sys_arch.c file. In some implementations they can provide a more light-weight protection mechanism than using semaphores. Otherwise semaphores can be used for implementation */ #ifndef SYS_ARCH_PROTECT /** SYS_LIGHTWEIGHT_PROT * define SYS_LIGHTWEIGHT_PROT in lwipopts.h if you want inter-task protection * for certain critical regions during buffer allocation, deallocation and memory * allocation and deallocation. */ #if SYS_LIGHTWEIGHT_PROT /** SYS_ARCH_DECL_PROTECT * declare a protection variable. This macro will default to defining a variable of * type sys_prot_t. If a particular port needs a different implementation, then * this macro may be defined in sys_arch.h. */ #define SYS_ARCH_DECL_PROTECT(lev) sys_prot_t lev /** SYS_ARCH_PROTECT * Perform a "fast" protect. This could be implemented by * disabling interrupts for an embedded system or by using a semaphore or * mutex. The implementation should allow calling SYS_ARCH_PROTECT when * already protected. The old protection level is returned in the variable * "lev". This macro will default to calling the sys_arch_protect() function * which should be implemented in sys_arch.c. If a particular port needs a * different implementation, then this macro may be defined in sys_arch.h */ #define SYS_ARCH_PROTECT(lev) lev = sys_arch_protect() /** SYS_ARCH_UNPROTECT * Perform a "fast" set of the protection level to "lev". This could be * implemented by setting the interrupt level to "lev" within the MACRO or by * using a semaphore or mutex. This macro will default to calling the * sys_arch_unprotect() function which should be implemented in * sys_arch.c. If a particular port needs a different implementation, then * this macro may be defined in sys_arch.h */ #define SYS_ARCH_UNPROTECT(lev) sys_arch_unprotect(lev) sys_prot_t sys_arch_protect(void); void sys_arch_unprotect(sys_prot_t pval); #else #define SYS_ARCH_DECL_PROTECT(lev) #define SYS_ARCH_PROTECT(lev) #define SYS_ARCH_UNPROTECT(lev) #endif /* SYS_LIGHTWEIGHT_PROT */ #endif /* SYS_ARCH_PROTECT */ /* * Macros to set/get and increase/decrease variables in a thread-safe way. * Use these for accessing variable that are used from more than one thread. */ #ifndef SYS_ARCH_INC #define SYS_ARCH_INC(var, val) do { \ SYS_ARCH_DECL_PROTECT(old_level); \ SYS_ARCH_PROTECT(old_level); \ var += val; \ SYS_ARCH_UNPROTECT(old_level); \ } while(0) #endif /* SYS_ARCH_INC */ #ifndef SYS_ARCH_DEC #define SYS_ARCH_DEC(var, val) do { \ SYS_ARCH_DECL_PROTECT(old_level); \ SYS_ARCH_PROTECT(old_level); \ var -= val; \ SYS_ARCH_UNPROTECT(old_level); \ } while(0) #endif /* SYS_ARCH_DEC */ #ifndef SYS_ARCH_GET #define SYS_ARCH_GET(var, ret) do { \ SYS_ARCH_DECL_PROTECT(old_level); \ SYS_ARCH_PROTECT(old_level); \ ret = var; \ SYS_ARCH_UNPROTECT(old_level); \ } while(0) #endif /* SYS_ARCH_GET */ #ifndef SYS_ARCH_SET #define SYS_ARCH_SET(var, val) do { \ SYS_ARCH_DECL_PROTECT(old_level); \ SYS_ARCH_PROTECT(old_level); \ var = val; \ SYS_ARCH_UNPROTECT(old_level); \ } while(0) #endif /* SYS_ARCH_SET */ #ifdef __cplusplus } #endif #endif /* LWIP_HDR_SYS_H */ ocproxy-1.60/lwip/src/include/lwip/tcp.h000066400000000000000000000354621303453231400202520ustar00rootroot00000000000000/* * Copyright (c) 2001-2004 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #ifndef LWIP_HDR_TCP_H #define LWIP_HDR_TCP_H #include "lwip/opt.h" #if LWIP_TCP /* don't build if not configured for use in lwipopts.h */ #include "lwip/mem.h" #include "lwip/pbuf.h" #include "lwip/ip.h" #include "lwip/icmp.h" #include "lwip/err.h" #include "lwip/ip6.h" #include "lwip/ip6_addr.h" #ifdef __cplusplus extern "C" { #endif struct tcp_pcb; /** Function prototype for tcp accept callback functions. Called when a new * connection can be accepted on a listening pcb. * * @param arg Additional argument to pass to the callback function (@see tcp_arg()) * @param newpcb The new connection pcb * @param err An error code if there has been an error accepting. * Only return ERR_ABRT if you have called tcp_abort from within the * callback function! */ typedef err_t (*tcp_accept_fn)(void *arg, struct tcp_pcb *newpcb, err_t err); /** Function prototype for tcp receive callback functions. Called when data has * been received. * * @param arg Additional argument to pass to the callback function (@see tcp_arg()) * @param tpcb The connection pcb which received data * @param p The received data (or NULL when the connection has been closed!) * @param err An error code if there has been an error receiving * Only return ERR_ABRT if you have called tcp_abort from within the * callback function! */ typedef err_t (*tcp_recv_fn)(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err); /** Function prototype for tcp sent callback functions. Called when sent data has * been acknowledged by the remote side. Use it to free corresponding resources. * This also means that the pcb has now space available to send new data. * * @param arg Additional argument to pass to the callback function (@see tcp_arg()) * @param tpcb The connection pcb for which data has been acknowledged * @param len The amount of bytes acknowledged * @return ERR_OK: try to send some data by calling tcp_output * Only return ERR_ABRT if you have called tcp_abort from within the * callback function! */ typedef err_t (*tcp_sent_fn)(void *arg, struct tcp_pcb *tpcb, u16_t len); /** Function prototype for tcp poll callback functions. Called periodically as * specified by @see tcp_poll. * * @param arg Additional argument to pass to the callback function (@see tcp_arg()) * @param tpcb tcp pcb * @return ERR_OK: try to send some data by calling tcp_output * Only return ERR_ABRT if you have called tcp_abort from within the * callback function! */ typedef err_t (*tcp_poll_fn)(void *arg, struct tcp_pcb *tpcb); /** Function prototype for tcp error callback functions. Called when the pcb * receives a RST or is unexpectedly closed for any other reason. * * @note The corresponding pcb is already freed when this callback is called! * * @param arg Additional argument to pass to the callback function (@see tcp_arg()) * @param err Error code to indicate why the pcb has been closed * ERR_ABRT: aborted through tcp_abort or by a TCP timer * ERR_RST: the connection was reset by the remote host */ typedef void (*tcp_err_fn)(void *arg, err_t err); /** Function prototype for tcp connected callback functions. Called when a pcb * is connected to the remote side after initiating a connection attempt by * calling tcp_connect(). * * @param arg Additional argument to pass to the callback function (@see tcp_arg()) * @param tpcb The connection pcb which is connected * @param err An unused error code, always ERR_OK currently ;-) TODO! * Only return ERR_ABRT if you have called tcp_abort from within the * callback function! * * @note When a connection attempt fails, the error callback is currently called! */ typedef err_t (*tcp_connected_fn)(void *arg, struct tcp_pcb *tpcb, err_t err); #if LWIP_WND_SCALE #define RCV_WND_SCALE(pcb, wnd) (((wnd) >> (pcb)->rcv_scale)) #define SND_WND_SCALE(pcb, wnd) (((wnd) << (pcb)->snd_scale)) typedef u32_t tcpwnd_size_t; typedef u16_t tcpflags_t; #else #define RCV_WND_SCALE(pcb, wnd) (wnd) #define SND_WND_SCALE(pcb, wnd) (wnd) typedef u16_t tcpwnd_size_t; typedef u8_t tcpflags_t; #endif enum tcp_state { CLOSED = 0, LISTEN = 1, SYN_SENT = 2, SYN_RCVD = 3, ESTABLISHED = 4, FIN_WAIT_1 = 5, FIN_WAIT_2 = 6, CLOSE_WAIT = 7, CLOSING = 8, LAST_ACK = 9, TIME_WAIT = 10 }; #if LWIP_CALLBACK_API /* Function to call when a listener has been connected. * @param arg user-supplied argument (tcp_pcb.callback_arg) * @param pcb a new tcp_pcb that now is connected * @param err an error argument (TODO: that is current always ERR_OK?) * @return ERR_OK: accept the new connection, * any other err_t abortsthe new connection */ #define DEF_ACCEPT_CALLBACK tcp_accept_fn accept; #else /* LWIP_CALLBACK_API */ #define DEF_ACCEPT_CALLBACK #endif /* LWIP_CALLBACK_API */ /** * members common to struct tcp_pcb and struct tcp_listen_pcb */ #define TCP_PCB_COMMON(type) \ type *next; /* for the linked list */ \ void *callback_arg; \ /* the accept callback for listen- and normal pcbs, if LWIP_CALLBACK_API */ \ DEF_ACCEPT_CALLBACK \ enum tcp_state state; /* TCP state */ \ u8_t prio; \ /* ports are in host byte order */ \ u16_t local_port /* the TCP protocol control block */ struct tcp_pcb { /** common PCB members */ IP_PCB; /** protocol specific PCB members */ TCP_PCB_COMMON(struct tcp_pcb); /* ports are in host byte order */ u16_t remote_port; tcpflags_t flags; #define TF_ACK_DELAY ((tcpflags_t)0x0001U) /* Delayed ACK. */ #define TF_ACK_NOW ((tcpflags_t)0x0002U) /* Immediate ACK. */ #define TF_INFR ((tcpflags_t)0x0004U) /* In fast recovery. */ #define TF_TIMESTAMP ((tcpflags_t)0x0008U) /* Timestamp option enabled */ #define TF_RXCLOSED ((tcpflags_t)0x0010U) /* rx closed by tcp_shutdown */ #define TF_FIN ((tcpflags_t)0x0020U) /* Connection was closed locally (FIN segment enqueued). */ #define TF_NODELAY ((tcpflags_t)0x0040U) /* Disable Nagle algorithm */ #define TF_NAGLEMEMERR ((tcpflags_t)0x0080U) /* nagle enabled, memerr, try to output to prevent delayed ACK to happen */ #if LWIP_WND_SCALE #define TF_WND_SCALE ((tcpflags_t)0x0100U) /* Window Scale option enabled */ #endif /* the rest of the fields are in host byte order as we have to do some math with them */ /* Timers */ u8_t polltmr, pollinterval; u8_t last_timer; u32_t tmr; /* receiver variables */ u32_t rcv_nxt; /* next seqno expected */ tcpwnd_size_t rcv_wnd; /* receiver window available */ tcpwnd_size_t rcv_ann_wnd; /* receiver window to announce */ u32_t rcv_ann_right_edge; /* announced right edge of window */ /* Retransmission timer. */ s16_t rtime; u16_t mss; /* maximum segment size */ /* RTT (round trip time) estimation variables */ u32_t rttest; /* RTT estimate in 500ms ticks */ u32_t rtseq; /* sequence number being timed */ s16_t sa, sv; /* @todo document this */ s16_t rto; /* retransmission time-out */ u8_t nrtx; /* number of retransmissions */ /* fast retransmit/recovery */ u8_t dupacks; u32_t lastack; /* Highest acknowledged seqno. */ /* congestion avoidance/control variables */ tcpwnd_size_t cwnd; tcpwnd_size_t ssthresh; /* sender variables */ u32_t snd_nxt; /* next new seqno to be sent */ u32_t snd_wl1, snd_wl2; /* Sequence and acknowledgement numbers of last window update. */ u32_t snd_lbb; /* Sequence number of next byte to be buffered. */ tcpwnd_size_t snd_wnd; /* sender window */ tcpwnd_size_t snd_wnd_max; /* the maximum sender window announced by the remote host */ tcpwnd_size_t acked; tcpwnd_size_t snd_buf; /* Available buffer space for sending (in bytes). */ #define TCP_SNDQUEUELEN_OVERFLOW (0xffffU-3) u16_t snd_queuelen; /* Available buffer space for sending (in pbufs). */ #if TCP_OVERSIZE /* Extra bytes available at the end of the last pbuf in unsent. */ u16_t unsent_oversize; #endif /* TCP_OVERSIZE */ /* These are ordered by sequence number: */ struct tcp_seg *unsent; /* Unsent (queued) segments. */ struct tcp_seg *unacked; /* Sent but unacknowledged segments. */ #if TCP_QUEUE_OOSEQ struct tcp_seg *ooseq; /* Received out of sequence segments. */ #endif /* TCP_QUEUE_OOSEQ */ struct pbuf *refused_data; /* Data previously received but not yet taken by upper layer */ #if LWIP_CALLBACK_API /* Function to be called when more send buffer space is available. */ tcp_sent_fn sent; /* Function to be called when (in-sequence) data has arrived. */ tcp_recv_fn recv; /* Function to be called when a connection has been set up. */ tcp_connected_fn connected; /* Function which is called periodically. */ tcp_poll_fn poll; /* Function to be called whenever a fatal error occurs. */ tcp_err_fn errf; #endif /* LWIP_CALLBACK_API */ #if LWIP_TCP_TIMESTAMPS u32_t ts_lastacksent; u32_t ts_recent; #endif /* LWIP_TCP_TIMESTAMPS */ /* idle time before KEEPALIVE is sent */ u32_t keep_idle; #if LWIP_TCP_KEEPALIVE u32_t keep_intvl; u32_t keep_cnt; #endif /* LWIP_TCP_KEEPALIVE */ /* Persist timer counter */ u8_t persist_cnt; /* Persist timer back-off */ u8_t persist_backoff; /* KEEPALIVE counter */ u8_t keep_cnt_sent; #if LWIP_WND_SCALE u8_t snd_scale; u8_t rcv_scale; #endif }; struct tcp_pcb_listen { /* Common members of all PCB types */ IP_PCB; /* Protocol specific PCB members */ TCP_PCB_COMMON(struct tcp_pcb_listen); #if TCP_LISTEN_BACKLOG u8_t backlog; u8_t accepts_pending; #endif /* TCP_LISTEN_BACKLOG */ #if LWIP_IPV6 u8_t accept_any_ip_version; #endif /* LWIP_IPV6 */ }; #if LWIP_EVENT_API enum lwip_event { LWIP_EVENT_ACCEPT, LWIP_EVENT_SENT, LWIP_EVENT_RECV, LWIP_EVENT_CONNECTED, LWIP_EVENT_POLL, LWIP_EVENT_ERR }; err_t lwip_tcp_event(void *arg, struct tcp_pcb *pcb, enum lwip_event, struct pbuf *p, u16_t size, err_t err); #endif /* LWIP_EVENT_API */ /* Application program's interface: */ struct tcp_pcb * tcp_new (void); void tcp_arg (struct tcp_pcb *pcb, void *arg); void tcp_accept (struct tcp_pcb *pcb, tcp_accept_fn accept); void tcp_recv (struct tcp_pcb *pcb, tcp_recv_fn recv); void tcp_sent (struct tcp_pcb *pcb, tcp_sent_fn sent); void tcp_poll (struct tcp_pcb *pcb, tcp_poll_fn poll, u8_t interval); void tcp_err (struct tcp_pcb *pcb, tcp_err_fn err); #define tcp_mss(pcb) (((pcb)->flags & TF_TIMESTAMP) ? ((pcb)->mss - 12) : (pcb)->mss) #define tcp_sndbuf(pcb) ((pcb)->snd_buf) #define tcp_sndqueuelen(pcb) ((pcb)->snd_queuelen) #define tcp_nagle_disable(pcb) ((pcb)->flags |= TF_NODELAY) #define tcp_nagle_enable(pcb) ((pcb)->flags &= ~TF_NODELAY) #define tcp_nagle_disabled(pcb) (((pcb)->flags & TF_NODELAY) != 0) #if TCP_LISTEN_BACKLOG #define tcp_accepted(pcb) do { \ LWIP_ASSERT("pcb->state == LISTEN (called for wrong pcb?)", pcb->state == LISTEN); \ (((struct tcp_pcb_listen *)(pcb))->accepts_pending--); } while(0) #else /* TCP_LISTEN_BACKLOG */ #define tcp_accepted(pcb) LWIP_ASSERT("pcb->state == LISTEN (called for wrong pcb?)", \ (pcb)->state == LISTEN) #endif /* TCP_LISTEN_BACKLOG */ void tcp_recved (struct tcp_pcb *pcb, u16_t len); err_t tcp_bind (struct tcp_pcb *pcb, ip_addr_t *ipaddr, u16_t port); err_t tcp_connect (struct tcp_pcb *pcb, ip_addr_t *ipaddr, u16_t port, tcp_connected_fn connected); struct tcp_pcb * tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog); #define tcp_listen(pcb) tcp_listen_with_backlog(pcb, TCP_DEFAULT_LISTEN_BACKLOG) void tcp_abort (struct tcp_pcb *pcb); err_t tcp_close (struct tcp_pcb *pcb); err_t tcp_shutdown(struct tcp_pcb *pcb, int shut_rx, int shut_tx); /* Flags for "apiflags" parameter in tcp_write */ #define TCP_WRITE_FLAG_COPY 0x01 #define TCP_WRITE_FLAG_MORE 0x02 err_t tcp_write (struct tcp_pcb *pcb, const void *dataptr, u16_t len, u8_t apiflags); void tcp_setprio (struct tcp_pcb *pcb, u8_t prio); #define TCP_PRIO_MIN 1 #define TCP_PRIO_NORMAL 64 #define TCP_PRIO_MAX 127 err_t tcp_output (struct tcp_pcb *pcb); const char* tcp_debug_state_str(enum tcp_state s); #if LWIP_IPV6 struct tcp_pcb * tcp_new_ip6 (void); #define tcp_bind_ip6(pcb, ip6addr, port) \ tcp_bind(pcb, ip6_2_ip(ip6addr), port) #define tcp_connect_ip6(pcb, ip6addr, port, connected) \ tcp_connect(pcb, ip6_2_ip(ip6addr), port, connected) struct tcp_pcb * tcp_listen_dual_with_backlog(struct tcp_pcb *pcb, u8_t backlog); #define tcp_listen_dual(pcb) tcp_listen_dual_with_backlog(pcb, TCP_DEFAULT_LISTEN_BACKLOG) #else /* LWIP_IPV6 */ #define tcp_listen_dual_with_backlog(pcb, backlog) tcp_listen_with_backlog(pcb, backlog) #define tcp_listen_dual(pcb) tcp_listen(pcb) #endif /* LWIP_IPV6 */ #ifdef __cplusplus } #endif #endif /* LWIP_TCP */ #endif /* LWIP_HDR_TCP_H */ ocproxy-1.60/lwip/src/include/lwip/tcp_impl.h000066400000000000000000000534531303453231400212730ustar00rootroot00000000000000/* * Copyright (c) 2001-2004 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #ifndef LWIP_HDR_TCP_IMPL_H #define LWIP_HDR_TCP_IMPL_H #include "lwip/opt.h" #if LWIP_TCP /* don't build if not configured for use in lwipopts.h */ #include "lwip/tcp.h" #include "lwip/mem.h" #include "lwip/pbuf.h" #include "lwip/ip.h" #include "lwip/icmp.h" #include "lwip/err.h" #include "lwip/ip6.h" #include "lwip/ip6_addr.h" #ifdef __cplusplus extern "C" { #endif /* Functions for interfacing with TCP: */ /* Lower layer interface to TCP: */ void tcp_init (void); /* Initialize this module. */ void tcp_tmr (void); /* Must be called every TCP_TMR_INTERVAL ms. (Typically 250 ms). */ /* It is also possible to call these two functions at the right intervals (instead of calling tcp_tmr()). */ void tcp_slowtmr (void); void tcp_fasttmr (void); /* Only used by IP to pass a TCP segment to TCP: */ void tcp_input (struct pbuf *p, struct netif *inp); /* Used within the TCP code only: */ struct tcp_pcb * tcp_alloc (u8_t prio); void tcp_abandon (struct tcp_pcb *pcb, int reset); err_t tcp_send_empty_ack(struct tcp_pcb *pcb); void tcp_rexmit (struct tcp_pcb *pcb); void tcp_rexmit_rto (struct tcp_pcb *pcb); void tcp_rexmit_fast (struct tcp_pcb *pcb); u32_t tcp_update_rcv_ann_wnd(struct tcp_pcb *pcb); err_t tcp_process_refused_data(struct tcp_pcb *pcb); /** * This is the Nagle algorithm: try to combine user data to send as few TCP * segments as possible. Only send if * - no previously transmitted data on the connection remains unacknowledged or * - the TF_NODELAY flag is set (nagle algorithm turned off for this pcb) or * - the only unsent segment is at least pcb->mss bytes long (or there is more * than one unsent segment - with lwIP, this can happen although unsent->len < mss) * - or if we are in fast-retransmit (TF_INFR) */ #define tcp_do_output_nagle(tpcb) ((((tpcb)->unacked == NULL) || \ ((tpcb)->flags & (TF_NODELAY | TF_INFR)) || \ (((tpcb)->unsent != NULL) && (((tpcb)->unsent->next != NULL) || \ ((tpcb)->unsent->len >= (tpcb)->mss))) || \ ((tcp_sndbuf(tpcb) == 0) || (tcp_sndqueuelen(tpcb) >= TCP_SND_QUEUELEN)) \ ) ? 1 : 0) #define tcp_output_nagle(tpcb) (tcp_do_output_nagle(tpcb) ? tcp_output(tpcb) : ERR_OK) #define TCP_SEQ_LT(a,b) ((s32_t)((u32_t)(a) - (u32_t)(b)) < 0) #define TCP_SEQ_LEQ(a,b) ((s32_t)((u32_t)(a) - (u32_t)(b)) <= 0) #define TCP_SEQ_GT(a,b) ((s32_t)((u32_t)(a) - (u32_t)(b)) > 0) #define TCP_SEQ_GEQ(a,b) ((s32_t)((u32_t)(a) - (u32_t)(b)) >= 0) /* is b<=a<=c? */ #if 0 /* see bug #10548 */ #define TCP_SEQ_BETWEEN(a,b,c) ((c)-(b) >= (a)-(b)) #endif #define TCP_SEQ_BETWEEN(a,b,c) (TCP_SEQ_GEQ(a,b) && TCP_SEQ_LEQ(a,c)) #define TCP_FIN 0x01U #define TCP_SYN 0x02U #define TCP_RST 0x04U #define TCP_PSH 0x08U #define TCP_ACK 0x10U #define TCP_URG 0x20U #define TCP_ECE 0x40U #define TCP_CWR 0x80U #define TCP_FLAGS 0x3fU /* Length of the TCP header, excluding options. */ #define TCP_HLEN 20 #ifndef TCP_TMR_INTERVAL #define TCP_TMR_INTERVAL 250 /* The TCP timer interval in milliseconds. */ #endif /* TCP_TMR_INTERVAL */ #ifndef TCP_FAST_INTERVAL #define TCP_FAST_INTERVAL TCP_TMR_INTERVAL /* the fine grained timeout in milliseconds */ #endif /* TCP_FAST_INTERVAL */ #ifndef TCP_SLOW_INTERVAL #define TCP_SLOW_INTERVAL (2*TCP_TMR_INTERVAL) /* the coarse grained timeout in milliseconds */ #endif /* TCP_SLOW_INTERVAL */ #define TCP_FIN_WAIT_TIMEOUT 20000 /* milliseconds */ #define TCP_SYN_RCVD_TIMEOUT 20000 /* milliseconds */ #define TCP_OOSEQ_TIMEOUT 6U /* x RTO */ #ifndef TCP_MSL #define TCP_MSL 60000UL /* The maximum segment lifetime in milliseconds */ #endif /* Keepalive values, compliant with RFC 1122. Don't change this unless you know what you're doing */ #ifndef TCP_KEEPIDLE_DEFAULT #define TCP_KEEPIDLE_DEFAULT 7200000UL /* Default KEEPALIVE timer in milliseconds */ #endif #ifndef TCP_KEEPINTVL_DEFAULT #define TCP_KEEPINTVL_DEFAULT 75000UL /* Default Time between KEEPALIVE probes in milliseconds */ #endif #ifndef TCP_KEEPCNT_DEFAULT #define TCP_KEEPCNT_DEFAULT 9U /* Default Counter for KEEPALIVE probes */ #endif #define TCP_MAXIDLE TCP_KEEPCNT_DEFAULT * TCP_KEEPINTVL_DEFAULT /* Maximum KEEPALIVE probe time */ /* Fields are (of course) in network byte order. * Some fields are converted to host byte order in tcp_input(). */ #ifdef PACK_STRUCT_USE_INCLUDES # include "arch/bpstruct.h" #endif PACK_STRUCT_BEGIN struct tcp_hdr { PACK_STRUCT_FIELD(u16_t src); PACK_STRUCT_FIELD(u16_t dest); PACK_STRUCT_FIELD(u32_t seqno); PACK_STRUCT_FIELD(u32_t ackno); PACK_STRUCT_FIELD(u16_t _hdrlen_rsvd_flags); PACK_STRUCT_FIELD(u16_t wnd); PACK_STRUCT_FIELD(u16_t chksum); PACK_STRUCT_FIELD(u16_t urgp); } PACK_STRUCT_STRUCT; PACK_STRUCT_END #ifdef PACK_STRUCT_USE_INCLUDES # include "arch/epstruct.h" #endif #define TCPH_HDRLEN(phdr) (ntohs((phdr)->_hdrlen_rsvd_flags) >> 12) #define TCPH_FLAGS(phdr) (ntohs((phdr)->_hdrlen_rsvd_flags) & TCP_FLAGS) #define TCPH_HDRLEN_SET(phdr, len) (phdr)->_hdrlen_rsvd_flags = htons(((len) << 12) | TCPH_FLAGS(phdr)) #define TCPH_FLAGS_SET(phdr, flags) (phdr)->_hdrlen_rsvd_flags = (((phdr)->_hdrlen_rsvd_flags & PP_HTONS((u16_t)(~(u16_t)(TCP_FLAGS)))) | htons(flags)) #define TCPH_HDRLEN_FLAGS_SET(phdr, len, flags) (phdr)->_hdrlen_rsvd_flags = htons(((len) << 12) | (flags)) #define TCPH_SET_FLAG(phdr, flags ) (phdr)->_hdrlen_rsvd_flags = ((phdr)->_hdrlen_rsvd_flags | htons(flags)) #define TCPH_UNSET_FLAG(phdr, flags) (phdr)->_hdrlen_rsvd_flags = htons(ntohs((phdr)->_hdrlen_rsvd_flags) | (TCPH_FLAGS(phdr) & ~(flags)) ) #define TCP_TCPLEN(seg) ((seg)->len + (((TCPH_FLAGS((seg)->tcphdr) & (TCP_FIN | TCP_SYN)) != 0) ? 1U : 0U)) /** Flags used on input processing, not on pcb->flags */ #define TF_RESET (u8_t)0x08U /* Connection was reset. */ #define TF_CLOSED (u8_t)0x10U /* Connection was sucessfully closed. */ #define TF_GOT_FIN (u8_t)0x20U /* Connection was closed by the remote end. */ #if LWIP_EVENT_API #define TCP_EVENT_ACCEPT(pcb,err,ret) ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\ LWIP_EVENT_ACCEPT, NULL, 0, err) #define TCP_EVENT_SENT(pcb,space,ret) ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\ LWIP_EVENT_SENT, NULL, space, ERR_OK) #define TCP_EVENT_RECV(pcb,p,err,ret) ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\ LWIP_EVENT_RECV, (p), 0, (err)) #define TCP_EVENT_CLOSED(pcb,ret) ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\ LWIP_EVENT_RECV, NULL, 0, ERR_OK) #define TCP_EVENT_CONNECTED(pcb,err,ret) ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\ LWIP_EVENT_CONNECTED, NULL, 0, (err)) #define TCP_EVENT_POLL(pcb,ret) ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\ LWIP_EVENT_POLL, NULL, 0, ERR_OK) #define TCP_EVENT_ERR(errf,arg,err) lwip_tcp_event((arg), NULL, \ LWIP_EVENT_ERR, NULL, 0, (err)) #else /* LWIP_EVENT_API */ #define TCP_EVENT_ACCEPT(pcb,err,ret) \ do { \ if((pcb)->accept != NULL) \ (ret) = (pcb)->accept((pcb)->callback_arg,(pcb),(err)); \ else (ret) = ERR_ARG; \ } while (0) #define TCP_EVENT_SENT(pcb,space,ret) \ do { \ if((pcb)->sent != NULL) \ (ret) = (pcb)->sent((pcb)->callback_arg,(pcb),(space)); \ else (ret) = ERR_OK; \ } while (0) #define TCP_EVENT_RECV(pcb,p,err,ret) \ do { \ if((pcb)->recv != NULL) { \ (ret) = (pcb)->recv((pcb)->callback_arg,(pcb),(p),(err));\ } else { \ (ret) = tcp_recv_null(NULL, (pcb), (p), (err)); \ } \ } while (0) #define TCP_EVENT_CLOSED(pcb,ret) \ do { \ if(((pcb)->recv != NULL)) { \ (ret) = (pcb)->recv((pcb)->callback_arg,(pcb),NULL,ERR_OK);\ } else { \ (ret) = ERR_OK; \ } \ } while (0) #define TCP_EVENT_CONNECTED(pcb,err,ret) \ do { \ if((pcb)->connected != NULL) \ (ret) = (pcb)->connected((pcb)->callback_arg,(pcb),(err)); \ else (ret) = ERR_OK; \ } while (0) #define TCP_EVENT_POLL(pcb,ret) \ do { \ if((pcb)->poll != NULL) \ (ret) = (pcb)->poll((pcb)->callback_arg,(pcb)); \ else (ret) = ERR_OK; \ } while (0) #define TCP_EVENT_ERR(errf,arg,err) \ do { \ if((errf) != NULL) \ (errf)((arg),(err)); \ } while (0) #endif /* LWIP_EVENT_API */ /** Enabled extra-check for TCP_OVERSIZE if LWIP_DEBUG is enabled */ #if TCP_OVERSIZE && defined(LWIP_DEBUG) #define TCP_OVERSIZE_DBGCHECK 1 #else #define TCP_OVERSIZE_DBGCHECK 0 #endif /** Don't generate checksum on copy if CHECKSUM_GEN_TCP is disabled */ #define TCP_CHECKSUM_ON_COPY (LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_TCP) /* This structure represents a TCP segment on the unsent, unacked and ooseq queues */ struct tcp_seg { struct tcp_seg *next; /* used when putting segements on a queue */ struct pbuf *p; /* buffer containing data + TCP header */ u16_t len; /* the TCP length of this segment */ #if TCP_OVERSIZE_DBGCHECK u16_t oversize_left; /* Extra bytes available at the end of the last pbuf in unsent (used for asserting vs. tcp_pcb.unsent_oversized only) */ #endif /* TCP_OVERSIZE_DBGCHECK */ #if TCP_CHECKSUM_ON_COPY u16_t chksum; u8_t chksum_swapped; #endif /* TCP_CHECKSUM_ON_COPY */ u8_t flags; #define TF_SEG_OPTS_MSS (u8_t)0x01U /* Include MSS option. */ #define TF_SEG_OPTS_TS (u8_t)0x02U /* Include timestamp option. */ #define TF_SEG_DATA_CHECKSUMMED (u8_t)0x04U /* ALL data (not the header) is checksummed into 'chksum' */ #define TF_SEG_OPTS_WND_SCALE (u8_t)0x08U /* Include WND SCALE option */ struct tcp_hdr *tcphdr; /* the TCP header */ }; #define LWIP_TCP_OPT_EOL 0 #define LWIP_TCP_OPT_NOP 1 #define LWIP_TCP_OPT_MSS 2 #define LWIP_TCP_OPT_WS 3 #define LWIP_TCP_OPT_TS 8 #define LWIP_TCP_OPT_LEN_MSS 4 #if LWIP_TCP_TIMESTAMPS #define LWIP_TCP_OPT_LEN_TS 10 #define LWIP_TCP_OPT_LEN_TS_OUT 12 /* aligned for output (includes NOP padding) */ #else #define LWIP_TCP_OPT_LEN_TS_OUT 0 #endif #if LWIP_WND_SCALE #define LWIP_TCP_OPT_LEN_WS 3 #define LWIP_TCP_OPT_LEN_WS_OUT 4 /* aligned for output (includes NOP padding) */ #else #define LWIP_TCP_OPT_LEN_WS_OUT 0 #endif #define LWIP_TCP_OPT_LENGTH(flags) \ (flags & TF_SEG_OPTS_MSS ? LWIP_TCP_OPT_LEN_MSS : 0) + \ (flags & TF_SEG_OPTS_TS ? LWIP_TCP_OPT_LEN_TS_OUT : 0) + \ (flags & TF_SEG_OPTS_WND_SCALE ? LWIP_TCP_OPT_LEN_WS_OUT : 0) /** This returns a TCP header option for MSS in an u32_t */ #define TCP_BUILD_MSS_OPTION(mss) htonl(0x02040000 | ((mss) & 0xFFFF)) #if LWIP_WND_SCALE #define TCPWNDSIZE_F U32_F #define TCPWND_MAX 0xFFFFFFFFU #else /* LWIP_WND_SCALE */ #define TCPWNDSIZE_F U16_F #define TCPWND_MAX 0xFFFFU #endif /* LWIP_WND_SCALE */ /* Global variables: */ extern struct tcp_pcb *tcp_input_pcb; extern u32_t tcp_ticks; extern u8_t tcp_active_pcbs_changed; /* The TCP PCB lists. */ union tcp_listen_pcbs_t { /* List of all TCP PCBs in LISTEN state. */ struct tcp_pcb_listen *listen_pcbs; struct tcp_pcb *pcbs; }; extern struct tcp_pcb *tcp_bound_pcbs; extern union tcp_listen_pcbs_t tcp_listen_pcbs; extern struct tcp_pcb *tcp_active_pcbs; /* List of all TCP PCBs that are in a state in which they accept or send data. */ extern struct tcp_pcb *tcp_tw_pcbs; /* List of all TCP PCBs in TIME-WAIT. */ extern struct tcp_pcb *tcp_tmp_pcb; /* Only used for temporary storage. */ /* Axioms about the above lists: 1) Every TCP PCB that is not CLOSED is in one of the lists. 2) A PCB is only in one of the lists. 3) All PCBs in the tcp_listen_pcbs list is in LISTEN state. 4) All PCBs in the tcp_tw_pcbs list is in TIME-WAIT state. */ /* Define two macros, TCP_REG and TCP_RMV that registers a TCP PCB with a PCB list or removes a PCB from a list, respectively. */ #ifndef TCP_DEBUG_PCB_LISTS #define TCP_DEBUG_PCB_LISTS 0 #endif #if TCP_DEBUG_PCB_LISTS #define TCP_REG(pcbs, npcb) do {\ LWIP_DEBUGF(TCP_DEBUG, ("TCP_REG %p local port %d\n", (npcb), (npcb)->local_port)); \ for(tcp_tmp_pcb = *(pcbs); \ tcp_tmp_pcb != NULL; \ tcp_tmp_pcb = tcp_tmp_pcb->next) { \ LWIP_ASSERT("TCP_REG: already registered\n", tcp_tmp_pcb != (npcb)); \ } \ LWIP_ASSERT("TCP_REG: pcb->state != CLOSED", ((pcbs) == &tcp_bound_pcbs) || ((npcb)->state != CLOSED)); \ (npcb)->next = *(pcbs); \ LWIP_ASSERT("TCP_REG: npcb->next != npcb", (npcb)->next != (npcb)); \ *(pcbs) = (npcb); \ LWIP_ASSERT("TCP_RMV: tcp_pcbs sane", tcp_pcbs_sane()); \ tcp_timer_needed(); \ } while(0) #define TCP_RMV(pcbs, npcb) do { \ LWIP_ASSERT("TCP_RMV: pcbs != NULL", *(pcbs) != NULL); \ LWIP_DEBUGF(TCP_DEBUG, ("TCP_RMV: removing %p from %p\n", (npcb), *(pcbs))); \ if(*(pcbs) == (npcb)) { \ *(pcbs) = (*pcbs)->next; \ } else for(tcp_tmp_pcb = *(pcbs); tcp_tmp_pcb != NULL; tcp_tmp_pcb = tcp_tmp_pcb->next) { \ if(tcp_tmp_pcb->next == (npcb)) { \ tcp_tmp_pcb->next = (npcb)->next; \ break; \ } \ } \ (npcb)->next = NULL; \ LWIP_ASSERT("TCP_RMV: tcp_pcbs sane", tcp_pcbs_sane()); \ LWIP_DEBUGF(TCP_DEBUG, ("TCP_RMV: removed %p from %p\n", (npcb), *(pcbs))); \ } while(0) #else /* LWIP_DEBUG */ #define TCP_REG(pcbs, npcb) \ do { \ (npcb)->next = *pcbs; \ *(pcbs) = (npcb); \ tcp_timer_needed(); \ } while (0) #define TCP_RMV(pcbs, npcb) \ do { \ if(*(pcbs) == (npcb)) { \ (*(pcbs)) = (*pcbs)->next; \ } \ else { \ for(tcp_tmp_pcb = *pcbs; \ tcp_tmp_pcb != NULL; \ tcp_tmp_pcb = tcp_tmp_pcb->next) { \ if(tcp_tmp_pcb->next == (npcb)) { \ tcp_tmp_pcb->next = (npcb)->next; \ break; \ } \ } \ } \ (npcb)->next = NULL; \ } while(0) #endif /* LWIP_DEBUG */ #define TCP_REG_ACTIVE(npcb) \ do { \ TCP_REG(&tcp_active_pcbs, npcb); \ tcp_active_pcbs_changed = 1; \ } while (0) #define TCP_RMV_ACTIVE(npcb) \ do { \ TCP_RMV(&tcp_active_pcbs, npcb); \ tcp_active_pcbs_changed = 1; \ } while (0) #define TCP_PCB_REMOVE_ACTIVE(pcb) \ do { \ tcp_pcb_remove(&tcp_active_pcbs, pcb); \ tcp_active_pcbs_changed = 1; \ } while (0) /* Internal functions: */ struct tcp_pcb *tcp_pcb_copy(struct tcp_pcb *pcb); void tcp_pcb_purge(struct tcp_pcb *pcb); void tcp_pcb_remove(struct tcp_pcb **pcblist, struct tcp_pcb *pcb); void tcp_segs_free(struct tcp_seg *seg); void tcp_seg_free(struct tcp_seg *seg); struct tcp_seg *tcp_seg_copy(struct tcp_seg *seg); #define tcp_ack(pcb) \ do { \ if((pcb)->flags & TF_ACK_DELAY) { \ (pcb)->flags &= ~TF_ACK_DELAY; \ (pcb)->flags |= TF_ACK_NOW; \ } \ else { \ (pcb)->flags |= TF_ACK_DELAY; \ } \ } while (0) #define tcp_ack_now(pcb) \ do { \ (pcb)->flags |= TF_ACK_NOW; \ } while (0) err_t tcp_send_fin(struct tcp_pcb *pcb); err_t tcp_enqueue_flags(struct tcp_pcb *pcb, u8_t flags); void tcp_rexmit_seg(struct tcp_pcb *pcb, struct tcp_seg *seg); void tcp_rst_impl(u32_t seqno, u32_t ackno, ipX_addr_t *local_ip, ipX_addr_t *remote_ip, u16_t local_port, u16_t remote_port #if LWIP_IPV6 , u8_t isipv6 #endif /* LWIP_IPV6 */ ); #if LWIP_IPV6 #define tcp_rst(seqno, ackno, local_ip, remote_ip, local_port, remote_port, isipv6) \ tcp_rst_impl(seqno, ackno, local_ip, remote_ip, local_port, remote_port, isipv6) #else /* LWIP_IPV6 */ #define tcp_rst(seqno, ackno, local_ip, remote_ip, local_port, remote_port, isipv6) \ tcp_rst_impl(seqno, ackno, local_ip, remote_ip, local_port, remote_port) #endif /* LWIP_IPV6 */ u32_t tcp_next_iss(void); void tcp_keepalive(struct tcp_pcb *pcb); void tcp_zero_window_probe(struct tcp_pcb *pcb); #if TCP_CALCULATE_EFF_SEND_MSS u16_t tcp_eff_send_mss_impl(u16_t sendmss, ipX_addr_t *dest #if LWIP_IPV6 , ipX_addr_t *src, u8_t isipv6 #endif /* LWIP_IPV6 */ ); #if LWIP_IPV6 #define tcp_eff_send_mss(sendmss, src, dest, isipv6) tcp_eff_send_mss_impl(sendmss, dest, src, isipv6) #else /* LWIP_IPV6 */ #define tcp_eff_send_mss(sendmss, src, dest, isipv6) tcp_eff_send_mss_impl(sendmss, dest) #endif /* LWIP_IPV6 */ #endif /* TCP_CALCULATE_EFF_SEND_MSS */ #if LWIP_CALLBACK_API err_t tcp_recv_null(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err); #endif /* LWIP_CALLBACK_API */ #if TCP_DEBUG || TCP_INPUT_DEBUG || TCP_OUTPUT_DEBUG void tcp_debug_print(struct tcp_hdr *tcphdr); void tcp_debug_print_flags(u8_t flags); void tcp_debug_print_state(enum tcp_state s); void tcp_debug_print_pcbs(void); s16_t tcp_pcbs_sane(void); #else # define tcp_debug_print(tcphdr) # define tcp_debug_print_flags(flags) # define tcp_debug_print_state(s) # define tcp_debug_print_pcbs() # define tcp_pcbs_sane() 1 #endif /* TCP_DEBUG */ /** External function (implemented in timers.c), called when TCP detects * that a timer is needed (i.e. active- or time-wait-pcb found). */ void tcp_timer_needed(void); #ifdef __cplusplus } #endif #endif /* LWIP_TCP */ #endif /* LWIP_HDR_TCP_H */ ocproxy-1.60/lwip/src/include/lwip/tcpip.h000066400000000000000000000166641303453231400206060ustar00rootroot00000000000000/* * Copyright (c) 2001-2004 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #ifndef LWIP_HDR_TCPIP_H #define LWIP_HDR_TCPIP_H #include "lwip/opt.h" #if !NO_SYS /* don't build if not configured for use in lwipopts.h */ #include "lwip/api_msg.h" #include "lwip/netifapi.h" #include "lwip/pppapi.h" #include "lwip/pbuf.h" #include "lwip/api.h" #include "lwip/sys.h" #include "lwip/timers.h" #include "lwip/netif.h" #ifdef __cplusplus extern "C" { #endif /** Define this to something that triggers a watchdog. This is called from * tcpip_thread after processing a message. */ #ifndef LWIP_TCPIP_THREAD_ALIVE #define LWIP_TCPIP_THREAD_ALIVE() #endif #if LWIP_TCPIP_CORE_LOCKING /** The global semaphore to lock the stack. */ extern sys_mutex_t lock_tcpip_core; #define LOCK_TCPIP_CORE() sys_mutex_lock(&lock_tcpip_core) #define UNLOCK_TCPIP_CORE() sys_mutex_unlock(&lock_tcpip_core) #ifdef LWIP_DEBUG #define TCIP_APIMSG_SET_ERR(m, e) (m)->msg.err = e /* catch functions that don't set err */ #else #define TCIP_APIMSG_SET_ERR(m, e) #endif #define TCPIP_APIMSG_NOERR(m,f) do { \ TCIP_APIMSG_SET_ERR(m, ERR_VAL); \ LOCK_TCPIP_CORE(); \ f(&((m)->msg)); \ UNLOCK_TCPIP_CORE(); \ } while(0) #define TCPIP_APIMSG(m,f,e) do { \ TCPIP_APIMSG_NOERR(m,f); \ (e) = (m)->msg.err; \ } while(0) #define TCPIP_APIMSG_ACK(m) #define TCPIP_NETIFAPI(m) tcpip_netifapi_lock(m) #define TCPIP_NETIFAPI_ACK(m) #define TCPIP_PPPAPI(m) tcpip_pppapi_lock(m) #define TCPIP_PPPAPI_ACK(m) #else /* LWIP_TCPIP_CORE_LOCKING */ #define LOCK_TCPIP_CORE() #define UNLOCK_TCPIP_CORE() #define TCPIP_APIMSG_NOERR(m,f) do { (m)->function = f; tcpip_apimsg(m); } while(0) #define TCPIP_APIMSG(m,f,e) do { (m)->function = f; (e) = tcpip_apimsg(m); } while(0) #define TCPIP_APIMSG_ACK(m) sys_sem_signal(&m->conn->op_completed) #define TCPIP_NETIFAPI(m) tcpip_netifapi(m) #define TCPIP_NETIFAPI_ACK(m) sys_sem_signal(&m->sem) #define TCPIP_PPPAPI(m) tcpip_pppapi(m) #define TCPIP_PPPAPI_ACK(m) sys_sem_signal(&m->sem) #endif /* LWIP_TCPIP_CORE_LOCKING */ #if LWIP_MPU_COMPATIBLE #define API_VAR_REF(name) (*(name)) #define API_VAR_DECLARE(type, name) type * name #define API_VAR_ALLOC(type, pool, name) do { \ name = (type *)memp_malloc(pool); \ if (name == NULL) { \ return ERR_MEM; \ } \ } while(0) #define API_VAR_ALLOC_DONTFAIL(type, pool, name) do { \ name = (type *)memp_malloc(pool); \ LWIP_ASSERT("pool empty", name != NULL); \ } while(0) #define API_VAR_FREE(pool, name) memp_free(pool, name) #define API_EXPR_REF(expr) &(expr) #define API_EXPR_DEREF(expr) expr #else /* LWIP_MPU_COMPATIBLE */ #define API_VAR_REF(name) name #define API_VAR_DECLARE(type, name) type name #define API_VAR_ALLOC(type, pool, name) #define API_VAR_ALLOC_DONTFAIL(type, pool, name) #define API_VAR_FREE(pool, name) #define API_EXPR_REF(expr) expr #define API_EXPR_DEREF(expr) *(expr) #endif /* LWIP_MPU_COMPATIBLE */ /** Function prototype for the init_done function passed to tcpip_init */ typedef void (*tcpip_init_done_fn)(void *arg); /** Function prototype for functions passed to tcpip_callback() */ typedef void (*tcpip_callback_fn)(void *ctx); /* Forward declarations */ struct tcpip_callback_msg; void tcpip_init(tcpip_init_done_fn tcpip_init_done, void *arg); #if LWIP_NETCONN err_t tcpip_apimsg(struct api_msg *apimsg); #endif /* LWIP_NETCONN */ err_t tcpip_input(struct pbuf *p, struct netif *inp); #if LWIP_NETIF_API err_t tcpip_netifapi(struct netifapi_msg *netifapimsg); #if LWIP_TCPIP_CORE_LOCKING err_t tcpip_netifapi_lock(struct netifapi_msg *netifapimsg); #endif /* LWIP_TCPIP_CORE_LOCKING */ #endif /* LWIP_NETIF_API */ #if LWIP_PPP_API err_t tcpip_pppapi(struct pppapi_msg *pppapimsg); #if LWIP_TCPIP_CORE_LOCKING err_t tcpip_pppapi_lock(struct pppapi_msg *pppapimsg); #endif /* LWIP_TCPIP_CORE_LOCKING */ #endif /* LWIP_PPP_API */ err_t tcpip_callback_with_block(tcpip_callback_fn function, void *ctx, u8_t block); #define tcpip_callback(f, ctx) tcpip_callback_with_block(f, ctx, 1) struct tcpip_callback_msg* tcpip_callbackmsg_new(tcpip_callback_fn function, void *ctx); void tcpip_callbackmsg_delete(struct tcpip_callback_msg* msg); err_t tcpip_trycallback(struct tcpip_callback_msg* msg); /* free pbufs or heap memory from another context without blocking */ err_t pbuf_free_callback(struct pbuf *p); err_t mem_free_callback(void *m); #if LWIP_TCPIP_TIMEOUT err_t tcpip_timeout(u32_t msecs, sys_timeout_handler h, void *arg); err_t tcpip_untimeout(sys_timeout_handler h, void *arg); #endif /* LWIP_TCPIP_TIMEOUT */ enum tcpip_msg_type { #if LWIP_NETCONN TCPIP_MSG_API, #endif /* LWIP_NETCONN */ TCPIP_MSG_INPKT, #if LWIP_NETIF_API TCPIP_MSG_NETIFAPI, #endif /* LWIP_NETIF_API */ #if LWIP_PPP_API TCPIP_MSG_PPPAPI, #endif /* LWIP_PPP_API */ #if LWIP_TCPIP_TIMEOUT TCPIP_MSG_TIMEOUT, TCPIP_MSG_UNTIMEOUT, #endif /* LWIP_TCPIP_TIMEOUT */ TCPIP_MSG_CALLBACK, TCPIP_MSG_CALLBACK_STATIC }; struct tcpip_msg { enum tcpip_msg_type type; sys_sem_t *sem; union { #if LWIP_NETCONN struct api_msg *apimsg; #endif /* LWIP_NETCONN */ #if LWIP_NETIF_API struct netifapi_msg *netifapimsg; #endif /* LWIP_NETIF_API */ #if LWIP_PPP_API struct pppapi_msg *pppapimsg; #endif /* LWIP_PPP_API */ struct { struct pbuf *p; struct netif *netif; } inp; struct { tcpip_callback_fn function; void *ctx; } cb; #if LWIP_TCPIP_TIMEOUT struct { u32_t msecs; sys_timeout_handler h; void *arg; } tmo; #endif /* LWIP_TCPIP_TIMEOUT */ } msg; }; #ifdef __cplusplus } #endif #endif /* !NO_SYS */ #endif /* LWIP_HDR_TCPIP_H */ ocproxy-1.60/lwip/src/include/lwip/timers.h000066400000000000000000000063321303453231400207610ustar00rootroot00000000000000/* * Copyright (c) 2001-2004 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * Simon Goldschmidt * */ #ifndef LWIP_HDR_TIMERS_H #define LWIP_HDR_TIMERS_H #include "lwip/opt.h" /* Timers are not supported when NO_SYS==1 and NO_SYS_NO_TIMERS==1 */ #define LWIP_TIMERS (!NO_SYS || (NO_SYS && !NO_SYS_NO_TIMERS)) #if LWIP_TIMERS #include "lwip/err.h" #if !NO_SYS #include "lwip/sys.h" #endif #ifdef __cplusplus extern "C" { #endif #ifndef LWIP_DEBUG_TIMERNAMES #ifdef LWIP_DEBUG #define LWIP_DEBUG_TIMERNAMES SYS_DEBUG #else /* LWIP_DEBUG */ #define LWIP_DEBUG_TIMERNAMES 0 #endif /* LWIP_DEBUG*/ #endif /** Function prototype for a timeout callback function. Register such a function * using sys_timeout(). * * @param arg Additional argument to pass to the function - set up by sys_timeout() */ typedef void (* sys_timeout_handler)(void *arg); struct sys_timeo { struct sys_timeo *next; u32_t time; sys_timeout_handler h; void *arg; #if LWIP_DEBUG_TIMERNAMES const char* handler_name; #endif /* LWIP_DEBUG_TIMERNAMES */ }; void sys_timeouts_init(void); #if LWIP_DEBUG_TIMERNAMES void sys_timeout_debug(u32_t msecs, sys_timeout_handler handler, void *arg, const char* handler_name); #define sys_timeout(msecs, handler, arg) sys_timeout_debug(msecs, handler, arg, #handler) #else /* LWIP_DEBUG_TIMERNAMES */ void sys_timeout(u32_t msecs, sys_timeout_handler handler, void *arg); #endif /* LWIP_DEBUG_TIMERNAMES */ void sys_untimeout(sys_timeout_handler handler, void *arg); #if NO_SYS void sys_check_timeouts(void); void sys_restart_timeouts(void); #else /* NO_SYS */ void sys_timeouts_mbox_fetch(sys_mbox_t *mbox, void **msg); #endif /* NO_SYS */ #ifdef __cplusplus } #endif #endif /* LWIP_TIMERS */ #endif /* LWIP_HDR_TIMERS_H */ ocproxy-1.60/lwip/src/include/lwip/udp.h000066400000000000000000000204741303453231400202510ustar00rootroot00000000000000/* * Copyright (c) 2001-2004 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #ifndef LWIP_HDR_UDP_H #define LWIP_HDR_UDP_H #include "lwip/opt.h" #if LWIP_UDP /* don't build if not configured for use in lwipopts.h */ #include "lwip/pbuf.h" #include "lwip/netif.h" #include "lwip/ip_addr.h" #include "lwip/ip.h" #include "lwip/ip6_addr.h" #ifdef __cplusplus extern "C" { #endif #define UDP_HLEN 8 /* Fields are (of course) in network byte order. */ #ifdef PACK_STRUCT_USE_INCLUDES # include "arch/bpstruct.h" #endif PACK_STRUCT_BEGIN struct udp_hdr { PACK_STRUCT_FIELD(u16_t src); PACK_STRUCT_FIELD(u16_t dest); /* src/dest UDP ports */ PACK_STRUCT_FIELD(u16_t len); PACK_STRUCT_FIELD(u16_t chksum); } PACK_STRUCT_STRUCT; PACK_STRUCT_END #ifdef PACK_STRUCT_USE_INCLUDES # include "arch/epstruct.h" #endif #define UDP_FLAGS_NOCHKSUM 0x01U #define UDP_FLAGS_UDPLITE 0x02U #define UDP_FLAGS_CONNECTED 0x04U #define UDP_FLAGS_MULTICAST_LOOP 0x08U struct udp_pcb; /** Function prototype for udp pcb receive callback functions * addr and port are in same byte order as in the pcb * The callback is responsible for freeing the pbuf * if it's not used any more. * * ATTENTION: Be aware that 'addr' points into the pbuf 'p' so freeing this pbuf * makes 'addr' invalid, too. * * @param arg user supplied argument (udp_pcb.recv_arg) * @param pcb the udp_pcb which received data * @param p the packet buffer that was received * @param addr the remote IP address from which the packet was received * @param port the remote port from which the packet was received */ typedef void (*udp_recv_fn)(void *arg, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port); #if LWIP_IPV6 /** Function prototype for udp pcb IPv6 receive callback functions * The callback is responsible for freeing the pbuf * if it's not used any more. * * @param arg user supplied argument (udp_pcb.recv_arg) * @param pcb the udp_pcb which received data * @param p the packet buffer that was received * @param addr the remote IPv6 address from which the packet was received * @param port the remote port from which the packet was received */ typedef void (*udp_recv_ip6_fn)(void *arg, struct udp_pcb *pcb, struct pbuf *p, ip6_addr_t *addr, u16_t port); #endif /* LWIP_IPV6 */ #if LWIP_IPV6 #define UDP_PCB_RECV_IP6 udp_recv_ip6_fn ip6; #else #define UDP_PCB_RECV_IP6 #endif /* LWIP_IPV6 */ struct udp_pcb { /* Common members of all PCB types */ IP_PCB; /* Protocol specific PCB members */ struct udp_pcb *next; u8_t flags; /** ports are in host byte order */ u16_t local_port, remote_port; #if LWIP_IGMP /** outgoing network interface for multicast packets */ ip_addr_t multicast_ip; #endif /* LWIP_IGMP */ #if LWIP_UDPLITE /** used for UDP_LITE only */ u16_t chksum_len_rx, chksum_len_tx; #endif /* LWIP_UDPLITE */ /** receive callback function */ union { udp_recv_fn ip4; UDP_PCB_RECV_IP6 }recv; /** user-supplied argument for the recv callback */ void *recv_arg; }; /* udp_pcbs export for exernal reference (e.g. SNMP agent) */ extern struct udp_pcb *udp_pcbs; /* The following functions is the application layer interface to the UDP code. */ struct udp_pcb * udp_new (void); void udp_remove (struct udp_pcb *pcb); err_t udp_bind (struct udp_pcb *pcb, ip_addr_t *ipaddr, u16_t port); err_t udp_connect (struct udp_pcb *pcb, ip_addr_t *ipaddr, u16_t port); void udp_disconnect (struct udp_pcb *pcb); void udp_recv (struct udp_pcb *pcb, udp_recv_fn recv, void *recv_arg); err_t udp_sendto_if (struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip, u16_t dst_port, struct netif *netif); err_t udp_sendto_if_src(struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip, u16_t dst_port, struct netif *netif, ip_addr_t *src_ip); err_t udp_sendto (struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip, u16_t dst_port); err_t udp_send (struct udp_pcb *pcb, struct pbuf *p); #if LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP err_t udp_sendto_if_chksum(struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip, u16_t dst_port, struct netif *netif, u8_t have_chksum, u16_t chksum); err_t udp_sendto_chksum(struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip, u16_t dst_port, u8_t have_chksum, u16_t chksum); err_t udp_send_chksum(struct udp_pcb *pcb, struct pbuf *p, u8_t have_chksum, u16_t chksum); err_t udp_sendto_if_src_chksum(struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip, u16_t dst_port, struct netif *netif, u8_t have_chksum, u16_t chksum, ip_addr_t *src_ip); #endif /* LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP */ #define udp_flags(pcb) ((pcb)->flags) #define udp_setflags(pcb, f) ((pcb)->flags = (f)) /* The following functions are the lower layer interface to UDP. */ void udp_input (struct pbuf *p, struct netif *inp); void udp_init (void); #if LWIP_IPV6 struct udp_pcb * udp_new_ip6(void); #define udp_bind_ip6(pcb, ip6addr, port) \ udp_bind(pcb, ip6_2_ip(ip6addr), port) #define udp_connect_ip6(pcb, ip6addr, port) \ udp_connect(pcb, ip6_2_ip(ip6addr), port) #define udp_recv_ip6(pcb, recv_ip6_fn, recv_arg) \ udp_recv(pcb, (udp_recv_fn)recv_ip6_fn, recv_arg) #define udp_sendto_ip6(pcb, pbuf, ip6addr, port) \ udp_sendto(pcb, pbuf, ip6_2_ip(ip6addr), port) #define udp_sendto_if_ip6(pcb, pbuf, ip6addr, port, netif) \ udp_sendto_if(pcb, pbuf, ip6_2_ip(ip6addr), port, netif) #if LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP #define udp_sendto_chksum_ip6(pcb, pbuf, ip6addr, port, have_chk, chksum) \ udp_sendto_chksum(pcb, pbuf, ip6_2_ip(ip6addr), port, have_chk, chksum) #define udp_sendto_if_chksum_ip6(pcb, pbuf, ip6addr, port, netif, have_chk, chksum) \ udp_sendto_if_chksum(pcb, pbuf, ip6_2_ip(ip6addr), port, netif, have_chk, chksum) #endif /*LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_UDP */ #endif /* LWIP_IPV6 */ #if UDP_DEBUG void udp_debug_print(struct udp_hdr *udphdr); #else #define udp_debug_print(udphdr) #endif #ifdef __cplusplus } #endif #endif /* LWIP_UDP */ #endif /* LWIP_HDR_UDP_H */ ocproxy-1.60/lwip/src/include/netif/000077500000000000000000000000001303453231400174335ustar00rootroot00000000000000ocproxy-1.60/lwip/src/include/netif/etharp.h000066400000000000000000000172201303453231400210710ustar00rootroot00000000000000/* * Copyright (c) 2001-2003 Swedish Institute of Computer Science. * Copyright (c) 2003-2004 Leon Woestenberg * Copyright (c) 2003-2004 Axon Digital Design B.V., The Netherlands. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #ifndef LWIP_HDR_NETIF_ETHARP_H #define LWIP_HDR_NETIF_ETHARP_H #include "lwip/opt.h" #if LWIP_ARP || LWIP_ETHERNET /* don't build if not configured for use in lwipopts.h */ #include "lwip/pbuf.h" #include "lwip/ip_addr.h" #include "lwip/netif.h" #include "lwip/ip.h" #ifdef __cplusplus extern "C" { #endif #ifndef ETHARP_HWADDR_LEN #define ETHARP_HWADDR_LEN 6 #endif #ifdef PACK_STRUCT_USE_INCLUDES # include "arch/bpstruct.h" #endif PACK_STRUCT_BEGIN struct eth_addr { PACK_STRUCT_FIELD(u8_t addr[ETHARP_HWADDR_LEN]); } PACK_STRUCT_STRUCT; PACK_STRUCT_END #ifdef PACK_STRUCT_USE_INCLUDES # include "arch/epstruct.h" #endif #ifdef PACK_STRUCT_USE_INCLUDES # include "arch/bpstruct.h" #endif PACK_STRUCT_BEGIN /** Ethernet header */ struct eth_hdr { #if ETH_PAD_SIZE PACK_STRUCT_FIELD(u8_t padding[ETH_PAD_SIZE]); #endif PACK_STRUCT_FIELD(struct eth_addr dest); PACK_STRUCT_FIELD(struct eth_addr src); PACK_STRUCT_FIELD(u16_t type); } PACK_STRUCT_STRUCT; PACK_STRUCT_END #ifdef PACK_STRUCT_USE_INCLUDES # include "arch/epstruct.h" #endif #define SIZEOF_ETH_HDR (14 + ETH_PAD_SIZE) #if ETHARP_SUPPORT_VLAN #ifdef PACK_STRUCT_USE_INCLUDES # include "arch/bpstruct.h" #endif PACK_STRUCT_BEGIN /** VLAN header inserted between ethernet header and payload * if 'type' in ethernet header is ETHTYPE_VLAN. * See IEEE802.Q */ struct eth_vlan_hdr { PACK_STRUCT_FIELD(u16_t prio_vid); PACK_STRUCT_FIELD(u16_t tpid); } PACK_STRUCT_STRUCT; PACK_STRUCT_END #ifdef PACK_STRUCT_USE_INCLUDES # include "arch/epstruct.h" #endif #define SIZEOF_VLAN_HDR 4 #define VLAN_ID(vlan_hdr) (htons((vlan_hdr)->prio_vid) & 0xFFF) #endif /* ETHARP_SUPPORT_VLAN */ #ifdef PACK_STRUCT_USE_INCLUDES # include "arch/bpstruct.h" #endif PACK_STRUCT_BEGIN /** the ARP message, see RFC 826 ("Packet format") */ struct etharp_hdr { PACK_STRUCT_FIELD(u16_t hwtype); PACK_STRUCT_FIELD(u16_t proto); PACK_STRUCT_FIELD(u8_t hwlen); PACK_STRUCT_FIELD(u8_t protolen); PACK_STRUCT_FIELD(u16_t opcode); PACK_STRUCT_FIELD(struct eth_addr shwaddr); PACK_STRUCT_FIELD(struct ip_addr2 sipaddr); PACK_STRUCT_FIELD(struct eth_addr dhwaddr); PACK_STRUCT_FIELD(struct ip_addr2 dipaddr); } PACK_STRUCT_STRUCT; PACK_STRUCT_END #ifdef PACK_STRUCT_USE_INCLUDES # include "arch/epstruct.h" #endif #define SIZEOF_ETHARP_HDR 28 #define SIZEOF_ETHARP_PACKET (SIZEOF_ETH_HDR + SIZEOF_ETHARP_HDR) #if ETHARP_SUPPORT_VLAN && defined(LWIP_HOOK_VLAN_SET) #define SIZEOF_ETHARP_PACKET_TX (SIZEOF_ETHARP_PACKET + SIZEOF_VLAN_HDR) #else /* ETHARP_SUPPORT_VLAN && defined(LWIP_HOOK_VLAN_SET) */ #define SIZEOF_ETHARP_PACKET_TX SIZEOF_ETHARP_PACKET #endif /* ETHARP_SUPPORT_VLAN && defined(LWIP_HOOK_VLAN_SET) */ /** 1 seconds period */ #define ARP_TMR_INTERVAL 1000 #define ETHTYPE_ARP 0x0806U #define ETHTYPE_IP 0x0800U #define ETHTYPE_VLAN 0x8100U #define ETHTYPE_IPV6 0x86DDU #define ETHTYPE_PPPOEDISC 0x8863U /* PPP Over Ethernet Discovery Stage */ #define ETHTYPE_PPPOE 0x8864U /* PPP Over Ethernet Session Stage */ /** MEMCPY-like macro to copy to/from struct eth_addr's that are local variables * or known to be 32-bit aligned within the protocol header. */ #ifndef ETHADDR32_COPY #define ETHADDR32_COPY(src, dst) SMEMCPY(src, dst, ETHARP_HWADDR_LEN) #endif /** MEMCPY-like macro to copy to/from struct eth_addr's that are no local * variables and known to be 16-bit aligned within the protocol header. */ #ifndef ETHADDR16_COPY #define ETHADDR16_COPY(src, dst) SMEMCPY(src, dst, ETHARP_HWADDR_LEN) #endif #if LWIP_ARP /* don't build if not configured for use in lwipopts.h */ /** ARP message types (opcodes) */ #define ARP_REQUEST 1 #define ARP_REPLY 2 /** Define this to 1 and define LWIP_ARP_FILTER_NETIF_FN(pbuf, netif, type) * to a filter function that returns the correct netif when using multiple * netifs on one hardware interface where the netif's low-level receive * routine cannot decide for the correct netif (e.g. when mapping multiple * IP addresses to one hardware interface). */ #ifndef LWIP_ARP_FILTER_NETIF #define LWIP_ARP_FILTER_NETIF 0 #endif #if ARP_QUEUEING /** struct for queueing outgoing packets for unknown address * defined here to be accessed by memp.h */ struct etharp_q_entry { struct etharp_q_entry *next; struct pbuf *p; }; #endif /* ARP_QUEUEING */ #define etharp_init() /* Compatibility define, not init needed. */ void etharp_tmr(void); s8_t etharp_find_addr(struct netif *netif, ip_addr_t *ipaddr, struct eth_addr **eth_ret, ip_addr_t **ip_ret); err_t etharp_output(struct netif *netif, struct pbuf *q, ip_addr_t *ipaddr); err_t etharp_query(struct netif *netif, ip_addr_t *ipaddr, struct pbuf *q); err_t etharp_request(struct netif *netif, ip_addr_t *ipaddr); /** For Ethernet network interfaces, we might want to send "gratuitous ARP"; * this is an ARP packet sent by a node in order to spontaneously cause other * nodes to update an entry in their ARP cache. * From RFC 3220 "IP Mobility Support for IPv4" section 4.6. */ #define etharp_gratuitous(netif) etharp_request((netif), &(netif)->ip_addr) void etharp_cleanup_netif(struct netif *netif); #if ETHARP_SUPPORT_STATIC_ENTRIES err_t etharp_add_static_entry(ip_addr_t *ipaddr, struct eth_addr *ethaddr); err_t etharp_remove_static_entry(ip_addr_t *ipaddr); #endif /* ETHARP_SUPPORT_STATIC_ENTRIES */ #if LWIP_AUTOIP err_t etharp_raw(struct netif *netif, const struct eth_addr *ethsrc_addr, const struct eth_addr *ethdst_addr, const struct eth_addr *hwsrc_addr, const ip_addr_t *ipsrc_addr, const struct eth_addr *hwdst_addr, const ip_addr_t *ipdst_addr, const u16_t opcode); #endif /* LWIP_AUTOIP */ #endif /* LWIP_ARP */ err_t ethernet_input(struct pbuf *p, struct netif *netif); #define eth_addr_cmp(addr1, addr2) (memcmp((addr1)->addr, (addr2)->addr, ETHARP_HWADDR_LEN) == 0) extern const struct eth_addr ethbroadcast, ethzero; #endif /* LWIP_ARP || LWIP_ETHERNET */ #ifdef __cplusplus } #endif #endif /* LWIP_HDR_NETIF_ARP_H */ ocproxy-1.60/lwip/src/include/netif/ppp/000077500000000000000000000000001303453231400202325ustar00rootroot00000000000000ocproxy-1.60/lwip/src/include/netif/ppp/ccp.h000066400000000000000000000043221303453231400211510ustar00rootroot00000000000000/* * ccp.h - Definitions for PPP Compression Control Protocol. * * Copyright (c) 1994-2002 Paul Mackerras. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. The name(s) of the authors of this software must not be used to * endorse or promote products derived from this software without * prior written permission. * * 3. Redistributions of any form whatsoever must retain the following * acknowledgment: * "This product includes software developed by Paul Mackerras * ". * * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * $Id: ccp.h,v 1.12 2004/11/04 10:02:26 paulus Exp $ */ #include "lwip/opt.h" #if PPP_SUPPORT && CCP_SUPPORT /* don't build if not configured for use in lwipopts.h */ typedef struct ccp_options { bool bsd_compress; /* do BSD Compress? */ bool deflate; /* do Deflate? */ bool predictor_1; /* do Predictor-1? */ bool predictor_2; /* do Predictor-2? */ bool deflate_correct; /* use correct code for deflate? */ bool deflate_draft; /* use draft RFC code for deflate? */ bool mppe; /* do MPPE? */ u_short bsd_bits; /* # bits/code for BSD Compress */ u_short deflate_size; /* lg(window size) for Deflate */ short method; /* code for chosen compression method */ } ccp_options; extern fsm ccp_fsm[]; extern ccp_options ccp_wantoptions[]; extern ccp_options ccp_gotoptions[]; extern ccp_options ccp_allowoptions[]; extern ccp_options ccp_hisoptions[]; extern const struct protent ccp_protent; #endif /* PPP_SUPPORT && CCP_SUPPORT */ ocproxy-1.60/lwip/src/include/netif/ppp/chap-md5.h000066400000000000000000000026661303453231400220130ustar00rootroot00000000000000/* * chap-md5.h - New CHAP/MD5 implementation. * * Copyright (c) 2003 Paul Mackerras. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. The name(s) of the authors of this software must not be used to * endorse or promote products derived from this software without * prior written permission. * * 3. Redistributions of any form whatsoever must retain the following * acknowledgment: * "This product includes software developed by Paul Mackerras * ". * * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "lwip/opt.h" #if PPP_SUPPORT && CHAP_SUPPORT /* don't build if not configured for use in lwipopts.h */ extern const struct chap_digest_type md5_digest; #endif /* PPP_SUPPORT && CHAP_SUPPORT */ ocproxy-1.60/lwip/src/include/netif/ppp/chap-new.h000066400000000000000000000135461303453231400221160ustar00rootroot00000000000000/* * chap-new.c - New CHAP implementation. * * Copyright (c) 2003 Paul Mackerras. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. The name(s) of the authors of this software must not be used to * endorse or promote products derived from this software without * prior written permission. * * 3. Redistributions of any form whatsoever must retain the following * acknowledgment: * "This product includes software developed by Paul Mackerras * ". * * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "lwip/opt.h" #if PPP_SUPPORT && CHAP_SUPPORT /* don't build if not configured for use in lwipopts.h */ #ifndef CHAP_H #define CHAP_H #include "ppp.h" /* * CHAP packets begin with a standard header with code, id, len (2 bytes). */ #define CHAP_HDRLEN 4 /* * Values for the code field. */ #define CHAP_CHALLENGE 1 #define CHAP_RESPONSE 2 #define CHAP_SUCCESS 3 #define CHAP_FAILURE 4 /* * CHAP digest codes. */ #define CHAP_MD5 5 #if MSCHAP_SUPPORT #define CHAP_MICROSOFT 0x80 #define CHAP_MICROSOFT_V2 0x81 #endif /* MSCHAP_SUPPORT */ /* * Semi-arbitrary limits on challenge and response fields. */ #define MAX_CHALLENGE_LEN 64 #define MAX_RESPONSE_LEN 64 /* * These limits apply to challenge and response packets we send. * The +4 is the +1 that we actually need rounded up. */ #define CHAL_MAX_PKTLEN (PPP_HDRLEN + CHAP_HDRLEN + 4 + MAX_CHALLENGE_LEN + MAXNAMELEN) #define RESP_MAX_PKTLEN (PPP_HDRLEN + CHAP_HDRLEN + 4 + MAX_RESPONSE_LEN + MAXNAMELEN) /* bitmask of supported algorithms */ #if MSCHAP_SUPPORT #define MDTYPE_MICROSOFT_V2 0x1 #define MDTYPE_MICROSOFT 0x2 #endif /* MSCHAP_SUPPORT */ #define MDTYPE_MD5 0x4 #define MDTYPE_NONE 0 #if MSCHAP_SUPPORT /* Return the digest alg. ID for the most preferred digest type. */ #define CHAP_DIGEST(mdtype) \ ((mdtype) & MDTYPE_MD5)? CHAP_MD5: \ ((mdtype) & MDTYPE_MICROSOFT_V2)? CHAP_MICROSOFT_V2: \ ((mdtype) & MDTYPE_MICROSOFT)? CHAP_MICROSOFT: \ 0 #else /* !MSCHAP_SUPPORT */ #define CHAP_DIGEST(mdtype) \ ((mdtype) & MDTYPE_MD5)? CHAP_MD5: \ 0 #endif /* MSCHAP_SUPPORT */ /* Return the bit flag (lsb set) for our most preferred digest type. */ #define CHAP_MDTYPE(mdtype) ((mdtype) ^ ((mdtype) - 1)) & (mdtype) /* Return the bit flag for a given digest algorithm ID. */ #if MSCHAP_SUPPORT #define CHAP_MDTYPE_D(digest) \ ((digest) == CHAP_MICROSOFT_V2)? MDTYPE_MICROSOFT_V2: \ ((digest) == CHAP_MICROSOFT)? MDTYPE_MICROSOFT: \ ((digest) == CHAP_MD5)? MDTYPE_MD5: \ 0 #else /* !MSCHAP_SUPPORT */ #define CHAP_MDTYPE_D(digest) \ ((digest) == CHAP_MD5)? MDTYPE_MD5: \ 0 #endif /* MSCHAP_SUPPORT */ /* Can we do the requested digest? */ #if MSCHAP_SUPPORT #define CHAP_CANDIGEST(mdtype, digest) \ ((digest) == CHAP_MICROSOFT_V2)? (mdtype) & MDTYPE_MICROSOFT_V2: \ ((digest) == CHAP_MICROSOFT)? (mdtype) & MDTYPE_MICROSOFT: \ ((digest) == CHAP_MD5)? (mdtype) & MDTYPE_MD5: \ 0 #else /* !MSCHAP_SUPPORT */ #define CHAP_CANDIGEST(mdtype, digest) \ ((digest) == CHAP_MD5)? (mdtype) & MDTYPE_MD5: \ 0 #endif /* MSCHAP_SUPPORT */ /* * The code for each digest type has to supply one of these. */ struct chap_digest_type { int code; #if PPP_SERVER /* * Note: challenge and response arguments below are formatted as * a length byte followed by the actual challenge/response data. */ void (*generate_challenge)(unsigned char *challenge); int (*verify_response)(int id, char *name, unsigned char *secret, int secret_len, unsigned char *challenge, unsigned char *response, char *message, int message_space); #endif /* PPP_SERVER */ void (*make_response)(unsigned char *response, int id, char *our_name, unsigned char *challenge, char *secret, int secret_len, unsigned char *priv); int (*check_success)(unsigned char *pkt, int len, unsigned char *priv); void (*handle_failure)(unsigned char *pkt, int len); }; /* * Each interface is described by chap structure. */ #if CHAP_SUPPORT typedef struct chap_client_state { u8_t flags; char *name; const struct chap_digest_type *digest; unsigned char priv[64]; /* private area for digest's use */ } chap_client_state; #if PPP_SERVER typedef struct chap_server_state { u8_t flags; int id; char *name; const struct chap_digest_type *digest; int challenge_xmits; int challenge_pktlen; unsigned char challenge[CHAL_MAX_PKTLEN]; char message[256]; } chap_server_state; #endif /* PPP_SERVER */ #endif /* CHAP_SUPPORT */ #if 0 /* UNUSED */ /* Hook for a plugin to validate CHAP challenge */ extern int (*chap_verify_hook)(char *name, char *ourname, int id, const struct chap_digest_type *digest, unsigned char *challenge, unsigned char *response, char *message, int message_space); #endif /* UNUSED */ #if PPP_SERVER /* Called by authentication code to start authenticating the peer. */ extern void chap_auth_peer(ppp_pcb *pcb, char *our_name, int digest_code); #endif /* PPP_SERVER */ /* Called by auth. code to start authenticating us to the peer. */ extern void chap_auth_with_peer(ppp_pcb *pcb, char *our_name, int digest_code); /* Represents the CHAP protocol to the main pppd code */ extern const struct protent chap_protent; #endif /* CHAP_H */ #endif /* PPP_SUPPORT && CHAP_SUPPORT */ ocproxy-1.60/lwip/src/include/netif/ppp/chap_ms.h000066400000000000000000000100401303453231400220100ustar00rootroot00000000000000/* * chap_ms.h - Challenge Handshake Authentication Protocol definitions. * * Copyright (c) 1995 Eric Rosenquist. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The name(s) of the authors of this software must not be used to * endorse or promote products derived from this software without * prior written permission. * * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * $Id: chap_ms.h,v 1.13 2004/11/15 22:13:26 paulus Exp $ */ #include "lwip/opt.h" #if PPP_SUPPORT && MSCHAP_SUPPORT /* don't build if not configured for use in lwipopts.h */ #ifndef __CHAPMS_INCLUDE__ #define MD4_SIGNATURE_SIZE 16 /* 16 bytes in a MD4 message digest */ #define MAX_NT_PASSWORD 256 /* Max (Unicode) chars in an NT pass */ #define MS_CHAP_RESPONSE_LEN 49 /* Response length for MS-CHAP */ #define MS_CHAP2_RESPONSE_LEN 49 /* Response length for MS-CHAPv2 */ #define MS_AUTH_RESPONSE_LENGTH 40 /* MS-CHAPv2 authenticator response, */ /* as ASCII */ /* Error codes for MS-CHAP failure messages. */ #define MS_CHAP_ERROR_RESTRICTED_LOGON_HOURS 646 #define MS_CHAP_ERROR_ACCT_DISABLED 647 #define MS_CHAP_ERROR_PASSWD_EXPIRED 648 #define MS_CHAP_ERROR_NO_DIALIN_PERMISSION 649 #define MS_CHAP_ERROR_AUTHENTICATION_FAILURE 691 #define MS_CHAP_ERROR_CHANGING_PASSWORD 709 /* * Offsets within the response field for MS-CHAP */ #define MS_CHAP_LANMANRESP 0 #define MS_CHAP_LANMANRESP_LEN 24 #define MS_CHAP_NTRESP 24 #define MS_CHAP_NTRESP_LEN 24 #define MS_CHAP_USENT 48 /* * Offsets within the response field for MS-CHAP2 */ #define MS_CHAP2_PEER_CHALLENGE 0 #define MS_CHAP2_PEER_CHAL_LEN 16 #define MS_CHAP2_RESERVED_LEN 8 #define MS_CHAP2_NTRESP 24 #define MS_CHAP2_NTRESP_LEN 24 #define MS_CHAP2_FLAGS 48 #ifdef MPPE #include "mppe.h" /* MPPE_MAX_KEY_LEN */ extern u_char mppe_send_key[MPPE_MAX_KEY_LEN]; extern u_char mppe_recv_key[MPPE_MAX_KEY_LEN]; extern int mppe_keys_set; /* These values are the RADIUS attribute values--see RFC 2548. */ #define MPPE_ENC_POL_ENC_ALLOWED 1 #define MPPE_ENC_POL_ENC_REQUIRED 2 #define MPPE_ENC_TYPES_RC4_40 2 #define MPPE_ENC_TYPES_RC4_128 4 /* used by plugins (using above values) */ extern void set_mppe_enc_types(int, int); #endif /* Are we the authenticator or authenticatee? For MS-CHAPv2 key derivation. */ #define MS_CHAP2_AUTHENTICATEE 0 #define MS_CHAP2_AUTHENTICATOR 1 void ChapMS (u_char *, char *, int, u_char *); void ChapMS2 (u_char *, u_char *, char *, char *, int, u_char *, u_char[MS_AUTH_RESPONSE_LENGTH+1], int); #ifdef MPPE void mppe_set_keys (u_char *, u_char[MD4_SIGNATURE_SIZE]); void mppe_set_keys2(u_char PasswordHashHash[MD4_SIGNATURE_SIZE], u_char NTResponse[24], int IsServer); #endif void ChallengeHash (u_char[16], u_char *, char *, u_char[8]); void GenerateAuthenticatorResponse(u_char PasswordHashHash[MD4_SIGNATURE_SIZE], u_char NTResponse[24], u_char PeerChallenge[16], u_char *rchallenge, char *username, u_char authResponse[MS_AUTH_RESPONSE_LENGTH+1]); extern const struct chap_digest_type chapms_digest; extern const struct chap_digest_type chapms2_digest; #define __CHAPMS_INCLUDE__ #endif /* __CHAPMS_INCLUDE__ */ #endif /* PPP_SUPPORT && MSCHAP_SUPPORT */ ocproxy-1.60/lwip/src/include/netif/ppp/eap.h000066400000000000000000000124751303453231400211610ustar00rootroot00000000000000/* * eap.h - Extensible Authentication Protocol for PPP (RFC 2284) * * Copyright (c) 2001 by Sun Microsystems, Inc. * All rights reserved. * * Non-exclusive rights to redistribute, modify, translate, and use * this software in source and binary forms, in whole or in part, is * hereby granted, provided that the above copyright notice is * duplicated in any source form, and that neither the name of the * copyright holder nor the author is used to endorse or promote * products derived from this software. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. * * Original version by James Carlson * * $Id: eap.h,v 1.2 2003/06/11 23:56:26 paulus Exp $ */ #include "lwip/opt.h" #if PPP_SUPPORT && EAP_SUPPORT /* don't build if not configured for use in lwipopts.h */ #ifndef PPP_EAP_H #define PPP_EAP_H #include "ppp.h" #ifdef __cplusplus extern "C" { #endif /* * Packet header = Code, id, length. */ #define EAP_HEADERLEN 4 /* EAP message codes. */ #define EAP_REQUEST 1 #define EAP_RESPONSE 2 #define EAP_SUCCESS 3 #define EAP_FAILURE 4 /* EAP types */ #define EAPT_IDENTITY 1 #define EAPT_NOTIFICATION 2 #define EAPT_NAK 3 /* (response only) */ #define EAPT_MD5CHAP 4 #define EAPT_OTP 5 /* One-Time Password; RFC 1938 */ #define EAPT_TOKEN 6 /* Generic Token Card */ /* 7 and 8 are unassigned. */ #define EAPT_RSA 9 /* RSA Public Key Authentication */ #define EAPT_DSS 10 /* DSS Unilateral */ #define EAPT_KEA 11 /* KEA */ #define EAPT_KEA_VALIDATE 12 /* KEA-VALIDATE */ #define EAPT_TLS 13 /* EAP-TLS */ #define EAPT_DEFENDER 14 /* Defender Token (AXENT) */ #define EAPT_W2K 15 /* Windows 2000 EAP */ #define EAPT_ARCOT 16 /* Arcot Systems */ #define EAPT_CISCOWIRELESS 17 /* Cisco Wireless */ #define EAPT_NOKIACARD 18 /* Nokia IP smart card */ #define EAPT_SRP 19 /* Secure Remote Password */ /* 20 is deprecated */ /* EAP SRP-SHA1 Subtypes */ #define EAPSRP_CHALLENGE 1 /* Request 1 - Challenge */ #define EAPSRP_CKEY 1 /* Response 1 - Client Key */ #define EAPSRP_SKEY 2 /* Request 2 - Server Key */ #define EAPSRP_CVALIDATOR 2 /* Response 2 - Client Validator */ #define EAPSRP_SVALIDATOR 3 /* Request 3 - Server Validator */ #define EAPSRP_ACK 3 /* Response 3 - final ack */ #define EAPSRP_LWRECHALLENGE 4 /* Req/resp 4 - Lightweight rechal */ #define SRPVAL_EBIT 0x00000001 /* Use shared key for ECP */ #define SRP_PSEUDO_ID "pseudo_" #define SRP_PSEUDO_LEN 7 #define MD5_SIGNATURE_SIZE 16 #define EAP_MIN_CHALLENGE_LENGTH 16 #define EAP_MAX_CHALLENGE_LENGTH 24 #define EAP_STATES \ "Initial", "Pending", "Closed", "Listen", "Identify", \ "SRP1", "SRP2", "SRP3", "MD5Chall", "Open", "SRP4", "BadAuth" #define eap_client_active(pcb) ((pcb)->eap.es_client.ea_state == eapListen) #if PPP_SERVER #define eap_server_active(pcb) \ ((pcb)->eap.es_server.ea_state >= eapIdentify && \ (pcb)->eap.es_server.ea_state <= eapMD5Chall) #endif /* PPP_SERVER */ /* * Complete EAP state for one PPP session. */ enum eap_state_code { eapInitial = 0, /* No EAP authentication yet requested */ eapPending, /* Waiting for LCP (no timer) */ eapClosed, /* Authentication not in use */ eapListen, /* Client ready (and timer running) */ eapIdentify, /* EAP Identify sent */ eapSRP1, /* Sent EAP SRP-SHA1 Subtype 1 */ eapSRP2, /* Sent EAP SRP-SHA1 Subtype 2 */ eapSRP3, /* Sent EAP SRP-SHA1 Subtype 3 */ eapMD5Chall, /* Sent MD5-Challenge */ eapOpen, /* Completed authentication */ eapSRP4, /* Sent EAP SRP-SHA1 Subtype 4 */ eapBadAuth /* Failed authentication */ }; struct eap_auth { char *ea_name; /* Our name */ char *ea_peer; /* Peer's name */ void *ea_session; /* Authentication library linkage */ u_char *ea_skey; /* Shared encryption key */ u_short ea_namelen; /* Length of our name */ u_short ea_peerlen; /* Length of peer's name */ enum eap_state_code ea_state; u_char ea_id; /* Current id */ u_char ea_requests; /* Number of Requests sent/received */ u_char ea_responses; /* Number of Responses */ u_char ea_type; /* One of EAPT_* */ u32_t ea_keyflags; /* SRP shared key usage flags */ }; #ifndef EAP_MAX_CHALLENGE_LENGTH #define EAP_MAX_CHALLENGE_LENGTH 24 #endif typedef struct eap_state { struct eap_auth es_client; /* Client (authenticatee) data */ #if PPP_SERVER struct eap_auth es_server; /* Server (authenticator) data */ #endif /* PPP_SERVER */ int es_savedtime; /* Saved timeout */ int es_rechallenge; /* EAP rechallenge interval */ int es_lwrechallenge; /* SRP lightweight rechallenge inter */ u8_t es_usepseudo; /* Use SRP Pseudonym if offered one */ int es_usedpseudo; /* Set if we already sent PN */ int es_challen; /* Length of challenge string */ u_char es_challenge[EAP_MAX_CHALLENGE_LENGTH]; } eap_state; /* * Timeouts. */ #if 0 /* moved to opt.h */ #define EAP_DEFTIMEOUT 3 /* Timeout (seconds) for rexmit */ #define EAP_DEFTRANSMITS 10 /* max # times to transmit */ #define EAP_DEFREQTIME 20 /* Time to wait for peer request */ #define EAP_DEFALLOWREQ 20 /* max # times to accept requests */ #endif /* moved to opt.h */ void eap_authwithpeer(ppp_pcb *pcb, char *localname); void eap_authpeer(ppp_pcb *pcb, char *localname); extern const struct protent eap_protent; #ifdef __cplusplus } #endif #endif /* PPP_EAP_H */ #endif /* PPP_SUPPORT && EAP_SUPPORT */ ocproxy-1.60/lwip/src/include/netif/ppp/ecp.h000066400000000000000000000035171303453231400211600ustar00rootroot00000000000000/* * ecp.h - Definitions for PPP Encryption Control Protocol. * * Copyright (c) 2002 Google, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The name(s) of the authors of this software must not be used to * endorse or promote products derived from this software without * prior written permission. * * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * $Id: ecp.h,v 1.2 2003/01/10 07:12:36 fcusack Exp $ */ #include "lwip/opt.h" #if PPP_SUPPORT && ECP_SUPPORT /* don't build if not configured for use in lwipopts.h */ typedef struct ecp_options { bool required; /* Is ECP required? */ unsigned enctype; /* Encryption type */ } ecp_options; extern fsm ecp_fsm[]; extern ecp_options ecp_wantoptions[]; extern ecp_options ecp_gotoptions[]; extern ecp_options ecp_allowoptions[]; extern ecp_options ecp_hisoptions[]; extern const struct protent ecp_protent; #endif /* PPP_SUPPORT && ECP_SUPPORT */ ocproxy-1.60/lwip/src/include/netif/ppp/eui64.h000066400000000000000000000056431303453231400213470ustar00rootroot00000000000000/* * eui64.h - EUI64 routines for IPv6CP. * * Copyright (c) 1999 Tommi Komulainen. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The name(s) of the authors of this software must not be used to * endorse or promote products derived from this software without * prior written permission. * * 4. Redistributions of any form whatsoever must retain the following * acknowledgment: * "This product includes software developed by Tommi Komulainen * ". * * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * $Id: eui64.h,v 1.6 2002/12/04 23:03:32 paulus Exp $ */ #include "lwip/opt.h" #if PPP_SUPPORT && PPP_IPV6_SUPPORT /* don't build if not configured for use in lwipopts.h */ #ifndef __EUI64_H__ #define __EUI64_H__ /* * TODO: * * Maybe this should be done by processing struct in6_addr directly... */ typedef union { u8_t e8[8]; u16_t e16[4]; u32_t e32[2]; } eui64_t; #define eui64_iszero(e) (((e).e32[0] | (e).e32[1]) == 0) #define eui64_equals(e, o) (((e).e32[0] == (o).e32[0]) && \ ((e).e32[1] == (o).e32[1])) #define eui64_zero(e) (e).e32[0] = (e).e32[1] = 0; #define eui64_copy(s, d) memcpy(&(d), &(s), sizeof(eui64_t)) #define eui64_magic(e) do { \ (e).e32[0] = magic(); \ (e).e32[1] = magic(); \ (e).e8[0] &= ~2; \ } while (0) #define eui64_magic_nz(x) do { \ eui64_magic(x); \ } while (eui64_iszero(x)) #define eui64_magic_ne(x, y) do { \ eui64_magic(x); \ } while (eui64_equals(x, y)) #define eui64_get(ll, cp) do { \ eui64_copy((*cp), (ll)); \ (cp) += sizeof(eui64_t); \ } while (0) #define eui64_put(ll, cp) do { \ eui64_copy((ll), (*cp)); \ (cp) += sizeof(eui64_t); \ } while (0) #define eui64_set32(e, l) do { \ (e).e32[0] = 0; \ (e).e32[1] = htonl(l); \ } while (0) #define eui64_setlo32(e, l) eui64_set32(e, l) char *eui64_ntoa(eui64_t); /* Returns ascii representation of id */ #endif /* __EUI64_H__ */ #endif /* PPP_SUPPORT && PPP_IPV6_SUPPORT */ ocproxy-1.60/lwip/src/include/netif/ppp/fsm.h000066400000000000000000000142031303453231400211700ustar00rootroot00000000000000/* * fsm.h - {Link, IP} Control Protocol Finite State Machine definitions. * * Copyright (c) 1984-2000 Carnegie Mellon University. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The name "Carnegie Mellon University" must not be used to * endorse or promote products derived from this software without * prior written permission. For permission or any legal * details, please contact * Office of Technology Transfer * Carnegie Mellon University * 5000 Forbes Avenue * Pittsburgh, PA 15213-3890 * (412) 268-4387, fax: (412) 268-7395 * tech-transfer@andrew.cmu.edu * * 4. Redistributions of any form whatsoever must retain the following * acknowledgment: * "This product includes software developed by Computing Services * at Carnegie Mellon University (http://www.cmu.edu/computing/)." * * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * $Id: fsm.h,v 1.10 2004/11/13 02:28:15 paulus Exp $ */ #include "lwip/opt.h" #if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */ #ifndef FSM_H #define FSM_H #include "ppp.h" /* * Packet header = Code, id, length. */ #define HEADERLEN 4 /* * CP (LCP, IPCP, etc.) codes. */ #define CONFREQ 1 /* Configuration Request */ #define CONFACK 2 /* Configuration Ack */ #define CONFNAK 3 /* Configuration Nak */ #define CONFREJ 4 /* Configuration Reject */ #define TERMREQ 5 /* Termination Request */ #define TERMACK 6 /* Termination Ack */ #define CODEREJ 7 /* Code Reject */ /* * Each FSM is described by an fsm structure and fsm callbacks. */ typedef struct fsm { ppp_pcb *pcb; /* PPP Interface */ const struct fsm_callbacks *callbacks; /* Callback routines */ char *term_reason; /* Reason for closing protocol */ u8_t seen_ack; /* Have received valid Ack/Nak/Rej to Req */ /* -- This is our only flag, we might use u_int :1 if we have more flags */ u16_t protocol; /* Data Link Layer Protocol field value */ u8_t state; /* State */ u8_t flags; /* Contains option bits */ u8_t id; /* Current id */ u8_t reqid; /* Current request id */ u8_t retransmits; /* Number of retransmissions left */ u8_t nakloops; /* Number of nak loops since last ack */ u8_t rnakloops; /* Number of naks received */ u8_t maxnakloops; /* Maximum number of nak loops tolerated (necessary because IPCP require a custom large max nak loops value) */ u8_t term_reason_len; /* Length of term_reason */ } fsm; typedef struct fsm_callbacks { void (*resetci) /* Reset our Configuration Information */ (fsm *); int (*cilen) /* Length of our Configuration Information */ (fsm *); void (*addci) /* Add our Configuration Information */ (fsm *, u_char *, int *); int (*ackci) /* ACK our Configuration Information */ (fsm *, u_char *, int); int (*nakci) /* NAK our Configuration Information */ (fsm *, u_char *, int, int); int (*rejci) /* Reject our Configuration Information */ (fsm *, u_char *, int); int (*reqci) /* Request peer's Configuration Information */ (fsm *, u_char *, int *, int); void (*up) /* Called when fsm reaches PPP_FSM_OPENED state */ (fsm *); void (*down) /* Called when fsm leaves PPP_FSM_OPENED state */ (fsm *); void (*starting) /* Called when we want the lower layer */ (fsm *); void (*finished) /* Called when we don't want the lower layer */ (fsm *); void (*protreject) /* Called when Protocol-Reject received */ (int); void (*retransmit) /* Retransmission is necessary */ (fsm *); int (*extcode) /* Called when unknown code received */ (fsm *, int, int, u_char *, int); char *proto_name; /* String name for protocol (for messages) */ } fsm_callbacks; /* * Link states. */ #define PPP_FSM_INITIAL 0 /* Down, hasn't been opened */ #define PPP_FSM_STARTING 1 /* Down, been opened */ #define PPP_FSM_CLOSED 2 /* Up, hasn't been opened */ #define PPP_FSM_STOPPED 3 /* Open, waiting for down event */ #define PPP_FSM_CLOSING 4 /* Terminating the connection, not open */ #define PPP_FSM_STOPPING 5 /* Terminating, but open */ #define PPP_FSM_REQSENT 6 /* We've sent a Config Request */ #define PPP_FSM_ACKRCVD 7 /* We've received a Config Ack */ #define PPP_FSM_ACKSENT 8 /* We've sent a Config Ack */ #define PPP_FSM_OPENED 9 /* Connection available */ /* * Flags - indicate options controlling FSM operation */ #define OPT_PASSIVE 1 /* Don't die if we don't get a response */ #define OPT_RESTART 2 /* Treat 2nd OPEN as DOWN, UP */ #define OPT_SILENT 4 /* Wait for peer to speak first */ /* * Timeouts. */ #if 0 /* moved to opt.h */ #define DEFTIMEOUT 3 /* Timeout time in seconds */ #define DEFMAXTERMREQS 2 /* Maximum Terminate-Request transmissions */ #define DEFMAXCONFREQS 10 /* Maximum Configure-Request transmissions */ #define DEFMAXNAKLOOPS 5 /* Maximum number of nak loops */ #endif /* moved to opt.h */ /* * Prototypes */ void fsm_init(fsm *f); void fsm_lowerup(fsm *f); void fsm_lowerdown(fsm *f); void fsm_open(fsm *f); void fsm_close(fsm *f, char *reason); void fsm_input(fsm *f, u_char *inpacket, int l); void fsm_protreject(fsm *f); void fsm_sdata(fsm *f, u_char code, u_char id, u_char *data, int datalen); #endif /* FSM_H */ #endif /* PPP_SUPPORT */ ocproxy-1.60/lwip/src/include/netif/ppp/ipcp.h000066400000000000000000000107671303453231400213510ustar00rootroot00000000000000/* * ipcp.h - IP Control Protocol definitions. * * Copyright (c) 1984-2000 Carnegie Mellon University. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The name "Carnegie Mellon University" must not be used to * endorse or promote products derived from this software without * prior written permission. For permission or any legal * details, please contact * Office of Technology Transfer * Carnegie Mellon University * 5000 Forbes Avenue * Pittsburgh, PA 15213-3890 * (412) 268-4387, fax: (412) 268-7395 * tech-transfer@andrew.cmu.edu * * 4. Redistributions of any form whatsoever must retain the following * acknowledgment: * "This product includes software developed by Computing Services * at Carnegie Mellon University (http://www.cmu.edu/computing/)." * * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * $Id: ipcp.h,v 1.14 2002/12/04 23:03:32 paulus Exp $ */ #include "lwip/opt.h" #if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */ #ifndef IPCP_H #define IPCP_H /* * Options. */ #define CI_ADDRS 1 /* IP Addresses */ #define CI_COMPRESSTYPE 2 /* Compression Type */ #define CI_ADDR 3 #define CI_MS_DNS1 129 /* Primary DNS value */ #define CI_MS_WINS1 130 /* Primary WINS value */ #define CI_MS_DNS2 131 /* Secondary DNS value */ #define CI_MS_WINS2 132 /* Secondary WINS value */ #define MAX_STATES 16 /* from slcompress.h */ #define IPCP_VJMODE_OLD 1 /* "old" mode (option # = 0x0037) */ #define IPCP_VJMODE_RFC1172 2 /* "old-rfc"mode (option # = 0x002d) */ #define IPCP_VJMODE_RFC1332 3 /* "new-rfc"mode (option # = 0x002d, */ /* maxslot and slot number compression) */ #define IPCP_VJ_COMP 0x002d /* current value for VJ compression option*/ #define IPCP_VJ_COMP_OLD 0x0037 /* "old" (i.e, broken) value for VJ */ /* compression option*/ typedef struct ipcp_options { unsigned int neg_addr :1; /* Negotiate IP Address? */ unsigned int old_addrs :1; /* Use old (IP-Addresses) option? */ unsigned int req_addr :1; /* Ask peer to send IP address? */ #if 0 /* UNUSED */ unsigned int default_route :1; /* Assign default route through interface? */ unsigned int replace_default_route :1; /* Replace default route through interface? */ #endif /* UNUSED */ unsigned int proxy_arp :1; /* Make proxy ARP entry for peer? */ unsigned int neg_vj :1; /* Van Jacobson Compression? */ unsigned int old_vj :1; /* use old (short) form of VJ option? */ unsigned int accept_local :1; /* accept peer's value for ouraddr */ unsigned int accept_remote :1; /* accept peer's value for hisaddr */ unsigned int req_dns1 :1; /* Ask peer to send primary DNS address? */ unsigned int req_dns2 :1; /* Ask peer to send secondary DNS address? */ unsigned int cflag :1; unsigned int :5; /* 3 bits of padding to round out to 16 bits */ u32_t ouraddr, hisaddr; /* Addresses in NETWORK BYTE ORDER */ u32_t dnsaddr[2]; /* Primary and secondary MS DNS entries */ u32_t winsaddr[2]; /* Primary and secondary MS WINS entries */ u16_t vj_protocol; /* protocol value to use in VJ option */ u8_t maxslotindex; /* values for RFC1332 VJ compression neg. */ } ipcp_options; #if 0 /* UNUSED, already defined by lwIP */ char *ip_ntoa (u32_t); #endif /* UNUSED, already defined by lwIP */ extern const struct protent ipcp_protent; #endif /* IPCP_H */ #endif /* PPP_SUPPORT */ ocproxy-1.60/lwip/src/include/netif/ppp/ipv6cp.h000066400000000000000000000166051303453231400216220ustar00rootroot00000000000000/* * ipv6cp.h - PPP IPV6 Control Protocol. * * Copyright (c) 1999 Tommi Komulainen. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The name(s) of the authors of this software must not be used to * endorse or promote products derived from this software without * prior written permission. * * 4. Redistributions of any form whatsoever must retain the following * acknowledgment: * "This product includes software developed by Tommi Komulainen * ". * * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * */ /* Original version, based on RFC2023 : Copyright (c) 1995, 1996, 1997 Francis.Dupont@inria.fr, INRIA Rocquencourt, Alain.Durand@imag.fr, IMAG, Jean-Luc.Richier@imag.fr, IMAG-LSR. Copyright (c) 1998, 1999 Francis.Dupont@inria.fr, GIE DYADE, Alain.Durand@imag.fr, IMAG, Jean-Luc.Richier@imag.fr, IMAG-LSR. Ce travail a été fait au sein du GIE DYADE (Groupement d'Intérêt Économique ayant pour membres BULL S.A. et l'INRIA). Ce logiciel informatique est disponible aux conditions usuelles dans la recherche, c'est-à-dire qu'il peut être utilisé, copié, modifié, distribué à l'unique condition que ce texte soit conservé afin que l'origine de ce logiciel soit reconnue. Le nom de l'Institut National de Recherche en Informatique et en Automatique (INRIA), de l'IMAG, ou d'une personne morale ou physique ayant participé à l'élaboration de ce logiciel ne peut être utilisé sans son accord préalable explicite. Ce logiciel est fourni tel quel sans aucune garantie, support ou responsabilité d'aucune sorte. Ce logiciel est dérivé de sources d'origine "University of California at Berkeley" et "Digital Equipment Corporation" couvertes par des copyrights. L'Institut d'Informatique et de Mathématiques Appliquées de Grenoble (IMAG) est une fédération d'unités mixtes de recherche du CNRS, de l'Institut National Polytechnique de Grenoble et de l'Université Joseph Fourier regroupant sept laboratoires dont le laboratoire Logiciels, Systèmes, Réseaux (LSR). This work has been done in the context of GIE DYADE (joint R & D venture between BULL S.A. and INRIA). This software is available with usual "research" terms with the aim of retain credits of the software. Permission to use, copy, modify and distribute this software for any purpose and without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies, and the name of INRIA, IMAG, or any contributor not be used in advertising or publicity pertaining to this material without the prior explicit permission. The software is provided "as is" without any warranties, support or liabilities of any kind. This software is derived from source code from "University of California at Berkeley" and "Digital Equipment Corporation" protected by copyrights. Grenoble's Institute of Computer Science and Applied Mathematics (IMAG) is a federation of seven research units funded by the CNRS, National Polytechnic Institute of Grenoble and University Joseph Fourier. The research unit in Software, Systems, Networks (LSR) is member of IMAG. */ /* * Derived from : * * * ipcp.h - IP Control Protocol definitions. * * Copyright (c) 1984-2000 Carnegie Mellon University. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The name "Carnegie Mellon University" must not be used to * endorse or promote products derived from this software without * prior written permission. For permission or any legal * details, please contact * Office of Technology Transfer * Carnegie Mellon University * 5000 Forbes Avenue * Pittsburgh, PA 15213-3890 * (412) 268-4387, fax: (412) 268-7395 * tech-transfer@andrew.cmu.edu * * 4. Redistributions of any form whatsoever must retain the following * acknowledgment: * "This product includes software developed by Computing Services * at Carnegie Mellon University (http://www.cmu.edu/computing/)." * * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * $Id: ipv6cp.h,v 1.7 2002/12/04 23:03:32 paulus Exp $ */ #include "lwip/opt.h" #if PPP_SUPPORT && PPP_IPV6_SUPPORT /* don't build if not configured for use in lwipopts.h */ #ifndef IPV6CP_H #define IPV6CP_H #include "eui64.h" /* * Options. */ #define CI_IFACEID 1 /* Interface Identifier */ #define CI_COMPRESSTYPE 2 /* Compression Type */ /* No compression types yet defined. *#define IPV6CP_COMP 0x004f */ typedef struct ipv6cp_options { unsigned int neg_ifaceid :1; /* Negotiate interface identifier? */ unsigned int req_ifaceid :1; /* Ask peer to send interface identifier? */ unsigned int accept_local :1; /* accept peer's value for iface id? */ unsigned int opt_local :1; /* ourtoken set by option */ unsigned int opt_remote :1; /* histoken set by option */ unsigned int use_ip :1; /* use IP as interface identifier */ #if 0 #if defined(SOL2) || defined(__linux__) unsigned int use_persistent :1; /* use uniquely persistent value for address */ #endif /* defined(SOL2) */ #endif unsigned int neg_vj :1; /* Van Jacobson Compression? */ unsigned int :1; /* 1 bit of padding to round out to 8 bits */ u_short vj_protocol; /* protocol value to use in VJ option */ eui64_t ourid, hisid; /* Interface identifiers */ } ipv6cp_options; extern const struct protent ipv6cp_protent; #endif /* IPV6CP_H */ #endif /* PPP_SUPPORT && PPP_IPV6_SUPPORT */ ocproxy-1.60/lwip/src/include/netif/ppp/lcp.h000066400000000000000000000154461303453231400211730ustar00rootroot00000000000000/* * lcp.h - Link Control Protocol definitions. * * Copyright (c) 1984-2000 Carnegie Mellon University. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The name "Carnegie Mellon University" must not be used to * endorse or promote products derived from this software without * prior written permission. For permission or any legal * details, please contact * Office of Technology Transfer * Carnegie Mellon University * 5000 Forbes Avenue * Pittsburgh, PA 15213-3890 * (412) 268-4387, fax: (412) 268-7395 * tech-transfer@andrew.cmu.edu * * 4. Redistributions of any form whatsoever must retain the following * acknowledgment: * "This product includes software developed by Computing Services * at Carnegie Mellon University (http://www.cmu.edu/computing/)." * * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * $Id: lcp.h,v 1.20 2004/11/14 22:53:42 carlsonj Exp $ */ #include "lwip/opt.h" #if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */ #ifndef LCP_H #define LCP_H #include "ppp.h" /* * Options. */ #define CI_VENDOR 0 /* Vendor Specific */ #define CI_MRU 1 /* Maximum Receive Unit */ #define CI_ASYNCMAP 2 /* Async Control Character Map */ #define CI_AUTHTYPE 3 /* Authentication Type */ #define CI_QUALITY 4 /* Quality Protocol */ #define CI_MAGICNUMBER 5 /* Magic Number */ #define CI_PCOMPRESSION 7 /* Protocol Field Compression */ #define CI_ACCOMPRESSION 8 /* Address/Control Field Compression */ #define CI_FCSALTERN 9 /* FCS-Alternatives */ #define CI_SDP 10 /* Self-Describing-Pad */ #define CI_NUMBERED 11 /* Numbered-Mode */ #define CI_CALLBACK 13 /* callback */ #define CI_MRRU 17 /* max reconstructed receive unit; multilink */ #define CI_SSNHF 18 /* short sequence numbers for multilink */ #define CI_EPDISC 19 /* endpoint discriminator */ #define CI_MPPLUS 22 /* Multi-Link-Plus-Procedure */ #define CI_LDISC 23 /* Link-Discriminator */ #define CI_LCPAUTH 24 /* LCP Authentication */ #define CI_COBS 25 /* Consistent Overhead Byte Stuffing */ #define CI_PREFELIS 26 /* Prefix Elision */ #define CI_MPHDRFMT 27 /* MP Header Format */ #define CI_I18N 28 /* Internationalization */ #define CI_SDL 29 /* Simple Data Link */ /* * LCP-specific packet types (code numbers). */ #define PROTREJ 8 /* Protocol Reject */ #define ECHOREQ 9 /* Echo Request */ #define ECHOREP 10 /* Echo Reply */ #define DISCREQ 11 /* Discard Request */ #define IDENTIF 12 /* Identification */ #define TIMEREM 13 /* Time Remaining */ /* Value used as data for CI_CALLBACK option */ #define CBCP_OPT 6 /* Use callback control protocol */ #define DEFMRU 1500 /* Try for this */ #define MINMRU 128 /* No MRUs below this */ #define MAXMRU 16384 /* Normally limit MRU to this */ /* An endpoint discriminator, used with multilink. */ #define MAX_ENDP_LEN 20 /* maximum length of discriminator value */ struct epdisc { unsigned char class_; /* -- The word "class" is reserved in C++. */ unsigned char length; unsigned char value[MAX_ENDP_LEN]; }; /* * The state of options is described by an lcp_options structure. */ typedef struct lcp_options { unsigned int passive :1; /* Don't die if we don't get a response */ unsigned int silent :1; /* Wait for the other end to start first */ unsigned int restart :1; /* Restart vs. exit after close */ unsigned int neg_mru :1; /* Negotiate the MRU? */ unsigned int neg_asyncmap :1; /* Negotiate the async map? */ #if PAP_SUPPORT unsigned int neg_upap :1; /* Ask for UPAP authentication? */ #else unsigned int :1; /* 1 bit of padding */ #endif /* PAP_SUPPORT */ #if CHAP_SUPPORT unsigned int neg_chap :1; /* Ask for CHAP authentication? */ #else unsigned int :1; /* 1 bit of padding */ #endif /* CHAP_SUPPORT */ #if EAP_SUPPORT unsigned int neg_eap :1; /* Ask for EAP authentication? */ #else unsigned int :1; /* 1 bit of padding */ #endif /* EAP_SUPPORT */ unsigned int neg_magicnumber :1; /* Ask for magic number? */ unsigned int neg_pcompression :1; /* HDLC Protocol Field Compression? */ unsigned int neg_accompression :1; /* HDLC Address/Control Field Compression? */ #if LQR_SUPPORT unsigned int neg_lqr :1; /* Negotiate use of Link Quality Reports */ #else unsigned int :1; /* 1 bit of padding */ #endif /* LQR_SUPPORT */ unsigned int neg_cbcp :1; /* Negotiate use of CBCP */ #ifdef HAVE_MULTILINK unsigned int neg_mrru :1; /* negotiate multilink MRRU */ #else unsigned int :1; /* 1 bit of padding */ #endif /* HAVE_MULTILINK */ unsigned int neg_ssnhf :1; /* negotiate short sequence numbers */ unsigned int neg_endpoint :1; /* negotiate endpoint discriminator */ u16_t mru; /* Value of MRU */ #ifdef HAVE_MULTILINK u16_t mrru; /* Value of MRRU, and multilink enable */ #endif /* MULTILINK */ #if CHAP_SUPPORT u8_t chap_mdtype; /* which MD types (hashing algorithm) */ #endif /* CHAP_SUPPORT */ u32_t asyncmap; /* Value of async map */ u32_t magicnumber; u8_t numloops; /* Number of loops during magic number neg. */ #if LQR_SUPPORT u32_t lqr_period; /* Reporting period for LQR 1/100ths second */ #endif /* LQR_SUPPORT */ struct epdisc endpoint; /* endpoint discriminator */ } lcp_options; void lcp_open(ppp_pcb *pcb); void lcp_close(ppp_pcb *pcb, char *reason); void lcp_lowerup(ppp_pcb *pcb); void lcp_lowerdown(ppp_pcb *pcb); void lcp_sprotrej(ppp_pcb *pcb, u_char *p, int len); /* send protocol reject */ extern const struct protent lcp_protent; #if 0 /* moved to opt.h */ /* Default number of times we receive our magic number from the peer before deciding the link is looped-back. */ #define DEFLOOPBACKFAIL 10 #endif /* moved to opt.h */ #endif /* LCP_H */ #endif /* PPP_SUPPORT */ ocproxy-1.60/lwip/src/include/netif/ppp/magic.h000066400000000000000000000111541303453231400214650ustar00rootroot00000000000000/* * magic.h - PPP Magic Number definitions. * * Copyright (c) 1984-2000 Carnegie Mellon University. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The name "Carnegie Mellon University" must not be used to * endorse or promote products derived from this software without * prior written permission. For permission or any legal * details, please contact * Office of Technology Transfer * Carnegie Mellon University * 5000 Forbes Avenue * Pittsburgh, PA 15213-3890 * (412) 268-4387, fax: (412) 268-7395 * tech-transfer@andrew.cmu.edu * * 4. Redistributions of any form whatsoever must retain the following * acknowledgment: * "This product includes software developed by Computing Services * at Carnegie Mellon University (http://www.cmu.edu/computing/)." * * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * $Id: magic.h,v 1.5 2003/06/11 23:56:26 paulus Exp $ */ /***************************************************************************** * randm.h - Random number generator header file. * * Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc. * Copyright (c) 1998 Global Election Systems Inc. * * The authors hereby grant permission to use, copy, modify, distribute, * and license this software and its documentation for any purpose, provided * that existing copyright notices are retained in all copies and that this * notice and the following disclaimer are included verbatim in any * distributions. No written agreement, license, or royalty fee is required * for any of the authorized uses. * * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ****************************************************************************** * REVISION HISTORY * * 03-01-01 Marc Boucher * Ported to lwIP. * 98-05-29 Guy Lancaster , Global Election Systems Inc. * Extracted from avos. *****************************************************************************/ #include "lwip/opt.h" #if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */ #ifndef MAGIC_H #define MAGIC_H /*********************** *** PUBLIC FUNCTIONS *** ***********************/ /* * Initialize the random number generator. */ void magic_init(void); /* * Randomize our random seed value. To be called for truely random events * such as user operations and network traffic. */ void magic_randomize(void); /* * Return a new random number. */ u32_t magic(void); /* Returns the next magic number */ #if PPP_MD5_RANDM /* * Fill buffer with random bytes * * Use the random pool to generate random data. This degrades to pseudo * random when used faster than randomness is supplied using magic_churnrand(). * Thus it's important to make sure that the results of this are not * published directly because one could predict the next result to at * least some degree. Also, it's important to get a good seed before * the first use. */ void random_bytes(unsigned char *buf, u32_t len); #endif /* PPP_MD5_RANDM */ #endif /* MAGIC_H */ #endif /* PPP_SUPPORT */ ocproxy-1.60/lwip/src/include/netif/ppp/polarssl/000077500000000000000000000000001303453231400220715ustar00rootroot00000000000000ocproxy-1.60/lwip/src/include/netif/ppp/polarssl/des.h000066400000000000000000000057121303453231400230220ustar00rootroot00000000000000/** * \file des.h * * Based on XySSL: Copyright (C) 2006-2008 Christophe Devine * * Copyright (C) 2009 Paul Bakker * * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the names of PolarSSL or XySSL nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "lwip/opt.h" #if LWIP_INCLUDED_POLARSSL_DES #ifndef LWIP_INCLUDED_POLARSSL_DES_H #define LWIP_INCLUDED_POLARSSL_DES_H #define DES_ENCRYPT 1 #define DES_DECRYPT 0 /** * \brief DES context structure */ typedef struct { int mode; /*!< encrypt/decrypt */ unsigned long sk[32]; /*!< DES subkeys */ } des_context; #ifdef __cplusplus extern "C" { #endif /** * \brief DES key schedule (56-bit, encryption) * * \param ctx DES context to be initialized * \param key 8-byte secret key */ void des_setkey_enc( des_context *ctx, unsigned char key[8] ); /** * \brief DES key schedule (56-bit, decryption) * * \param ctx DES context to be initialized * \param key 8-byte secret key */ void des_setkey_dec( des_context *ctx, unsigned char key[8] ); /** * \brief DES-ECB block encryption/decryption * * \param ctx DES context * \param input 64-bit input block * \param output 64-bit output block */ void des_crypt_ecb( des_context *ctx, unsigned char input[8], unsigned char output[8] ); #ifdef __cplusplus } #endif #endif /* LWIP_INCLUDED_POLARSSL_DES_H */ #endif /* LWIP_INCLUDED_POLARSSL_DES */ ocproxy-1.60/lwip/src/include/netif/ppp/polarssl/md4.h000066400000000000000000000060541303453231400227330ustar00rootroot00000000000000/** * \file md4.h * * Based on XySSL: Copyright (C) 2006-2008 Christophe Devine * * Copyright (C) 2009 Paul Bakker * * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the names of PolarSSL or XySSL nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "lwip/opt.h" #if LWIP_INCLUDED_POLARSSL_MD4 #ifndef LWIP_INCLUDED_POLARSSL_MD4_H #define LWIP_INCLUDED_POLARSSL_MD4_H /** * \brief MD4 context structure */ typedef struct { unsigned long total[2]; /*!< number of bytes processed */ unsigned long state[4]; /*!< intermediate digest state */ unsigned char buffer[64]; /*!< data block being processed */ } md4_context; #ifdef __cplusplus extern "C" { #endif /** * \brief MD4 context setup * * \param ctx context to be initialized */ void md4_starts( md4_context *ctx ); /** * \brief MD4 process buffer * * \param ctx MD4 context * \param input buffer holding the data * \param ilen length of the input data */ void md4_update( md4_context *ctx, unsigned char *input, int ilen ); /** * \brief MD4 final digest * * \param ctx MD4 context * \param output MD4 checksum result */ void md4_finish( md4_context *ctx, unsigned char output[16] ); /** * \brief Output = MD4( input buffer ) * * \param input buffer holding the data * \param ilen length of the input data * \param output MD4 checksum result */ void md4( unsigned char *input, int ilen, unsigned char output[16] ); #ifdef __cplusplus } #endif #endif /* LWIP_INCLUDED_POLARSSL_MD4_H */ #endif /* LWIP_INCLUDED_POLARSSL_MD4 */ ocproxy-1.60/lwip/src/include/netif/ppp/polarssl/md5.h000066400000000000000000000060531303453231400227330ustar00rootroot00000000000000/** * \file md5.h * * Based on XySSL: Copyright (C) 2006-2008 Christophe Devine * * Copyright (C) 2009 Paul Bakker * * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the names of PolarSSL or XySSL nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "lwip/opt.h" #if LWIP_INCLUDED_POLARSSL_MD5 #ifndef LWIP_INCLUDED_POLARSSL_MD5_H #define LWIP_INCLUDED_POLARSSL_MD5_H /** * \brief MD5 context structure */ typedef struct { unsigned long total[2]; /*!< number of bytes processed */ unsigned long state[4]; /*!< intermediate digest state */ unsigned char buffer[64]; /*!< data block being processed */ } md5_context; #ifdef __cplusplus extern "C" { #endif /** * \brief MD5 context setup * * \param ctx context to be initialized */ void md5_starts( md5_context *ctx ); /** * \brief MD5 process buffer * * \param ctx MD5 context * \param input buffer holding the data * \param ilen length of the input data */ void md5_update( md5_context *ctx, unsigned char *input, int ilen ); /** * \brief MD5 final digest * * \param ctx MD5 context * \param output MD5 checksum result */ void md5_finish( md5_context *ctx, unsigned char output[16] ); /** * \brief Output = MD5( input buffer ) * * \param input buffer holding the data * \param ilen length of the input data * \param output MD5 checksum result */ void md5( unsigned char *input, int ilen, unsigned char output[16] ); #ifdef __cplusplus } #endif #endif /* LWIP_INCLUDED_POLARSSL_MD5_H */ #endif /* LWIP_INCLUDED_POLARSSL_MD5 */ ocproxy-1.60/lwip/src/include/netif/ppp/polarssl/sha1.h000066400000000000000000000061131303453231400230770ustar00rootroot00000000000000/** * \file sha1.h * * Based on XySSL: Copyright (C) 2006-2008 Christophe Devine * * Copyright (C) 2009 Paul Bakker * * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the names of PolarSSL or XySSL nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "lwip/opt.h" #if LWIP_INCLUDED_POLARSSL_SHA1 #ifndef LWIP_INCLUDED_POLARSSL_SHA1_H #define LWIP_INCLUDED_POLARSSL_SHA1_H /** * \brief SHA-1 context structure */ typedef struct { unsigned long total[2]; /*!< number of bytes processed */ unsigned long state[5]; /*!< intermediate digest state */ unsigned char buffer[64]; /*!< data block being processed */ } sha1_context; #ifdef __cplusplus extern "C" { #endif /** * \brief SHA-1 context setup * * \param ctx context to be initialized */ void sha1_starts( sha1_context *ctx ); /** * \brief SHA-1 process buffer * * \param ctx SHA-1 context * \param input buffer holding the data * \param ilen length of the input data */ void sha1_update( sha1_context *ctx, unsigned char *input, int ilen ); /** * \brief SHA-1 final digest * * \param ctx SHA-1 context * \param output SHA-1 checksum result */ void sha1_finish( sha1_context *ctx, unsigned char output[20] ); /** * \brief Output = SHA-1( input buffer ) * * \param input buffer holding the data * \param ilen length of the input data * \param output SHA-1 checksum result */ void sha1( unsigned char *input, int ilen, unsigned char output[20] ); #ifdef __cplusplus } #endif #endif /* LWIP_INCLUDED_POLARSSL_SHA1_H */ #endif /* LWIP_INCLUDED_POLARSSL_SHA1 */ ocproxy-1.60/lwip/src/include/netif/ppp/ppp.h000066400000000000000000000527271303453231400212170ustar00rootroot00000000000000/***************************************************************************** * ppp.h - Network Point to Point Protocol header file. * * Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc. * portions Copyright (c) 1997 Global Election Systems Inc. * * The authors hereby grant permission to use, copy, modify, distribute, * and license this software and its documentation for any purpose, provided * that existing copyright notices are retained in all copies and that this * notice and the following disclaimer are included verbatim in any * distributions. No written agreement, license, or royalty fee is required * for any of the authorized uses. * * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ****************************************************************************** * REVISION HISTORY * * 03-01-01 Marc Boucher * Ported to lwIP. * 97-11-05 Guy Lancaster , Global Election Systems Inc. * Original derived from BSD codes. *****************************************************************************/ #include "lwip/opt.h" #if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */ #ifndef PPP_H #define PPP_H #include "lwip/def.h" #include "lwip/sio.h" #include "lwip/stats.h" #include "lwip/mem.h" #include "lwip/netif.h" #include "lwip/sys.h" #include "lwip/timers.h" #if PPP_IPV6_SUPPORT #include "lwip/ip6_addr.h" #endif /* PPP_IPV6_SUPPORT */ /************************* *** PUBLIC DEFINITIONS *** *************************/ /* * The basic PPP frame. */ #define PPP_HDRLEN 4 /* octets for standard ppp header */ #define PPP_FCSLEN 2 /* octets for FCS */ /* * Values for phase. */ #define PPP_PHASE_DEAD 0 #define PPP_PHASE_INITIALIZE 1 #define PPP_PHASE_SERIALCONN 2 #define PPP_PHASE_DORMANT 3 #define PPP_PHASE_ESTABLISH 4 #define PPP_PHASE_AUTHENTICATE 5 #define PPP_PHASE_CALLBACK 6 #define PPP_PHASE_NETWORK 7 #define PPP_PHASE_RUNNING 8 #define PPP_PHASE_TERMINATE 9 #define PPP_PHASE_DISCONNECT 10 #define PPP_PHASE_HOLDOFF 11 #define PPP_PHASE_MASTER 12 /* Error codes. */ #define PPPERR_NONE 0 /* No error. */ #define PPPERR_PARAM 1 /* Invalid parameter. */ #define PPPERR_OPEN 2 /* Unable to open PPP session. */ #define PPPERR_DEVICE 3 /* Invalid I/O device for PPP. */ #define PPPERR_ALLOC 4 /* Unable to allocate resources. */ #define PPPERR_USER 5 /* User interrupt. */ #define PPPERR_CONNECT 6 /* Connection lost. */ #define PPPERR_AUTHFAIL 7 /* Failed authentication challenge. */ #define PPPERR_PROTOCOL 8 /* Failed to meet protocol. */ #define PPPERR_PEERDEAD 9 /* Connection timeout */ #define PPPERR_IDLETIMEOUT 10 /* Idle Timeout */ #define PPPERR_CONNECTTIME 11 /* Max connect time reached */ #define PPPERR_LOOPBACK 12 /* Loopback detected */ /* * PPP IOCTL commands. */ /* * Get the up status - 0 for down, non-zero for up. The argument must * point to an int. */ #define PPPCTLG_UPSTATUS 100 /* Get the up status - 0 down else up */ #define PPPCTLS_ERRCODE 101 /* Set the error code */ #define PPPCTLG_ERRCODE 102 /* Get the error code */ #define PPPCTLG_FD 103 /* Get the fd associated with the ppp */ /************************ *** PUBLIC DATA TYPES *** ************************/ /* * Other headers require ppp_pcb definition for prototypes, but ppp_pcb * require some structure definition from other headers as well, we are * fixing the dependency loop here by declaring the ppp_pcb type then * by including headers containing necessary struct definition for ppp_pcb */ typedef struct ppp_pcb_s ppp_pcb; /* Type definitions for BSD code. */ #ifndef __u_char_defined typedef unsigned long u_long; typedef unsigned int u_int; typedef unsigned short u_short; typedef unsigned char u_char; #endif #include "fsm.h" #include "lcp.h" #include "ipcp.h" #if PPP_IPV6_SUPPORT #include "ipv6cp.h" #endif /* PPP_IPV6_SUPPORT */ #if PAP_SUPPORT #include "upap.h" #endif /* PAP_SUPPORT */ #if CHAP_SUPPORT #include "chap-new.h" #endif /* CHAP_SUPPORT */ #if EAP_SUPPORT #include "eap.h" #endif /* EAP_SUPPORT */ #if VJ_SUPPORT #include "vj.h" #endif /* VJ_SUPPORT */ #if PPPOE_SUPPORT #include "netif/ppp/pppoe.h" #endif /* PPPOE_SUPPORT */ #if PPPOL2TP_SUPPORT #include "netif/ppp/pppol2tp.h" #endif /* PPPOL2TP_SUPPORT */ /* * PPP configuration. */ typedef struct ppp_settings_s { #if PPP_SERVER unsigned int auth_required : 1; /* Peer is required to authenticate */ unsigned int null_login : 1; /* Username of "" and a password of "" are acceptable */ #else unsigned int :2; /* 2 bits of padding */ #endif /* PPP_SERVER */ #if PPP_REMOTENAME unsigned int explicit_remote : 1; /* remote_name specified with remotename opt */ #else unsigned int :1; /* 1 bit of padding */ #endif /* PPP_REMOTENAME */ #if PAP_SUPPORT unsigned int refuse_pap : 1; /* Don't wanna auth. ourselves with PAP */ #else unsigned int :1; /* 1 bit of padding */ #endif /* PAP_SUPPORT */ #if CHAP_SUPPORT unsigned int refuse_chap : 1; /* Don't wanna auth. ourselves with CHAP */ #else unsigned int :1; /* 1 bit of padding */ #endif /* CHAP_SUPPORT */ #if MSCHAP_SUPPORT unsigned int refuse_mschap : 1; /* Don't wanna auth. ourselves with MS-CHAP */ unsigned int refuse_mschap_v2 : 1; /* Don't wanna auth. ourselves with MS-CHAPv2 */ #else unsigned int :2; /* 2 bits of padding */ #endif /* MSCHAP_SUPPORT */ #if EAP_SUPPORT unsigned int refuse_eap : 1; /* Don't wanna auth. ourselves with EAP */ #else unsigned int :1; /* 1 bit of padding */ #endif /* EAP_SUPPORT */ unsigned int usepeerdns : 1; /* Ask peer for DNS adds */ unsigned int persist : 1; /* Persist mode, always try to reopen the connection */ #if PRINTPKT_SUPPORT unsigned int hide_password : 1; /* Hide password in dumped packets */ #else unsigned int :1; /* 1 bit of padding */ #endif /* PRINTPKT_SUPPORT */ unsigned int noremoteip : 1; /* Let him have no IP address */ unsigned int lax_recv : 1; /* accept control chars in asyncmap */ unsigned int noendpoint : 1; /* don't send/accept endpoint discriminator */ #if PPP_LCP_ADAPTIVE unsigned int lcp_echo_adaptive : 1; /* request echo only if the link was idle */ #else unsigned int :1; /* 1 bit of padding */ #endif unsigned int :1; /* 1 bit of padding to round out to 16 bits */ u16_t listen_time; /* time to listen first (ms), waiting for peer to send LCP packet */ #if PPP_IDLETIMELIMIT u16_t idle_time_limit; /* Disconnect if idle for this many seconds */ #endif /* PPP_IDLETIMELIMIT */ #if PPP_MAXCONNECT u32_t maxconnect; /* Maximum connect time (seconds) */ #endif /* PPP_MAXCONNECT */ /* auth data */ char *user; /* Username for PAP */ char *passwd; /* Password for PAP, secret for CHAP */ #if PPP_SERVER char our_name [MAXNAMELEN + 1]; /* Our name for authentication purposes */ #endif /* PPP_SERVER */ #if PPP_REMOTENAME char remote_name[MAXNAMELEN + 1]; /* Peer's name for authentication */ #endif /* PPP_REMOTENAME */ #if PAP_SUPPORT u8_t pap_timeout_time; /* Timeout (seconds) for auth-req retrans. */ u8_t pap_max_transmits; /* Number of auth-reqs sent */ #if PPP_SERVER u8_t pap_req_timeout; /* Time to wait for auth-req from peer */ #endif /* PPP_SERVER */ #endif /* PAP_SUPPPORT */ #if CHAP_SUPPORT u8_t chap_timeout_time; /* Timeout (seconds) for retransmitting req */ u8_t chap_max_transmits; /* max # times to send challenge */ #if PPP_SERVER u8_t chap_rechallenge_time; /* Time to wait for auth-req from peer */ #endif /* PPP_SERVER */ #endif /* CHAP_SUPPPORT */ #if EAP_SUPPORT u8_t eap_req_time; /* Time to wait (for retransmit/fail) */ u8_t eap_allow_req; /* Max Requests allowed */ #if PPP_SERVER u8_t eap_timeout_time; /* Time to wait (for retransmit/fail) */ u8_t eap_max_transmits; /* Max Requests allowed */ #endif /* PPP_SERVER */ #endif /* EAP_SUPPORT */ u8_t fsm_timeout_time; /* Timeout time in seconds */ u8_t fsm_max_conf_req_transmits; /* Maximum Configure-Request transmissions */ u8_t fsm_max_term_transmits; /* Maximum Terminate-Request transmissions */ u8_t fsm_max_nak_loops; /* Maximum number of nak loops tolerated */ u8_t lcp_loopbackfail; /* Number of times we receive our magic number from the peer before deciding the link is looped-back. */ u8_t lcp_echo_interval; /* Interval between LCP echo-requests */ u8_t lcp_echo_fails; /* Tolerance to unanswered echo-requests */ } ppp_settings; struct ppp_addrs { ip_addr_t our_ipaddr, his_ipaddr, netmask; ip_addr_t dns1, dns2; #if PPP_IPV6_SUPPORT ip6_addr_t our6_ipaddr, his6_ipaddr; #endif /* PPP_IPV6_SUPPORT */ }; /* FIXME: find a way to move ppp_dev_states and ppp_pcb_rx_s to ppp_impl.h */ #if PPPOS_SUPPORT /* * Extended asyncmap - allows any character to be escaped. */ typedef u_char ext_accm[32]; /* PPP packet parser states. Current state indicates operation yet to be * completed. */ typedef enum { PDIDLE = 0, /* Idle state - waiting. */ PDSTART, /* Process start flag. */ PDADDRESS, /* Process address field. */ PDCONTROL, /* Process control field. */ PDPROTOCOL1, /* Process protocol field 1. */ PDPROTOCOL2, /* Process protocol field 2. */ PDDATA /* Process data byte. */ } ppp_dev_states; /* * PPP interface RX control block. */ typedef struct ppp_pcb_rx_s { /** ppp descriptor */ ppp_pcb *pcb; /** the rx file descriptor */ sio_fd_t fd; /* The input packet. */ struct pbuf *in_head, *in_tail; u16_t in_protocol; /* The input protocol code. */ u16_t in_fcs; /* Input Frame Check Sequence value. */ ppp_dev_states in_state; /* The input process state. */ char in_escaped; /* Escape next character. */ ext_accm in_accm; /* Async-Ctl-Char-Map for input. */ } ppp_pcb_rx; #endif /* PPPOS_SUPPORT */ /* * PPP interface control block. */ struct ppp_pcb_s { /* -- below are data that will NOT be cleared between two sessions */ #if PPP_DEBUG u8_t num; /* Interface number - only useful for debugging */ #endif /* PPP_DEBUG */ ppp_settings settings; #if PPPOS_SUPPORT sio_fd_t fd; /* File device ID of port. */ #endif /* PPPOS_SUPPORT */ #if PPPOE_SUPPORT struct pppoe_softc *pppoe_sc; #endif /* PPPOE_SUPPORT */ #if PPPOL2TP_SUPPORT pppol2tp_pcb *l2tp_pcb; #endif /* PPPOL2TP_SUPPORT */ void (*link_status_cb)(ppp_pcb *pcb, int err_code, void *ctx); /* Status change callback */ #if PPP_NOTIFY_PHASE void (*notify_phase_cb)(ppp_pcb *pcb, u8_t phase, void *ctx); /* Notify phase callback */ #endif /* PPP_NOTIFY_PHASE */ void *ctx_cb; /* Callbacks optional pointer */ struct netif netif; /* PPP interface */ /* -- below are data that will be cleared between two sessions */ /* * phase must be the first member of cleared members, because it is used to know * which part must not be cleared. */ u8_t phase; /* where the link is at */ u8_t err_code; /* Code indicating why interface is down. */ /* flags */ unsigned int if_up :1; /* True when the interface is up. */ unsigned int pcomp :1; /* Does peer accept protocol compression? */ unsigned int accomp :1; /* Does peer accept addr/ctl compression? */ unsigned int proxy_arp_set :1; /* Have created proxy arp entry */ unsigned int ipcp_is_open :1; /* haven't called np_finished() */ unsigned int ipcp_is_up :1; /* have called ipcp_up() */ #if PPP_IPV6_SUPPORT unsigned int ipv6cp_is_up :1; /* have called ip6cp_up() */ #else unsigned int :1; /* 1 bit of padding */ #endif /* PPP_IPV6_SUPPORT */ unsigned int ask_for_local :1; /* request our address from peer */ unsigned int lcp_echo_timer_running :1; /* set if a timer is running */ #if PPPOS_SUPPORT && VJ_SUPPORT unsigned int vj_enabled :1; /* Flag indicating VJ compression enabled. */ #else unsigned int :1; /* 1 bit of padding */ #endif /* PPPOS_SUPPORT && VJ_SUPPORT */ unsigned int :6; /* 5 bits of padding to round out to 16 bits */ #if PPPOS_SUPPORT /* FIXME: there is probably one superfluous */ ext_accm out_accm; /* Async-Ctl-Char-Map for output. */ ext_accm xmit_accm; /* extended transmit ACCM */ ppp_pcb_rx rx; #if VJ_SUPPORT struct vjcompress vj_comp; /* Van Jacobson compression header. */ #endif /* VJ_SUPPORT */ #endif /* PPPOS_SUPPORT */ u32_t last_xmit; /* Time of last transmission. */ struct ppp_addrs addrs; /* PPP addresses */ /* auth data */ #if PPP_SERVER char peer_authname[MAXNAMELEN + 1]; /* The name by which the peer authenticated itself to us. */ #endif /* PPP_SERVER */ u16_t auth_pending; /* Records which authentication operations haven't completed yet. */ u16_t auth_done; /* Records which authentication operations have been completed. */ u8_t num_np_open; /* Number of network protocols which we have opened. */ u8_t num_np_up; /* Number of network protocols which have come up. */ #if PAP_SUPPORT upap_state upap; /* PAP data */ #endif /* PAP_SUPPORT */ #if CHAP_SUPPORT chap_client_state chap_client; /* CHAP client data */ #if PPP_SERVER chap_server_state chap_server; /* CHAP server data */ #endif /* PPP_SERVER */ #endif /* CHAP_SUPPORT */ #if EAP_SUPPORT eap_state eap; /* EAP data */ #endif /* EAP_SUPPORT */ fsm lcp_fsm; /* LCP fsm structure */ lcp_options lcp_wantoptions; /* Options that we want to request */ lcp_options lcp_gotoptions; /* Options that peer ack'd */ lcp_options lcp_allowoptions; /* Options we allow peer to request */ lcp_options lcp_hisoptions; /* Options that we ack'd */ u8_t lcp_echos_pending; /* Number of outstanding echo msgs */ u8_t lcp_echo_number; /* ID number of next echo frame */ u16_t peer_mru; /* currently negotiated peer MRU */ fsm ipcp_fsm; /* IPCP fsm structure */ ipcp_options ipcp_wantoptions; /* Options that we want to request */ ipcp_options ipcp_gotoptions; /* Options that peer ack'd */ ipcp_options ipcp_allowoptions; /* Options we allow peer to request */ ipcp_options ipcp_hisoptions; /* Options that we ack'd */ #if PPP_IPV6_SUPPORT fsm ipv6cp_fsm; /* IPV6CP fsm structure */ ipv6cp_options ipv6cp_wantoptions; /* Options that we want to request */ ipv6cp_options ipv6cp_gotoptions; /* Options that peer ack'd */ ipv6cp_options ipv6cp_allowoptions; /* Options we allow peer to request */ ipv6cp_options ipv6cp_hisoptions; /* Options that we ack'd */ #endif /* PPP_IPV6_SUPPORT */ }; /************************ *** PUBLIC FUNCTIONS *** ************************/ /* * Initialize the PPP subsystem. */ int ppp_init(void); /* * Create a new PPP session. * * This initializes the PPP control block but does not * attempt to negotiate the LCP session. * * Return a new PPP connection control block pointer * on success or a null pointer on failure. */ ppp_pcb *ppp_new(void); /* * Set a PPP interface as the default network interface * (used to output all packets for which no specific route is found). */ void ppp_set_default(ppp_pcb *pcb); /* * Set auth helper, optional, you can either fill ppp_pcb->settings. * * Warning: Using PPPAUTHTYPE_ANY might have security consequences. * RFC 1994 says: * * In practice, within or associated with each PPP server, there is a * database which associates "user" names with authentication * information ("secrets"). It is not anticipated that a particular * named user would be authenticated by multiple methods. This would * make the user vulnerable to attacks which negotiate the least secure * method from among a set (such as PAP rather than CHAP). If the same * secret was used, PAP would reveal the secret to be used later with * CHAP. * * Instead, for each user name there should be an indication of exactly * one method used to authenticate that user name. If a user needs to * make use of different authentication methods under different * circumstances, then distinct user names SHOULD be employed, each of * which identifies exactly one authentication method. * */ #define PPPAUTHTYPE_NONE 0x00 #define PPPAUTHTYPE_PAP 0x01 #define PPPAUTHTYPE_CHAP 0x02 #define PPPAUTHTYPE_MSCHAP 0x04 #define PPPAUTHTYPE_EAP 0x08 #define PPPAUTHTYPE_ANY 0xff void ppp_set_auth(ppp_pcb *pcb, u8_t authtype, char *user, char *passwd); #if PPP_NOTIFY_PHASE /* * Set a PPP notify phase callback. * * This can be used for example to set a LED pattern depending on the * current phase of the PPP session. */ typedef void (*ppp_notify_phase_cb_fn)(ppp_pcb *pcb, u8_t phase, void *ctx); void ppp_set_notify_phase_callback(ppp_pcb *pcb, ppp_notify_phase_cb_fn notify_phase_cb); #endif /* PPP_NOTIFY_PHASE */ /* Link status callback function prototype */ typedef void (*ppp_link_status_cb_fn)(ppp_pcb *pcb, int err_code, void *ctx); #if PPPOS_SUPPORT /* * Create a new PPP connection using the given serial I/O device. * * If this port connects to a modem, the modem connection must be * established before calling this. * * Return 0 on success, an error code on failure. */ int ppp_over_serial_create(ppp_pcb *pcb, sio_fd_t fd, ppp_link_status_cb_fn link_status_cb, void *ctx_cb); #endif /* PPPOS_SUPPORT */ #if PPPOE_SUPPORT /* * Create a new PPP Over Ethernet (PPPoE) connection. * * Return 0 on success, an error code on failure. */ int ppp_over_ethernet_create(ppp_pcb *pcb, struct netif *ethif, const char *service_name, const char *concentrator_name, ppp_link_status_cb_fn link_status_cb, void *ctx_cb); #endif /* PPPOE_SUPPORT */ #if PPPOL2TP_SUPPORT /* * Create a new PPP Over L2TP (PPPoL2TP) connection. */ int ppp_over_l2tp_create(ppp_pcb *pcb, struct netif *netif, ip_addr_t *ipaddr, u16_t port, u8_t *secret, u8_t secret_len, ppp_link_status_cb_fn link_status_cb, void *ctx_cb); #endif /* PPPOL2TP_SUPPORT */ /* * Open a PPP connection. * * This can only be called if PPP is in the dead phase. * * Holdoff is the time to wait (in seconds) before initiating * the connection. */ int ppp_open(ppp_pcb *pcb, u16_t holdoff); /* * Initiate the end of a PPP connection. * Any outstanding packets in the queues are dropped. * Return 0 on success, an error code on failure. */ int ppp_close(ppp_pcb *pcb); /* * Indicate to the PPP stack that the line has disconnected. */ void ppp_sighup(ppp_pcb *pcb); /* * Free the control block, clean everything except the PPP PCB itself * and the netif, it allows you to change the underlying PPP protocol * (eg. from PPPoE to PPPoS to switch from DSL to GPRS) without losing * your PPP and netif handlers. * * This can only be called if PPP is in the dead phase. * * You must use ppp_close() before if you wish to terminate * an established PPP session. * * Return 0 on success, an error code on failure. */ int ppp_free(ppp_pcb *pcb); /* * Release the control block. * * This can only be called if PPP is in the dead phase. * * You must use ppp_close() before if you wish to terminate * an established PPP session. * * Return 0 on success, an error code on failure. */ int ppp_delete(ppp_pcb *pcb); /* * Get and set parameters for the given connection. * Return 0 on success, an error code on failure. */ int ppp_ioctl(ppp_pcb *pcb, int cmd, void *arg); #if PPPOS_SUPPORT /* * PPP over Serial: this is the input function to be called for received data. */ void pppos_input(ppp_pcb *pcb, u_char* data, int len); #endif /* PPPOS_SUPPORT */ /* Get the PPP netif interface */ #define ppp_netif(ppp) (&(ppp)->netif) /* Get the PPP addresses */ #define ppp_addrs(ppp) (&(ppp)->addrs) #if LWIP_NETIF_STATUS_CALLBACK /* Set an lwIP-style status-callback for the selected PPP device */ void ppp_set_netif_statuscallback(ppp_pcb *pcb, netif_status_callback_fn status_callback); #endif /* LWIP_NETIF_STATUS_CALLBACK */ #if LWIP_NETIF_LINK_CALLBACK /* Set an lwIP-style link-callback for the selected PPP device */ void ppp_set_netif_linkcallback(ppp_pcb *pcb, netif_status_callback_fn link_callback); #endif /* LWIP_NETIF_LINK_CALLBACK */ #endif /* PPP_H */ #endif /* PPP_SUPPORT */ ocproxy-1.60/lwip/src/include/netif/ppp/ppp_impl.h000066400000000000000000000457371303453231400222430ustar00rootroot00000000000000/***************************************************************************** * ppp.h - Network Point to Point Protocol header file. * * Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc. * portions Copyright (c) 1997 Global Election Systems Inc. * * The authors hereby grant permission to use, copy, modify, distribute, * and license this software and its documentation for any purpose, provided * that existing copyright notices are retained in all copies and that this * notice and the following disclaimer are included verbatim in any * distributions. No written agreement, license, or royalty fee is required * for any of the authorized uses. * * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ****************************************************************************** * REVISION HISTORY * * 03-01-01 Marc Boucher * Ported to lwIP. * 97-11-05 Guy Lancaster , Global Election Systems Inc. * Original derived from BSD codes. *****************************************************************************/ #include "lwip/opt.h" #if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */ #ifndef PPP_IMP_H_ #define PPP_IMP_H_ #include /* formats */ #include #include #include /* strtol() */ #include "lwip/netif.h" #include "lwip/def.h" #include "lwip/timers.h" #include "lwip/sio.h" #include "ppp.h" #include "pppdebug.h" /* * Memory used for control packets. * * PPP_CTRL_PBUF_MAX_SIZE is the amount of memory we allocate when we * cannot figure out how much we are going to use before filling the buffer. */ #if PPP_USE_PBUF_RAM #define PPP_CTRL_PBUF_TYPE PBUF_RAM #define PPP_CTRL_PBUF_MAX_SIZE 512 #else /* PPP_USE_PBUF_RAM */ #define PPP_CTRL_PBUF_TYPE PBUF_POOL #define PPP_CTRL_PBUF_MAX_SIZE PBUF_POOL_BUFSIZE #endif /* PPP_USE_PBUF_RAM */ /* * Limits. */ #define MAXWORDLEN 1024 /* max length of word in file (incl null) */ #define MAXARGS 1 /* max # args to a command */ #define MAXNAMELEN 256 /* max length of hostname or name for auth */ #define MAXSECRETLEN 256 /* max length of password or secret */ /* * The basic PPP frame. */ #define PPP_ADDRESS(p) (((u_char *)(p))[0]) #define PPP_CONTROL(p) (((u_char *)(p))[1]) #define PPP_PROTOCOL(p) ((((u_char *)(p))[2] << 8) + ((u_char *)(p))[3]) /* * Significant octet values. */ #define PPP_ALLSTATIONS 0xff /* All-Stations broadcast address */ #define PPP_UI 0x03 /* Unnumbered Information */ #define PPP_FLAG 0x7e /* Flag Sequence */ #define PPP_ESCAPE 0x7d /* Asynchronous Control Escape */ #define PPP_TRANS 0x20 /* Asynchronous transparency modifier */ /* * Protocol field values. */ #define PPP_IP 0x21 /* Internet Protocol */ #if 0 /* UNUSED */ #define PPP_AT 0x29 /* AppleTalk Protocol */ #define PPP_IPX 0x2b /* IPX protocol */ #endif /* UNUSED */ #if VJ_SUPPORT #define PPP_VJC_COMP 0x2d /* VJ compressed TCP */ #define PPP_VJC_UNCOMP 0x2f /* VJ uncompressed TCP */ #endif /* VJ_SUPPORT */ #if PPP_IPV6_SUPPORT #define PPP_IPV6 0x57 /* Internet Protocol Version 6 */ #endif /* PPP_IPV6_SUPPORT */ #if CCP_SUPPORT #define PPP_COMP 0xfd /* compressed packet */ #endif /* CCP_SUPPORT */ #define PPP_IPCP 0x8021 /* IP Control Protocol */ #if 0 /* UNUSED */ #define PPP_ATCP 0x8029 /* AppleTalk Control Protocol */ #define PPP_IPXCP 0x802b /* IPX Control Protocol */ #endif /* UNUSED */ #if PPP_IPV6_SUPPORT #define PPP_IPV6CP 0x8057 /* IPv6 Control Protocol */ #endif /* PPP_IPV6_SUPPORT */ #if CCP_SUPPORT #define PPP_CCP 0x80fd /* Compression Control Protocol */ #endif /* CCP_SUPPORT */ #if ECP_SUPPORT #define PPP_ECP 0x8053 /* Encryption Control Protocol */ #endif /* ECP_SUPPORT */ #define PPP_LCP 0xc021 /* Link Control Protocol */ #if PAP_SUPPORT #define PPP_PAP 0xc023 /* Password Authentication Protocol */ #endif /* PAP_SUPPORT */ #if LQR_SUPPORT #define PPP_LQR 0xc025 /* Link Quality Report protocol */ #endif /* LQR_SUPPORT */ #if CHAP_SUPPORT #define PPP_CHAP 0xc223 /* Cryptographic Handshake Auth. Protocol */ #endif /* CHAP_SUPPORT */ #if CBCP_SUPPORT #define PPP_CBCP 0xc029 /* Callback Control Protocol */ #endif /* CBCP_SUPPORT */ #if EAP_SUPPORT #define PPP_EAP 0xc227 /* Extensible Authentication Protocol */ #endif /* EAP_SUPPORT */ /* * Values for FCS calculations. */ #define PPP_INITFCS 0xffff /* Initial FCS value */ #define PPP_GOODFCS 0xf0b8 /* Good final FCS value */ #if PPP_FCS_TABLE #define PPP_FCS(fcs, c) (((fcs) >> 8) ^ fcstab[((fcs) ^ (c)) & 0xff]) #else u16_t ppp_get_fcs(u8_t byte); #define PPP_FCS(fcs, c) (((fcs) >> 8) ^ ppp_get_fcs(((fcs) ^ (c)) & 0xff)) #endif /* * What to do with network protocol (NP) packets. */ enum NPmode { NPMODE_PASS, /* pass the packet through */ NPMODE_DROP, /* silently drop the packet */ NPMODE_ERROR, /* return an error */ NPMODE_QUEUE /* save it up for later. */ }; /* * Statistics. */ #if PPP_STATS_SUPPORT struct pppstat { unsigned int ppp_ibytes; /* bytes received */ unsigned int ppp_ipackets; /* packets received */ unsigned int ppp_ierrors; /* receive errors */ unsigned int ppp_obytes; /* bytes sent */ unsigned int ppp_opackets; /* packets sent */ unsigned int ppp_oerrors; /* transmit errors */ }; #if VJ_SUPPORT struct vjstat { unsigned int vjs_packets; /* outbound packets */ unsigned int vjs_compressed; /* outbound compressed packets */ unsigned int vjs_searches; /* searches for connection state */ unsigned int vjs_misses; /* times couldn't find conn. state */ unsigned int vjs_uncompressedin; /* inbound uncompressed packets */ unsigned int vjs_compressedin; /* inbound compressed packets */ unsigned int vjs_errorin; /* inbound unknown type packets */ unsigned int vjs_tossed; /* inbound packets tossed because of error */ }; #endif /* VJ_SUPPORT */ struct ppp_stats { struct pppstat p; /* basic PPP statistics */ #if VJ_SUPPORT struct vjstat vj; /* VJ header compression statistics */ #endif /* VJ_SUPPORT */ }; #if CCP_SUPPORT struct compstat { unsigned int unc_bytes; /* total uncompressed bytes */ unsigned int unc_packets; /* total uncompressed packets */ unsigned int comp_bytes; /* compressed bytes */ unsigned int comp_packets; /* compressed packets */ unsigned int inc_bytes; /* incompressible bytes */ unsigned int inc_packets; /* incompressible packets */ unsigned int ratio; /* recent compression ratio << 8 */ }; struct ppp_comp_stats { struct compstat c; /* packet compression statistics */ struct compstat d; /* packet decompression statistics */ }; #endif /* CCP_SUPPORT */ #endif /* PPP_STATS_SUPPORT */ #if PPP_IDLETIMELIMIT /* * The following structure records the time in seconds since * the last NP packet was sent or received. */ struct ppp_idle { time_t xmit_idle; /* time since last NP packet sent */ time_t recv_idle; /* time since last NP packet received */ }; #endif /* PPP_IDLETIMELIMIT */ /* values for epdisc.class */ #define EPD_NULL 0 /* null discriminator, no data */ #define EPD_LOCAL 1 #define EPD_IP 2 #define EPD_MAC 3 #define EPD_MAGIC 4 #define EPD_PHONENUM 5 /* * Global variables. */ #ifdef HAVE_MULTILINK extern u8_t multilink; /* enable multilink operation */ extern u8_t doing_multilink; extern u8_t multilink_master; extern u8_t bundle_eof; extern u8_t bundle_terminating; #endif #ifdef MAXOCTETS extern unsigned int maxoctets; /* Maximum octetes per session (in bytes) */ extern int maxoctets_dir; /* Direction : 0 - in+out (default) 1 - in 2 - out 3 - max(in,out) */ extern int maxoctets_timeout; /* Timeout for check of octets limit */ #define PPP_OCTETS_DIRECTION_SUM 0 #define PPP_OCTETS_DIRECTION_IN 1 #define PPP_OCTETS_DIRECTION_OUT 2 #define PPP_OCTETS_DIRECTION_MAXOVERAL 3 /* same as previos, but little different on RADIUS side */ #define PPP_OCTETS_DIRECTION_MAXSESSION 4 #endif /* * The following struct gives the addresses of procedures to call * for a particular protocol. */ struct protent { u_short protocol; /* PPP protocol number */ /* Initialization procedure */ void (*init) (ppp_pcb *pcb); /* Process a received packet */ void (*input) (ppp_pcb *pcb, u_char *pkt, int len); /* Process a received protocol-reject */ void (*protrej) (ppp_pcb *pcb); /* Lower layer has come up */ void (*lowerup) (ppp_pcb *pcb); /* Lower layer has gone down */ void (*lowerdown) (ppp_pcb *pcb); /* Open the protocol */ void (*open) (ppp_pcb *pcb); /* Close the protocol */ void (*close) (ppp_pcb *pcb, char *reason); #if PRINTPKT_SUPPORT /* Print a packet in readable form */ int (*printpkt) (u_char *pkt, int len, void (*printer) (void *, char *, ...), void *arg); #endif /* PRINTPKT_SUPPORT */ /* FIXME: data input is only used by CCP, which is not supported at this time, * should we remove this entry and save some flash ? */ /* Process a received data packet */ void (*datainput) (ppp_pcb *pcb, u_char *pkt, int len); u8_t enabled_flag; /* 0 if protocol is disabled */ #if PRINTPKT_SUPPORT char *name; /* Text name of protocol */ char *data_name; /* Text name of corresponding data protocol */ #endif /* PRINTPKT_SUPPORT */ #if PPP_OPTIONS option_t *options; /* List of command-line options */ /* Check requested options, assign defaults */ void (*check_options) (void); #endif /* PPP_OPTIONS */ #if DEMAND_SUPPORT /* Configure interface for demand-dial */ int (*demand_conf) (int unit); /* Say whether to bring up link for this pkt */ int (*active_pkt) (u_char *pkt, int len); #endif /* DEMAND_SUPPORT */ }; /* Table of pointers to supported protocols */ extern const struct protent* const protocols[]; /* Values for auth_pending, auth_done */ #if PAP_SUPPORT #define PAP_WITHPEER 0x1 #define PAP_PEER 0x2 #endif /* PAP_SUPPORT */ #if CHAP_SUPPORT #define CHAP_WITHPEER 0x4 #define CHAP_PEER 0x8 #endif /* CHAP_SUPPORT */ #if EAP_SUPPORT #define EAP_WITHPEER 0x10 #define EAP_PEER 0x20 #endif /* EAP_SUPPORT */ /* Values for auth_done only */ #if CHAP_SUPPORT #define CHAP_MD5_WITHPEER 0x40 #define CHAP_MD5_PEER 0x80 #if MSCHAP_SUPPORT #define CHAP_MS_SHIFT 8 /* LSB position for MS auths */ #define CHAP_MS_WITHPEER 0x100 #define CHAP_MS_PEER 0x200 #define CHAP_MS2_WITHPEER 0x400 #define CHAP_MS2_PEER 0x800 #endif /* MSCHAP_SUPPORT */ #endif /* CHAP_SUPPORT */ /* Supported CHAP protocols */ #if CHAP_SUPPORT #include "chap-new.h" #if MSCHAP_SUPPORT #define CHAP_MDTYPE_SUPPORTED (MDTYPE_MICROSOFT_V2 | MDTYPE_MICROSOFT | MDTYPE_MD5) #else #define CHAP_MDTYPE_SUPPORTED (MDTYPE_MD5) #endif #else #define CHAP_MDTYPE_SUPPORTED (MDTYPE_NONE) #endif #if PPP_STATS_SUPPORT /* * PPP statistics structure */ struct pppd_stats { unsigned int bytes_in; unsigned int bytes_out; unsigned int pkts_in; unsigned int pkts_out; }; #endif /* PPP_STATS_SUPPORT */ /* PPP flow functions */ /* function called by pppoe.c */ void ppp_input(ppp_pcb *pcb, struct pbuf *pb); /* function called by all PPP subsystems to send packets */ int ppp_write(ppp_pcb *pcb, struct pbuf *p); /* functions called by auth.c link_terminated() */ void ppp_link_down(ppp_pcb *pcb); void ppp_link_terminated(ppp_pcb *pcb); /* merge a pbuf chain into one pbuf */ struct pbuf * ppp_singlebuf(struct pbuf *p); /* Functions called by various PPP subsystems to configure * the PPP interface or change the PPP phase. */ void new_phase(ppp_pcb *pcb, int p); #if PPPOS_SUPPORT void ppp_set_xaccm(ppp_pcb *pcb, ext_accm *accm); #endif /* PPPOS_SUPPORT */ int ppp_send_config(ppp_pcb *pcb, int mtu, u32_t accm, int pcomp, int accomp); int ppp_recv_config(ppp_pcb *pcb, int mru, u32_t accm, int pcomp, int accomp); int sifaddr(ppp_pcb *pcb, u32_t our_adr, u32_t his_adr, u32_t net_mask); int cifaddr(ppp_pcb *pcb, u32_t our_adr, u32_t his_adr); #if PPP_IPV6_SUPPORT int sif6addr(ppp_pcb *pcb, eui64_t our_eui64, eui64_t his_eui64); int cif6addr(ppp_pcb *pcb, eui64_t our_eui64, eui64_t his_eui64); #endif /* PPP_IPV6_SUPPORT */ int sdns(ppp_pcb *pcb, u32_t ns1, u32_t ns2); int cdns(ppp_pcb *pcb, u32_t ns1, u32_t ns2); int sifup(ppp_pcb *pcb); int sifdown (ppp_pcb *pcb); int sifnpmode(ppp_pcb *pcb, int proto, enum NPmode mode); void netif_set_mtu(ppp_pcb *pcb, int mtu); int netif_get_mtu(ppp_pcb *pcb); int sifproxyarp(ppp_pcb *pcb, u32_t his_adr); int cifproxyarp(ppp_pcb *pcb, u32_t his_adr); int sifvjcomp(ppp_pcb *pcb, int vjcomp, int cidcomp, int maxcid); #if PPP_IDLETIMELIMIT int get_idle_time(ppp_pcb *pcb, struct ppp_idle *ip); #endif /* PPP_IDLETIMELIMIT */ int get_loop_output(void); u32_t get_mask (u32_t addr); /* Optional protocol names list, to make our messages a little more informative. */ #if PPP_PROTOCOLNAME const char * protocol_name(int proto); #endif /* PPP_PROTOCOLNAME */ /* Optional stats support, to get some statistics on the PPP interface */ #if PPP_STATS_SUPPORT void print_link_stats(void); /* Print stats, if available */ void reset_link_stats(int u); /* Reset (init) stats when link goes up */ void update_link_stats(int u); /* Get stats at link termination */ #endif /* PPP_STATS_SUPPORT */ /* * Inline versions of get/put char/short/long. * Pointer is advanced; we assume that both arguments * are lvalues and will already be in registers. * cp MUST be u_char *. */ #define GETCHAR(c, cp) { \ (c) = *(cp)++; \ } #define PUTCHAR(c, cp) { \ *(cp)++ = (u_char) (c); \ } #define GETSHORT(s, cp) { \ (s) = *(cp)++ << 8; \ (s) |= *(cp)++; \ } #define PUTSHORT(s, cp) { \ *(cp)++ = (u_char) ((s) >> 8); \ *(cp)++ = (u_char) (s); \ } #define GETLONG(l, cp) { \ (l) = *(cp)++ << 8; \ (l) |= *(cp)++; (l) <<= 8; \ (l) |= *(cp)++; (l) <<= 8; \ (l) |= *(cp)++; \ } #define PUTLONG(l, cp) { \ *(cp)++ = (u_char) ((l) >> 24); \ *(cp)++ = (u_char) ((l) >> 16); \ *(cp)++ = (u_char) ((l) >> 8); \ *(cp)++ = (u_char) (l); \ } #define INCPTR(n, cp) ((cp) += (n)) #define DECPTR(n, cp) ((cp) -= (n)) /* * System dependent definitions for user-level 4.3BSD UNIX implementation. */ #define TIMEOUT(f, a, t) do { sys_untimeout((f), (a)); sys_timeout((t)*1000, (f), (a)); } while(0) #define TIMEOUTMS(f, a, t) do { sys_untimeout((f), (a)); sys_timeout((t), (f), (a)); } while(0) #define UNTIMEOUT(f, a) sys_untimeout((f), (a)) #define BZERO(s, n) memset(s, 0, n) #define BCMP(s1, s2, l) memcmp(s1, s2, l) #define PRINTMSG(m, l) { ppp_info("Remote message: %0.*v", l, m); } /* * MAKEHEADER - Add Header fields to a packet. */ #define MAKEHEADER(p, t) { \ PUTCHAR(PPP_ALLSTATIONS, p); \ PUTCHAR(PPP_UI, p); \ PUTSHORT(t, p); } /* Procedures exported from auth.c */ void link_required(ppp_pcb *pcb); /* we are starting to use the link */ void link_terminated(ppp_pcb *pcb); /* we are finished with the link */ void link_down(ppp_pcb *pcb); /* the LCP layer has left the Opened state */ void upper_layers_down(ppp_pcb *pcb); /* take all NCPs down */ void link_established(ppp_pcb *pcb); /* the link is up; authenticate now */ void start_networks(ppp_pcb *pcb); /* start all the network control protos */ void continue_networks(ppp_pcb *pcb); /* start network [ip, etc] control protos */ #if PPP_SERVER void auth_peer_fail(ppp_pcb *pcb, int protocol); /* peer failed to authenticate itself */ void auth_peer_success(ppp_pcb *pcb, int protocol, int prot_flavor, char *name, int namelen); /* peer successfully authenticated itself */ #endif /* PPP_SERVER */ void auth_withpeer_fail(ppp_pcb *pcb, int protocol); /* we failed to authenticate ourselves */ void auth_withpeer_success(ppp_pcb *pcb, int protocol, int prot_flavor); /* we successfully authenticated ourselves */ void np_up(ppp_pcb *pcb, int proto); /* a network protocol has come up */ void np_down(ppp_pcb *pcb, int proto); /* a network protocol has gone down */ void np_finished(ppp_pcb *pcb, int proto); /* a network protocol no longer needs link */ void auth_reset(ppp_pcb *pcb); /* check what secrets we have */ int get_secret(ppp_pcb *pcb, char *client, char *server, char *secret, int *secret_len, int am_server); /* get "secret" for chap */ /* Procedures exported from ipcp.c */ /* int parse_dotted_ip (char *, u32_t *); */ /* Procedures exported from demand.c */ #if DEMAND_SUPPORT void demand_conf (void); /* config interface(s) for demand-dial */ void demand_block (void); /* set all NPs to queue up packets */ void demand_unblock (void); /* set all NPs to pass packets */ void demand_discard (void); /* set all NPs to discard packets */ void demand_rexmit (int, u32_t); /* retransmit saved frames for an NP*/ int loop_chars (unsigned char *, int); /* process chars from loopback */ int loop_frame (unsigned char *, int); /* should we bring link up? */ #endif /* DEMAND_SUPPORT */ /* Procedures exported from multilink.c */ #ifdef HAVE_MULTILINK void mp_check_options (void); /* Check multilink-related options */ int mp_join_bundle (void); /* join our link to an appropriate bundle */ void mp_exit_bundle (void); /* have disconnected our link from bundle */ void mp_bundle_terminated (void); char *epdisc_to_str (struct epdisc *); /* string from endpoint discrim. */ int str_to_epdisc (struct epdisc *, char *); /* endpt disc. from str */ #else #define mp_bundle_terminated() /* nothing */ #define mp_exit_bundle() /* nothing */ #define doing_multilink 0 #define multilink_master 0 #endif /* Procedures exported from utils.c. */ void ppp_print_string(char *p, int len, void (*printer) (void *, char *, ...), void *arg); /* Format a string for output */ int ppp_slprintf(char *buf, int buflen, char *fmt, ...); /* sprintf++ */ int ppp_vslprintf(char *buf, int buflen, char *fmt, va_list args); /* vsprintf++ */ size_t ppp_strlcpy(char *dest, const char *src, size_t len); /* safe strcpy */ size_t ppp_strlcat(char *dest, const char *src, size_t len); /* safe strncpy */ void ppp_dbglog(char *fmt, ...); /* log a debug message */ void ppp_info(char *fmt, ...); /* log an informational message */ void ppp_notice(char *fmt, ...); /* log a notice-level message */ void ppp_warn(char *fmt, ...); /* log a warning message */ void ppp_error(char *fmt, ...); /* log an error message */ void ppp_fatal(char *fmt, ...); /* log an error message and die(1) */ #if PRINTPKT_SUPPORT void ppp_dump_packet(const char *tag, unsigned char *p, int len); /* dump packet to debug log if interesting */ #endif /* PRINTPKT_SUPPORT */ #endif /* PPP_IMP_H_ */ #endif /* PPP_SUPPORT */ ocproxy-1.60/lwip/src/include/netif/ppp/pppcrypt.h000066400000000000000000000031611303453231400222650ustar00rootroot00000000000000/* * pppcrypt.c - PPP/DES linkage for MS-CHAP and EAP SRP-SHA1 * * Extracted from chap_ms.c by James Carlson. * * Copyright (c) 1995 Eric Rosenquist. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The name(s) of the authors of this software must not be used to * endorse or promote products derived from this software without * prior written permission. * * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "lwip/opt.h" #if PPP_SUPPORT && MSCHAP_SUPPORT /* don't build if not configured for use in lwipopts.h */ #ifndef PPPCRYPT_H #define PPPCRYPT_H void pppcrypt_56_to_64_bit_key(u_char *key, u_char *des_key); #endif /* PPPCRYPT_H */ #endif /* PPP_SUPPORT && MSCHAP_SUPPORT */ ocproxy-1.60/lwip/src/include/netif/ppp/pppdebug.h000066400000000000000000000061161303453231400222150ustar00rootroot00000000000000/***************************************************************************** * pppdebug.h - System debugging utilities. * * Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc. * portions Copyright (c) 1998 Global Election Systems Inc. * portions Copyright (c) 2001 by Cognizant Pty Ltd. * * The authors hereby grant permission to use, copy, modify, distribute, * and license this software and its documentation for any purpose, provided * that existing copyright notices are retained in all copies and that this * notice and the following disclaimer are included verbatim in any * distributions. No written agreement, license, or royalty fee is required * for any of the authorized uses. * * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ****************************************************************************** * REVISION HISTORY (please don't use tabs!) * * 03-01-01 Marc Boucher * Ported to lwIP. * 98-07-29 Guy Lancaster , Global Election Systems Inc. * Original. * ***************************************************************************** */ #include "lwip/opt.h" #if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */ #ifndef PPPDEBUG_H #define PPPDEBUG_H /* Trace levels. */ #define LOG_CRITICAL (PPP_DEBUG | LWIP_DBG_LEVEL_SEVERE) #define LOG_ERR (PPP_DEBUG | LWIP_DBG_LEVEL_SEVERE) #define LOG_NOTICE (PPP_DEBUG | LWIP_DBG_LEVEL_WARNING) #define LOG_WARNING (PPP_DEBUG | LWIP_DBG_LEVEL_WARNING) #define LOG_INFO (PPP_DEBUG) #define LOG_DETAIL (PPP_DEBUG) #define LOG_DEBUG (PPP_DEBUG) #if PPP_DEBUG #define MAINDEBUG(a) LWIP_DEBUGF(LWIP_DBG_LEVEL_WARNING, a) #define SYSDEBUG(a) LWIP_DEBUGF(LWIP_DBG_LEVEL_WARNING, a) #define FSMDEBUG(a) LWIP_DEBUGF(LWIP_DBG_LEVEL_WARNING, a) #define LCPDEBUG(a) LWIP_DEBUGF(LWIP_DBG_LEVEL_WARNING, a) #define IPCPDEBUG(a) LWIP_DEBUGF(LWIP_DBG_LEVEL_WARNING, a) #define IPV6CPDEBUG(a) LWIP_DEBUGF(LWIP_DBG_LEVEL_WARNING, a) #define UPAPDEBUG(a) LWIP_DEBUGF(LWIP_DBG_LEVEL_WARNING, a) #define CHAPDEBUG(a) LWIP_DEBUGF(LWIP_DBG_LEVEL_WARNING, a) #define PPPDEBUG(a, b) LWIP_DEBUGF(a, b) #else /* PPP_DEBUG */ #define MAINDEBUG(a) #define SYSDEBUG(a) #define FSMDEBUG(a) #define LCPDEBUG(a) #define IPCPDEBUG(a) #define IPV6CPDEBUG(a) #define UPAPDEBUG(a) #define CHAPDEBUG(a) #define PPPDEBUG(a, b) #endif /* PPP_DEBUG */ #endif /* PPPDEBUG_H */ #endif /* PPP_SUPPORT */ ocproxy-1.60/lwip/src/include/netif/ppp/pppoe.h000066400000000000000000000167101303453231400215330ustar00rootroot00000000000000/***************************************************************************** * pppoe.h - PPP Over Ethernet implementation for lwIP. * * Copyright (c) 2006 by Marc Boucher, Services Informatiques (MBSI) inc. * * The authors hereby grant permission to use, copy, modify, distribute, * and license this software and its documentation for any purpose, provided * that existing copyright notices are retained in all copies and that this * notice and the following disclaimer are included verbatim in any * distributions. No written agreement, license, or royalty fee is required * for any of the authorized uses. * * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ****************************************************************************** * REVISION HISTORY * * 06-01-01 Marc Boucher * Ported to lwIP. *****************************************************************************/ /* based on NetBSD: if_pppoe.c,v 1.64 2006/01/31 23:50:15 martin Exp */ /*- * Copyright (c) 2002 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Martin Husemann . * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the NetBSD * Foundation, Inc. and its contributors. * 4. Neither the name of The NetBSD Foundation nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include "lwip/opt.h" #if PPP_SUPPORT && PPPOE_SUPPORT /* don't build if not configured for use in lwipopts.h */ #ifndef PPP_OE_H #define PPP_OE_H #include "ppp.h" #include "netif/etharp.h" #ifdef PACK_STRUCT_USE_INCLUDES # include "arch/bpstruct.h" #endif PACK_STRUCT_BEGIN struct pppoehdr { PACK_STRUCT_FIELD(u8_t vertype); PACK_STRUCT_FIELD(u8_t code); PACK_STRUCT_FIELD(u16_t session); PACK_STRUCT_FIELD(u16_t plen); } PACK_STRUCT_STRUCT; PACK_STRUCT_END #ifdef PACK_STRUCT_USE_INCLUDES # include "arch/epstruct.h" #endif #ifdef PACK_STRUCT_USE_INCLUDES # include "arch/bpstruct.h" #endif PACK_STRUCT_BEGIN struct pppoetag { PACK_STRUCT_FIELD(u16_t tag); PACK_STRUCT_FIELD(u16_t len); } PACK_STRUCT_STRUCT; PACK_STRUCT_END #ifdef PACK_STRUCT_USE_INCLUDES # include "arch/epstruct.h" #endif #define PPPOE_STATE_INITIAL 0 #define PPPOE_STATE_PADI_SENT 1 #define PPPOE_STATE_PADR_SENT 2 #define PPPOE_STATE_SESSION 3 /* passive */ #define PPPOE_STATE_PADO_SENT 1 #define PPPOE_CB_STATE_UP 0 /* PPPoE link is UP */ #define PPPOE_CB_STATE_DOWN 1 /* PPPoE link is DOWN - normal condition */ #define PPPOE_CB_STATE_FAILED 2 /* Failed to setup PPPoE link */ #define PPPOE_HEADERLEN sizeof(struct pppoehdr) #define PPPOE_VERTYPE 0x11 /* VER=1, TYPE = 1 */ #define PPPOE_TAG_EOL 0x0000 /* end of list */ #define PPPOE_TAG_SNAME 0x0101 /* service name */ #define PPPOE_TAG_ACNAME 0x0102 /* access concentrator name */ #define PPPOE_TAG_HUNIQUE 0x0103 /* host unique */ #define PPPOE_TAG_ACCOOKIE 0x0104 /* AC cookie */ #define PPPOE_TAG_VENDOR 0x0105 /* vendor specific */ #define PPPOE_TAG_RELAYSID 0x0110 /* relay session id */ #define PPPOE_TAG_SNAME_ERR 0x0201 /* service name error */ #define PPPOE_TAG_ACSYS_ERR 0x0202 /* AC system error */ #define PPPOE_TAG_GENERIC_ERR 0x0203 /* gerneric error */ #define PPPOE_CODE_PADI 0x09 /* Active Discovery Initiation */ #define PPPOE_CODE_PADO 0x07 /* Active Discovery Offer */ #define PPPOE_CODE_PADR 0x19 /* Active Discovery Request */ #define PPPOE_CODE_PADS 0x65 /* Active Discovery Session confirmation */ #define PPPOE_CODE_PADT 0xA7 /* Active Discovery Terminate */ #ifndef PPPOE_MAX_AC_COOKIE_LEN #define PPPOE_MAX_AC_COOKIE_LEN 64 #endif struct pppoe_softc { struct pppoe_softc *next; struct netif *sc_ethif; /* ethernet interface we are using */ ppp_pcb *pcb; /* PPP PCB */ void (*sc_link_status_cb)(ppp_pcb *pcb, int up); struct eth_addr sc_dest; /* hardware address of concentrator */ u16_t sc_session; /* PPPoE session id */ u8_t sc_state; /* discovery phase or session connected */ #ifdef PPPOE_TODO u8_t *sc_service_name; /* if != NULL: requested name of service */ u8_t *sc_concentrator_name; /* if != NULL: requested concentrator id */ #endif /* PPPOE_TODO */ u8_t sc_ac_cookie[PPPOE_MAX_AC_COOKIE_LEN]; /* content of AC cookie we must echo back */ u8_t sc_ac_cookie_len; /* length of cookie data */ #ifdef PPPOE_SERVER u8_t *sc_hunique; /* content of host unique we must echo back */ u8_t sc_hunique_len; /* length of host unique */ #endif u8_t sc_padi_retried; /* number of PADI retries already done */ u8_t sc_padr_retried; /* number of PADR retries already done */ }; #define pppoe_init() /* compatibility define, no initialization needed */ err_t pppoe_create(struct netif *ethif, ppp_pcb *pcb, void (*link_status_cb)(ppp_pcb *pcb, int up), struct pppoe_softc **scptr); err_t pppoe_destroy(struct pppoe_softc *sc); int pppoe_connect(struct pppoe_softc *sc); void pppoe_disconnect(struct pppoe_softc *sc); void pppoe_disc_input(struct netif *netif, struct pbuf *p); void pppoe_data_input(struct netif *netif, struct pbuf *p); err_t pppoe_xmit(struct pppoe_softc *sc, struct pbuf *pb); #endif /* PPP_OE_H */ #endif /* PPP_SUPPORT && PPPOE_SUPPORT */ ocproxy-1.60/lwip/src/include/netif/ppp/pppol2tp.h000066400000000000000000000222561303453231400221720ustar00rootroot00000000000000/** * @file * Network Point to Point Protocol over Layer 2 Tunneling Protocol header file. * */ /* * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * */ #include "lwip/opt.h" #if PPP_SUPPORT && PPPOL2TP_SUPPORT /* don't build if not configured for use in lwipopts.h */ #ifndef PPPOL2TP_H_ #define PPPOL2TP_H_ #include "ppp.h" /* Timeout */ #define PPPOL2TP_CONTROL_TIMEOUT (5*1000) /* base for quick timeout calculation */ #define PPPOL2TP_SLOW_RETRY (60*1000) /* persistent retry interval */ #define PPPOL2TP_MAXSCCRQ 4 /* retry SCCRQ four times (quickly) */ #define PPPOL2TP_MAXICRQ 4 /* retry IRCQ four times */ #define PPPOL2TP_MAXICCN 4 /* retry ICCN four times */ /* L2TP header flags */ #define PPPOL2TP_HEADERFLAG_CONTROL 0x8000 #define PPPOL2TP_HEADERFLAG_LENGTH 0x4000 #define PPPOL2TP_HEADERFLAG_SEQUENCE 0x0800 #define PPPOL2TP_HEADERFLAG_OFFSET 0x0200 #define PPPOL2TP_HEADERFLAG_PRIORITY 0x0100 #define PPPOL2TP_HEADERFLAG_VERSION 0x0002 /* Mandatory bits for control: Control, Length, Sequence, Version 2 */ #define PPPOL2TP_HEADERFLAG_CONTROL_MANDATORY (PPPOL2TP_HEADERFLAG_CONTROL|PPPOL2TP_HEADERFLAG_LENGTH|PPPOL2TP_HEADERFLAG_SEQUENCE|PPPOL2TP_HEADERFLAG_VERSION) /* Forbidden bits for control: Offset, Priority */ #define PPPOL2TP_HEADERFLAG_CONTROL_FORBIDDEN (PPPOL2TP_HEADERFLAG_OFFSET|PPPOL2TP_HEADERFLAG_PRIORITY) /* Mandatory bits for data: Version 2 */ #define PPPOL2TP_HEADERFLAG_DATA_MANDATORY (PPPOL2TP_HEADERFLAG_VERSION) /* AVP (Attribute Value Pair) header */ #define PPPOL2TP_AVPHEADERFLAG_MANDATORY 0x8000 #define PPPOL2TP_AVPHEADERFLAG_HIDDEN 0x4000 #define PPPOL2TP_AVPHEADERFLAG_LENGTHMASK 0x03ff /* -- AVP - Message type */ #define PPPOL2TP_AVPTYPE_MESSAGE 0 /* Message type */ /* Control Connection Management */ #define PPPOL2TP_MESSAGETYPE_SCCRQ 1 /* Start Control Connection Request */ #define PPPOL2TP_MESSAGETYPE_SCCRP 2 /* Start Control Connection Reply */ #define PPPOL2TP_MESSAGETYPE_SCCCN 3 /* Start Control Connection Connected */ #define PPPOL2TP_MESSAGETYPE_STOPCCN 4 /* Stop Control Connection Notification */ #define PPPOL2TP_MESSAGETYPE_HELLO 6 /* Hello */ /* Call Management */ #define PPPOL2TP_MESSAGETYPE_OCRQ 7 /* Outgoing Call Request */ #define PPPOL2TP_MESSAGETYPE_OCRP 8 /* Outgoing Call Reply */ #define PPPOL2TP_MESSAGETYPE_OCCN 9 /* Outgoing Call Connected */ #define PPPOL2TP_MESSAGETYPE_ICRQ 10 /* Incoming Call Request */ #define PPPOL2TP_MESSAGETYPE_ICRP 11 /* Incoming Call Reply */ #define PPPOL2TP_MESSAGETYPE_ICCN 12 /* Incoming Call Connected */ #define PPPOL2TP_MESSAGETYPE_CDN 14 /* Call Disconnect Notify */ /* Error reporting */ #define PPPOL2TP_MESSAGETYPE_WEN 15 /* WAN Error Notify */ /* PPP Session Control */ #define PPPOL2TP_MESSAGETYPE_SLI 16 /* Set Link Info */ /* -- AVP - Result code */ #define PPPOL2TP_AVPTYPE_RESULTCODE 1 /* Result code */ #define PPPOL2TP_RESULTCODE 1 /* General request to clear control connection */ /* -- AVP - Protocol version (!= L2TP Header version) */ #define PPPOL2TP_AVPTYPE_VERSION 2 #define PPPOL2TP_VERSION 0x0100 /* L2TP Protocol version 1, revision 0 */ /* -- AVP - Framing capabilities */ #define PPPOL2TP_AVPTYPE_FRAMINGCAPABILITIES 3 /* Bearer capabilities */ #define PPPOL2TP_FRAMINGCAPABILITIES 0x00000003 /* Async + Sync framing */ /* -- AVP - Bearer capabilities */ #define PPPOL2TP_AVPTYPE_BEARERCAPABILITIES 4 /* Bearer capabilities */ #define PPPOL2TP_BEARERCAPABILITIES 0x00000003 /* Analog + Digital Access */ /* -- AVP - Tie breaker */ #define PPPOL2TP_AVPTYPE_TIEBREAKER 5 /* -- AVP - Host name */ #define PPPOL2TP_AVPTYPE_HOSTNAME 7 /* Host name */ #define PPPOL2TP_HOSTNAME "lwIP" /* FIXME: make it configurable */ /* -- AVP - Vendor name */ #define PPPOL2TP_AVPTYPE_VENDORNAME 8 /* Vendor name */ #define PPPOL2TP_VENDORNAME "lwIP" /* FIXME: make it configurable */ /* -- AVP - Assign tunnel ID */ #define PPPOL2TP_AVPTYPE_TUNNELID 9 /* Assign Tunnel ID */ /* -- AVP - Receive window size */ #define PPPOL2TP_AVPTYPE_RECEIVEWINDOWSIZE 10 /* Receive window size */ #define PPPOL2TP_RECEIVEWINDOWSIZE 8 /* FIXME: make it configurable */ /* -- AVP - Challenge */ #define PPPOL2TP_AVPTYPE_CHALLENGE 11 /* Challenge */ /* -- AVP - Cause code */ #define PPPOL2TP_AVPTYPE_CAUSECODE 12 /* Cause code*/ /* -- AVP - Challenge response */ #define PPPOL2TP_AVPTYPE_CHALLENGERESPONSE 13 /* Challenge response */ #define PPPOL2TP_AVPTYPE_CHALLENGERESPONSE_SIZE 16 /* -- AVP - Assign session ID */ #define PPPOL2TP_AVPTYPE_SESSIONID 14 /* Assign Session ID */ /* -- AVP - Call serial number */ #define PPPOL2TP_AVPTYPE_CALLSERIALNUMBER 15 /* Call Serial Number */ /* -- AVP - Framing type */ #define PPPOL2TP_AVPTYPE_FRAMINGTYPE 19 /* Framing Type */ #define PPPOL2TP_FRAMINGTYPE 0x00000001 /* Sync framing */ /* -- AVP - TX Connect Speed */ #define PPPOL2TP_AVPTYPE_TXCONNECTSPEED 24 /* TX Connect Speed */ #define PPPOL2TP_TXCONNECTSPEED 100000000 /* Connect speed: 100 Mbits/s */ /* L2TP Session state */ #define PPPOL2TP_STATE_INITIAL 0 #define PPPOL2TP_STATE_SCCRQ_SENT 1 #define PPPOL2TP_STATE_ICRQ_SENT 2 #define PPPOL2TP_STATE_ICCN_SENT 3 #define PPPOL2TP_STATE_DATA 4 #define PPPOL2TP_CB_STATE_UP 0 /* PPPoL2TP link is UP */ #define PPPOL2TP_CB_STATE_DOWN 1 /* PPPo2TP link is DOWN - normal condition */ #define PPPOL2TP_CB_STATE_FAILED 2 /* Failed to setup PPPo2TP link */ #define PPPOL2TP_OUTPUT_DATA_HEADER_LEN 6 /* Our data header len */ /* * PPPoL2TP interface control block. */ typedef struct pppol2tp_pcb_s pppol2tp_pcb; struct pppol2tp_pcb_s { ppp_pcb *ppp; /* PPP PCB */ u8_t phase; /* L2TP phase */ void (*link_status_cb)(ppp_pcb *pcb, int status); struct udp_pcb *udp; /* UDP L2TP Socket */ struct netif *netif; /* Output interface, used as a default route */ ip_addr_t remote_ip; /* LNS IP Address */ u16_t remote_port; /* LNS port */ #if PPPOL2TP_AUTH_SUPPORT u8_t *secret; /* Secret string */ u8_t secret_len; /* Secret string length */ u8_t secret_rv[16]; /* Random vector */ u8_t challenge_hash[16]; /* Challenge response */ u8_t send_challenge; /* Boolean whether the next sent packet should contains a challenge response */ #endif /* PPPOL2TP_AUTH_SUPPORT */ u16_t tunnel_port; /* Tunnel port */ u16_t our_ns; /* NS to peer */ u16_t peer_nr; /* NR from peer */ u16_t peer_ns; /* NS from peer */ u16_t source_tunnel_id; /* Tunnel ID assigned by peer */ u16_t remote_tunnel_id; /* Tunnel ID assigned to peer */ u16_t source_session_id; /* Session ID assigned by peer */ u16_t remote_session_id; /* Session ID assigned to peer */ u8_t sccrq_retried; /* number of SCCRQ retries already done */ u8_t icrq_retried; /* number of ICRQ retries already done */ u8_t iccn_retried; /* number of ICCN retries already done */ }; /* Create a new L2TP session. */ err_t pppol2tp_create(ppp_pcb *ppp, void (*link_status_cb)(ppp_pcb *pcb, int status), pppol2tp_pcb **l2tpptr, struct netif *netif, ip_addr_t *ipaddr, u16_t port, u8_t *secret, u8_t secret_len); /* Destroy a L2TP control block */ err_t pppol2tp_destroy(pppol2tp_pcb *l2tp); /* Be a LAC, connect to a LNS. */ err_t pppol2tp_connect(pppol2tp_pcb *l2tp); /* Disconnect */ void pppol2tp_disconnect(pppol2tp_pcb *l2tp); /* Data packet from PPP to L2TP */ err_t pppol2tp_xmit(pppol2tp_pcb *l2tp, struct pbuf *pb); #endif /* PPPOL2TP_H_ */ #endif /* PPP_SUPPORT && PPPOL2TP_SUPPORT */ ocproxy-1.60/lwip/src/include/netif/ppp/upap.h000066400000000000000000000076741303453231400213660ustar00rootroot00000000000000/* * upap.h - User/Password Authentication Protocol definitions. * * Copyright (c) 1984-2000 Carnegie Mellon University. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The name "Carnegie Mellon University" must not be used to * endorse or promote products derived from this software without * prior written permission. For permission or any legal * details, please contact * Office of Technology Transfer * Carnegie Mellon University * 5000 Forbes Avenue * Pittsburgh, PA 15213-3890 * (412) 268-4387, fax: (412) 268-7395 * tech-transfer@andrew.cmu.edu * * 4. Redistributions of any form whatsoever must retain the following * acknowledgment: * "This product includes software developed by Computing Services * at Carnegie Mellon University (http://www.cmu.edu/computing/)." * * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * $Id: upap.h,v 1.8 2002/12/04 23:03:33 paulus Exp $ */ #include "lwip/opt.h" #if PPP_SUPPORT && PAP_SUPPORT /* don't build if not configured for use in lwipopts.h */ #ifndef UPAP_H #define UPAP_H #include "ppp.h" /* * Packet header = Code, id, length. */ #define UPAP_HEADERLEN 4 /* * UPAP codes. */ #define UPAP_AUTHREQ 1 /* Authenticate-Request */ #define UPAP_AUTHACK 2 /* Authenticate-Ack */ #define UPAP_AUTHNAK 3 /* Authenticate-Nak */ /* * Client states. */ #define UPAPCS_INITIAL 0 /* Connection down */ #define UPAPCS_CLOSED 1 /* Connection up, haven't requested auth */ #define UPAPCS_PENDING 2 /* Connection down, have requested auth */ #define UPAPCS_AUTHREQ 3 /* We've sent an Authenticate-Request */ #define UPAPCS_OPEN 4 /* We've received an Ack */ #define UPAPCS_BADAUTH 5 /* We've received a Nak */ /* * Server states. */ #define UPAPSS_INITIAL 0 /* Connection down */ #define UPAPSS_CLOSED 1 /* Connection up, haven't requested auth */ #define UPAPSS_PENDING 2 /* Connection down, have requested auth */ #define UPAPSS_LISTEN 3 /* Listening for an Authenticate */ #define UPAPSS_OPEN 4 /* We've sent an Ack */ #define UPAPSS_BADAUTH 5 /* We've sent a Nak */ /* * Timeouts. */ #if 0 /* moved to opt.h */ #define UPAP_DEFTIMEOUT 3 /* Timeout (seconds) for retransmitting req */ #define UPAP_DEFREQTIME 30 /* Time to wait for auth-req from peer */ #endif /* moved to opt.h */ /* * Each interface is described by upap structure. */ #if PAP_SUPPORT typedef struct upap_state { char *us_user; /* User */ u8_t us_userlen; /* User length */ char *us_passwd; /* Password */ u8_t us_passwdlen; /* Password length */ u8_t us_clientstate; /* Client state */ #if PPP_SERVER u8_t us_serverstate; /* Server state */ #endif /* PPP_SERVER */ u8_t us_id; /* Current id */ u8_t us_transmits; /* Number of auth-reqs sent */ } upap_state; #endif /* PAP_SUPPORT */ void upap_authwithpeer(ppp_pcb *pcb, char *user, char *password); #if PPP_SERVER void upap_authpeer(ppp_pcb *pcb); #endif /* PPP_SERVER */ extern const struct protent pap_protent; #endif /* UPAP_H */ #endif /* PPP_SUPPORT && PAP_SUPPORT */ ocproxy-1.60/lwip/src/include/netif/ppp/vj.h000066400000000000000000000143221303453231400210240ustar00rootroot00000000000000/* * Definitions for tcp compression routines. * * $Id: vj.h,v 1.7 2010/02/22 17:52:09 goldsimon Exp $ * * Copyright (c) 1989 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms are permitted * provided that the above copyright notice and this paragraph are * duplicated in all such forms and that any documentation, * advertising materials, and other materials related to such * distribution and use acknowledge that the software was developed * by the University of California, Berkeley. The name of the * University may not be used to endorse or promote products derived * from this software without specific prior written permission. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. * * Van Jacobson (van@helios.ee.lbl.gov), Dec 31, 1989: * - Initial distribution. */ #include "lwip/opt.h" #if PPP_SUPPORT && VJ_SUPPORT /* don't build if not configured for use in lwipopts.h */ #ifndef VJ_H #define VJ_H #include "lwip/ip.h" #include "lwip/tcp_impl.h" #define MAX_SLOTS 16 /* must be > 2 and < 256 */ #define MAX_HDR 128 /* * Compressed packet format: * * The first octet contains the packet type (top 3 bits), TCP * 'push' bit, and flags that indicate which of the 4 TCP sequence * numbers have changed (bottom 5 bits). The next octet is a * conversation number that associates a saved IP/TCP header with * the compressed packet. The next two octets are the TCP checksum * from the original datagram. The next 0 to 15 octets are * sequence number changes, one change per bit set in the header * (there may be no changes and there are two special cases where * the receiver implicitly knows what changed -- see below). * * There are 5 numbers which can change (they are always inserted * in the following order): TCP urgent pointer, window, * acknowlegement, sequence number and IP ID. (The urgent pointer * is different from the others in that its value is sent, not the * change in value.) Since typical use of SLIP links is biased * toward small packets (see comments on MTU/MSS below), changes * use a variable length coding with one octet for numbers in the * range 1 - 255 and 3 octets (0, MSB, LSB) for numbers in the * range 256 - 65535 or 0. (If the change in sequence number or * ack is more than 65535, an uncompressed packet is sent.) */ /* * Packet types (must not conflict with IP protocol version) * * The top nibble of the first octet is the packet type. There are * three possible types: IP (not proto TCP or tcp with one of the * control flags set); uncompressed TCP (a normal IP/TCP packet but * with the 8-bit protocol field replaced by an 8-bit connection id -- * this type of packet syncs the sender & receiver); and compressed * TCP (described above). * * LSB of 4-bit field is TCP "PUSH" bit (a worthless anachronism) and * is logically part of the 4-bit "changes" field that follows. Top * three bits are actual packet type. For backward compatibility * and in the interest of conserving bits, numbers are chosen so the * IP protocol version number (4) which normally appears in this nibble * means "IP packet". */ /* packet types */ #define TYPE_IP 0x40 #define TYPE_UNCOMPRESSED_TCP 0x70 #define TYPE_COMPRESSED_TCP 0x80 #define TYPE_ERROR 0x00 /* Bits in first octet of compressed packet */ #define NEW_C 0x40 /* flag bits for what changed in a packet */ #define NEW_I 0x20 #define NEW_S 0x08 #define NEW_A 0x04 #define NEW_W 0x02 #define NEW_U 0x01 /* reserved, special-case values of above */ #define SPECIAL_I (NEW_S|NEW_W|NEW_U) /* echoed interactive traffic */ #define SPECIAL_D (NEW_S|NEW_A|NEW_W|NEW_U) /* unidirectional data */ #define SPECIALS_MASK (NEW_S|NEW_A|NEW_W|NEW_U) #define TCP_PUSH_BIT 0x10 /* * "state" data for each active tcp conversation on the wire. This is * basically a copy of the entire IP/TCP header from the last packet * we saw from the conversation together with a small identifier * the transmit & receive ends of the line use to locate saved header. */ struct cstate { struct cstate *cs_next; /* next most recently used state (xmit only) */ u_short cs_hlen; /* size of hdr (receive only) */ u_char cs_id; /* connection # associated with this state */ u_char cs_filler; union { char csu_hdr[MAX_HDR]; struct ip_hdr csu_ip; /* ip/tcp hdr from most recent packet */ } vjcs_u; }; #define cs_ip vjcs_u.csu_ip #define cs_hdr vjcs_u.csu_hdr struct vjstat { unsigned long vjs_packets; /* outbound packets */ unsigned long vjs_compressed; /* outbound compressed packets */ unsigned long vjs_searches; /* searches for connection state */ unsigned long vjs_misses; /* times couldn't find conn. state */ unsigned long vjs_uncompressedin; /* inbound uncompressed packets */ unsigned long vjs_compressedin; /* inbound compressed packets */ unsigned long vjs_errorin; /* inbound unknown type packets */ unsigned long vjs_tossed; /* inbound packets tossed because of error */ }; /* * all the state data for one serial line (we need one of these per line). */ struct vjcompress { struct cstate *last_cs; /* most recently used tstate */ u_char last_recv; /* last rcvd conn. id */ u_char last_xmit; /* last sent conn. id */ u_short flags; u_char maxSlotIndex; u_char compressSlot; /* Flag indicating OK to compress slot ID. */ #if LINK_STATS struct vjstat stats; #endif struct cstate tstate[MAX_SLOTS]; /* xmit connection states */ struct cstate rstate[MAX_SLOTS]; /* receive connection states */ }; /* flag values */ #define VJF_TOSS 1U /* tossing rcvd frames because of input err */ extern void vj_compress_init (struct vjcompress *comp); extern u_int vj_compress_tcp (struct vjcompress *comp, struct pbuf *pb); extern void vj_uncompress_err (struct vjcompress *comp); extern int vj_uncompress_uncomp(struct pbuf *nb, struct vjcompress *comp); extern int vj_uncompress_tcp (struct pbuf **nb, struct vjcompress *comp); #endif /* VJ_H */ #endif /* PPP_SUPPORT && VJ_SUPPORT */ ocproxy-1.60/lwip/src/include/netif/slipif.h000066400000000000000000000060071303453231400210750ustar00rootroot00000000000000/* * Copyright (c) 2001, Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the Institute nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #ifndef LWIP_HDR_NETIF_SLIPIF_H #define LWIP_HDR_NETIF_SLIPIF_H #include "lwip/opt.h" #include "lwip/netif.h" /** Set this to 1 to start a thread that blocks reading on the serial line * (using sio_read()). */ #ifndef SLIP_USE_RX_THREAD #define SLIP_USE_RX_THREAD !NO_SYS #endif /** Set this to 1 to enable functions to pass in RX bytes from ISR context. * If enabled, slipif_received_byte[s]() process incoming bytes and put assembled * packets on a queue, which is fed into lwIP from slipif_poll(). * If disabled, slipif_poll() polls the serila line (using sio_tryread()). */ #ifndef SLIP_RX_FROM_ISR #define SLIP_RX_FROM_ISR 0 #endif /** Set this to 1 (default for SLIP_RX_FROM_ISR) to queue incoming packets * received by slipif_received_byte[s]() as long as PBUF_POOL pbufs are available. * If disabled, packets will be dropped if more than one packet is received. */ #ifndef SLIP_RX_QUEUE #define SLIP_RX_QUEUE SLIP_RX_FROM_ISR #endif #ifdef __cplusplus extern "C" { #endif err_t slipif_init(struct netif * netif); void slipif_poll(struct netif *netif); #if SLIP_RX_FROM_ISR void slipif_process_rxqueue(struct netif *netif); void slipif_received_byte(struct netif *netif, u8_t data); void slipif_received_bytes(struct netif *netif, u8_t *data, u8_t len); #endif /* SLIP_RX_FROM_ISR */ #ifdef __cplusplus } #endif #endif /* LWIP_HDR_NETIF_SLIPIF_H */ ocproxy-1.60/lwip/src/include/posix/000077500000000000000000000000001303453231400174705ustar00rootroot00000000000000ocproxy-1.60/lwip/src/include/posix/netdb.h000066400000000000000000000030331303453231400207340ustar00rootroot00000000000000/** * @file * This file is a posix wrapper for lwip/netdb.h. */ /* * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * */ #include "lwip/netdb.h" ocproxy-1.60/lwip/src/include/posix/sys/000077500000000000000000000000001303453231400203065ustar00rootroot00000000000000ocproxy-1.60/lwip/src/include/posix/sys/socket.h000066400000000000000000000030371303453231400217520ustar00rootroot00000000000000/** * @file * This file is a posix wrapper for lwip/sockets.h. */ /* * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * */ #include "lwip/sockets.h" ocproxy-1.60/lwip/src/netif/000077500000000000000000000000001303453231400160105ustar00rootroot00000000000000ocproxy-1.60/lwip/src/netif/FILES000066400000000000000000000024661303453231400166050ustar00rootroot00000000000000This directory contains generic network interface device drivers that do not contain any hardware or architecture specific code. The files are: etharp.c Implements the ARP (Address Resolution Protocol) over Ethernet. The code in this file should be used together with Ethernet device drivers. Note that this module has been largely made Ethernet independent so you should be able to adapt this for other link layers (such as Firewire). ethernetif.c An example of how an Ethernet device driver could look. This file can be used as a "skeleton" for developing new Ethernet network device drivers. It uses the etharp.c ARP code. loopif.c A "loopback" network interface driver. It requires configuration through the define LWIP_LOOPIF_MULTITHREADING (see opt.h). slipif.c A generic implementation of the SLIP (Serial Line IP) protocol. It requires a sio (serial I/O) module to work. ppp/ Point-to-Point Protocol stack The PPP stack has been ported from ucip (http://ucip.sourceforge.net). It matches quite well to pppd 2.3.1 (http://ppp.samba.org), although compared to that, it has some modifications for embedded systems and the source code has been reordered a bit.ocproxy-1.60/lwip/src/netif/etharp.c000066400000000000000000001543311303453231400174460ustar00rootroot00000000000000/** * @file * Address Resolution Protocol module for IP over Ethernet * * Functionally, ARP is divided into two parts. The first maps an IP address * to a physical address when sending a packet, and the second part answers * requests from other machines for our physical address. * * This implementation complies with RFC 826 (Ethernet ARP). It supports * Gratuitious ARP from RFC3220 (IP Mobility Support for IPv4) section 4.6 * if an interface calls etharp_gratuitous(our_netif) upon address change. */ /* * Copyright (c) 2001-2003 Swedish Institute of Computer Science. * Copyright (c) 2003-2004 Leon Woestenberg * Copyright (c) 2003-2004 Axon Digital Design B.V., The Netherlands. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * */ #include "lwip/opt.h" #if LWIP_ARP || LWIP_ETHERNET #include "lwip/ip_addr.h" #include "lwip/def.h" #include "lwip/ip.h" #include "lwip/stats.h" #include "lwip/snmp.h" #include "lwip/dhcp.h" #include "lwip/autoip.h" #include "netif/etharp.h" #include "lwip/ip6.h" #if PPPOE_SUPPORT #include "netif/ppp/pppoe.h" #endif /* PPPOE_SUPPORT */ #include const struct eth_addr ethbroadcast = {{0xff,0xff,0xff,0xff,0xff,0xff}}; const struct eth_addr ethzero = {{0,0,0,0,0,0}}; /** The 24-bit IANA multicast OUI is 01-00-5e: */ #define LL_MULTICAST_ADDR_0 0x01 #define LL_MULTICAST_ADDR_1 0x00 #define LL_MULTICAST_ADDR_2 0x5e #if LWIP_ARP /* don't build if not configured for use in lwipopts.h */ /** the time an ARP entry stays valid after its last update, * for ARP_TMR_INTERVAL = 1000, this is * (60 * 20) seconds = 20 minutes. */ #define ARP_MAXAGE 1200 /** Re-request a used ARP entry 1 minute before it would expire to prevent * breaking a steadily used connection because the ARP entry timed out. */ #define ARP_AGE_REREQUEST_USED (ARP_MAXAGE - 60) /** the time an ARP entry stays pending after first request, * for ARP_TMR_INTERVAL = 1000, this is * 10 seconds. * * @internal Keep this number at least 2, otherwise it might * run out instantly if the timeout occurs directly after a request. */ #define ARP_MAXPENDING 5 #define HWTYPE_ETHERNET 1 enum etharp_state { ETHARP_STATE_EMPTY = 0, ETHARP_STATE_PENDING, ETHARP_STATE_STABLE, ETHARP_STATE_STABLE_REREQUESTING #if ETHARP_SUPPORT_STATIC_ENTRIES ,ETHARP_STATE_STATIC #endif /* ETHARP_SUPPORT_STATIC_ENTRIES */ }; struct etharp_entry { #if ARP_QUEUEING /** Pointer to queue of pending outgoing packets on this ARP entry. */ struct etharp_q_entry *q; #else /* ARP_QUEUEING */ /** Pointer to a single pending outgoing packet on this ARP entry. */ struct pbuf *q; #endif /* ARP_QUEUEING */ ip_addr_t ipaddr; struct netif *netif; struct eth_addr ethaddr; u16_t ctime; u8_t state; }; static struct etharp_entry arp_table[ARP_TABLE_SIZE]; #if !LWIP_NETIF_HWADDRHINT static u8_t etharp_cached_entry; #endif /* !LWIP_NETIF_HWADDRHINT */ /** Try hard to create a new entry - we want the IP address to appear in the cache (even if this means removing an active entry or so). */ #define ETHARP_FLAG_TRY_HARD 1 #define ETHARP_FLAG_FIND_ONLY 2 #if ETHARP_SUPPORT_STATIC_ENTRIES #define ETHARP_FLAG_STATIC_ENTRY 4 #endif /* ETHARP_SUPPORT_STATIC_ENTRIES */ #if LWIP_NETIF_HWADDRHINT #define ETHARP_SET_HINT(netif, hint) if (((netif) != NULL) && ((netif)->addr_hint != NULL)) \ *((netif)->addr_hint) = (hint); #else /* LWIP_NETIF_HWADDRHINT */ #define ETHARP_SET_HINT(netif, hint) (etharp_cached_entry = (hint)) #endif /* LWIP_NETIF_HWADDRHINT */ /* Some checks, instead of etharp_init(): */ #if (LWIP_ARP && (ARP_TABLE_SIZE > 0x7f)) #error "ARP_TABLE_SIZE must fit in an s8_t, you have to reduce it in your lwipopts.h" #endif #if ARP_QUEUEING /** * Free a complete queue of etharp entries * * @param q a qeueue of etharp_q_entry's to free */ static void free_etharp_q(struct etharp_q_entry *q) { struct etharp_q_entry *r; LWIP_ASSERT("q != NULL", q != NULL); LWIP_ASSERT("q->p != NULL", q->p != NULL); while (q) { r = q; q = q->next; LWIP_ASSERT("r->p != NULL", (r->p != NULL)); pbuf_free(r->p); memp_free(MEMP_ARP_QUEUE, r); } } #else /* ARP_QUEUEING */ /** Compatibility define: free the queued pbuf */ #define free_etharp_q(q) pbuf_free(q) #endif /* ARP_QUEUEING */ /** Clean up ARP table entries */ static void etharp_free_entry(int i) { /* remove from SNMP ARP index tree */ snmp_delete_arpidx_tree(arp_table[i].netif, &arp_table[i].ipaddr); /* and empty packet queue */ if (arp_table[i].q != NULL) { /* remove all queued packets */ LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_free_entry: freeing entry %"U16_F", packet queue %p.\n", (u16_t)i, (void *)(arp_table[i].q))); free_etharp_q(arp_table[i].q); arp_table[i].q = NULL; } /* recycle entry for re-use */ arp_table[i].state = ETHARP_STATE_EMPTY; #ifdef LWIP_DEBUG /* for debugging, clean out the complete entry */ arp_table[i].ctime = 0; arp_table[i].netif = NULL; ip_addr_set_zero(&arp_table[i].ipaddr); arp_table[i].ethaddr = ethzero; #endif /* LWIP_DEBUG */ } /** * Clears expired entries in the ARP table. * * This function should be called every ETHARP_TMR_INTERVAL milliseconds (5 seconds), * in order to expire entries in the ARP table. */ void etharp_tmr(void) { u8_t i; LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer\n")); /* remove expired entries from the ARP table */ for (i = 0; i < ARP_TABLE_SIZE; ++i) { u8_t state = arp_table[i].state; if (state != ETHARP_STATE_EMPTY #if ETHARP_SUPPORT_STATIC_ENTRIES && (state != ETHARP_STATE_STATIC) #endif /* ETHARP_SUPPORT_STATIC_ENTRIES */ ) { arp_table[i].ctime++; if ((arp_table[i].ctime >= ARP_MAXAGE) || ((arp_table[i].state == ETHARP_STATE_PENDING) && (arp_table[i].ctime >= ARP_MAXPENDING))) { /* pending or stable entry has become old! */ LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer: expired %s entry %"U16_F".\n", arp_table[i].state >= ETHARP_STATE_STABLE ? "stable" : "pending", (u16_t)i)); /* clean up entries that have just been expired */ etharp_free_entry(i); } else if (arp_table[i].state == ETHARP_STATE_STABLE_REREQUESTING) { /* Reset state to stable, so that the next transmitted packet will re-send an ARP request. */ arp_table[i].state = ETHARP_STATE_STABLE; } /* still pending entry? (not expired) */ else if (arp_table[i].state == ETHARP_STATE_PENDING) { /* resend an ARP query here? */ if (etharp_request(arp_table[i].netif, &arp_table[i].ipaddr) != ERR_OK) { } } } } } /** * Search the ARP table for a matching or new entry. * * If an IP address is given, return a pending or stable ARP entry that matches * the address. If no match is found, create a new entry with this address set, * but in state ETHARP_EMPTY. The caller must check and possibly change the * state of the returned entry. * * If ipaddr is NULL, return a initialized new entry in state ETHARP_EMPTY. * * In all cases, attempt to create new entries from an empty entry. If no * empty entries are available and ETHARP_FLAG_TRY_HARD flag is set, recycle * old entries. Heuristic choose the least important entry for recycling. * * @param ipaddr IP address to find in ARP cache, or to add if not found. * @param flags @see definition of ETHARP_FLAG_* * @param netif netif related to this address (used for NETIF_HWADDRHINT) * * @return The ARP entry index that matched or is created, ERR_MEM if no * entry is found or could be recycled. */ static s8_t etharp_find_entry(ip_addr_t *ipaddr, u8_t flags) { s8_t old_pending = ARP_TABLE_SIZE, old_stable = ARP_TABLE_SIZE; s8_t empty = ARP_TABLE_SIZE; u8_t i = 0, age_pending = 0, age_stable = 0; /* oldest entry with packets on queue */ s8_t old_queue = ARP_TABLE_SIZE; /* its age */ u8_t age_queue = 0; /** * a) do a search through the cache, remember candidates * b) select candidate entry * c) create new entry */ /* a) in a single search sweep, do all of this * 1) remember the first empty entry (if any) * 2) remember the oldest stable entry (if any) * 3) remember the oldest pending entry without queued packets (if any) * 4) remember the oldest pending entry with queued packets (if any) * 5) search for a matching IP entry, either pending or stable * until 5 matches, or all entries are searched for. */ for (i = 0; i < ARP_TABLE_SIZE; ++i) { u8_t state = arp_table[i].state; /* no empty entry found yet and now we do find one? */ if ((empty == ARP_TABLE_SIZE) && (state == ETHARP_STATE_EMPTY)) { LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_find_entry: found empty entry %"U16_F"\n", (u16_t)i)); /* remember first empty entry */ empty = i; } else if (state != ETHARP_STATE_EMPTY) { LWIP_ASSERT("state == ETHARP_STATE_PENDING || state >= ETHARP_STATE_STABLE", state == ETHARP_STATE_PENDING || state >= ETHARP_STATE_STABLE); /* if given, does IP address match IP address in ARP entry? */ if (ipaddr && ip_addr_cmp(ipaddr, &arp_table[i].ipaddr)) { LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_find_entry: found matching entry %"U16_F"\n", (u16_t)i)); /* found exact IP address match, simply bail out */ return i; } /* pending entry? */ if (state == ETHARP_STATE_PENDING) { /* pending with queued packets? */ if (arp_table[i].q != NULL) { if (arp_table[i].ctime >= age_queue) { old_queue = i; age_queue = arp_table[i].ctime; } } else /* pending without queued packets? */ { if (arp_table[i].ctime >= age_pending) { old_pending = i; age_pending = arp_table[i].ctime; } } /* stable entry? */ } else if (state >= ETHARP_STATE_STABLE) { #if ETHARP_SUPPORT_STATIC_ENTRIES /* don't record old_stable for static entries since they never expire */ if (state < ETHARP_STATE_STATIC) #endif /* ETHARP_SUPPORT_STATIC_ENTRIES */ { /* remember entry with oldest stable entry in oldest, its age in maxtime */ if (arp_table[i].ctime >= age_stable) { old_stable = i; age_stable = arp_table[i].ctime; } } } } } /* { we have no match } => try to create a new entry */ /* don't create new entry, only search? */ if (((flags & ETHARP_FLAG_FIND_ONLY) != 0) || /* or no empty entry found and not allowed to recycle? */ ((empty == ARP_TABLE_SIZE) && ((flags & ETHARP_FLAG_TRY_HARD) == 0))) { LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_find_entry: no empty entry found and not allowed to recycle\n")); return (s8_t)ERR_MEM; } /* b) choose the least destructive entry to recycle: * 1) empty entry * 2) oldest stable entry * 3) oldest pending entry without queued packets * 4) oldest pending entry with queued packets * * { ETHARP_FLAG_TRY_HARD is set at this point } */ /* 1) empty entry available? */ if (empty < ARP_TABLE_SIZE) { i = empty; LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_find_entry: selecting empty entry %"U16_F"\n", (u16_t)i)); } else { /* 2) found recyclable stable entry? */ if (old_stable < ARP_TABLE_SIZE) { /* recycle oldest stable*/ i = old_stable; LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_find_entry: selecting oldest stable entry %"U16_F"\n", (u16_t)i)); /* no queued packets should exist on stable entries */ LWIP_ASSERT("arp_table[i].q == NULL", arp_table[i].q == NULL); /* 3) found recyclable pending entry without queued packets? */ } else if (old_pending < ARP_TABLE_SIZE) { /* recycle oldest pending */ i = old_pending; LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_find_entry: selecting oldest pending entry %"U16_F" (without queue)\n", (u16_t)i)); /* 4) found recyclable pending entry with queued packets? */ } else if (old_queue < ARP_TABLE_SIZE) { /* recycle oldest pending (queued packets are free in etharp_free_entry) */ i = old_queue; LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_find_entry: selecting oldest pending entry %"U16_F", freeing packet queue %p\n", (u16_t)i, (void *)(arp_table[i].q))); /* no empty or recyclable entries found */ } else { LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_find_entry: no empty or recyclable entries found\n")); return (s8_t)ERR_MEM; } /* { empty or recyclable entry found } */ LWIP_ASSERT("i < ARP_TABLE_SIZE", i < ARP_TABLE_SIZE); etharp_free_entry(i); } LWIP_ASSERT("i < ARP_TABLE_SIZE", i < ARP_TABLE_SIZE); LWIP_ASSERT("arp_table[i].state == ETHARP_STATE_EMPTY", arp_table[i].state == ETHARP_STATE_EMPTY); /* IP address given? */ if (ipaddr != NULL) { /* set IP address */ ip_addr_copy(arp_table[i].ipaddr, *ipaddr); } arp_table[i].ctime = 0; return (err_t)i; } /** * Send an IP packet on the network using netif->linkoutput * The ethernet header is filled in before sending. * * @params netif the lwIP network interface on which to send the packet * @params p the packet to send, p->payload pointing to the (uninitialized) ethernet header * @params src the source MAC address to be copied into the ethernet header * @params dst the destination MAC address to be copied into the ethernet header * @return ERR_OK if the packet was sent, any other err_t on failure */ static err_t etharp_send_ip(struct netif *netif, struct pbuf *p, struct eth_addr *src, struct eth_addr *dst) { struct eth_hdr *ethhdr = (struct eth_hdr *)p->payload; #if ETHARP_SUPPORT_VLAN && defined(LWIP_HOOK_VLAN_SET) struct eth_vlan_hdr *vlanhdr; #endif /* ETHARP_SUPPORT_VLAN && defined(LWIP_HOOK_VLAN_SET) */ LWIP_ASSERT("netif->hwaddr_len must be the same as ETHARP_HWADDR_LEN for etharp!", (netif->hwaddr_len == ETHARP_HWADDR_LEN)); #if ETHARP_SUPPORT_VLAN && defined(LWIP_HOOK_VLAN_SET) ethhdr->type = PP_HTONS(ETHTYPE_VLAN); vlanhdr = (struct eth_vlan_hdr*)(((u8_t*)ethhdr) + SIZEOF_ETH_HDR); vlanhdr->prio_vid = 0; vlanhdr->tpid = PP_HTONS(ETHTYPE_IP); if (!LWIP_HOOK_VLAN_SET(netif, ethhdr, vlanhdr)) { /* packet shall not contain VLAN header, so hide it and set correct ethertype */ pbuf_header(p, -SIZEOF_VLAN_HDR); ethhdr = (struct eth_hdr *)p->payload; #endif /* ETHARP_SUPPORT_VLAN && defined(LWIP_HOOK_VLAN_SET) */ ethhdr->type = PP_HTONS(ETHTYPE_IP); #if ETHARP_SUPPORT_VLAN && defined(LWIP_HOOK_VLAN_SET) } #endif /* ETHARP_SUPPORT_VLAN && defined(LWIP_HOOK_VLAN_SET) */ ETHADDR32_COPY(ðhdr->dest, dst); ETHADDR16_COPY(ðhdr->src, src); LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_send_ip: sending packet %p\n", (void *)p)); /* send the packet */ return netif->linkoutput(netif, p); } /** * Update (or insert) a IP/MAC address pair in the ARP cache. * * If a pending entry is resolved, any queued packets will be sent * at this point. * * @param netif netif related to this entry (used for NETIF_ADDRHINT) * @param ipaddr IP address of the inserted ARP entry. * @param ethaddr Ethernet address of the inserted ARP entry. * @param flags @see definition of ETHARP_FLAG_* * * @return * - ERR_OK Succesfully updated ARP cache. * - ERR_MEM If we could not add a new ARP entry when ETHARP_FLAG_TRY_HARD was set. * - ERR_ARG Non-unicast address given, those will not appear in ARP cache. * * @see pbuf_free() */ static err_t etharp_update_arp_entry(struct netif *netif, ip_addr_t *ipaddr, struct eth_addr *ethaddr, u8_t flags) { s8_t i; LWIP_ASSERT("netif->hwaddr_len == ETHARP_HWADDR_LEN", netif->hwaddr_len == ETHARP_HWADDR_LEN); LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_update_arp_entry: %"U16_F".%"U16_F".%"U16_F".%"U16_F" - %02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F"\n", ip4_addr1_16(ipaddr), ip4_addr2_16(ipaddr), ip4_addr3_16(ipaddr), ip4_addr4_16(ipaddr), ethaddr->addr[0], ethaddr->addr[1], ethaddr->addr[2], ethaddr->addr[3], ethaddr->addr[4], ethaddr->addr[5])); /* non-unicast address? */ if (ip_addr_isany(ipaddr) || ip_addr_isbroadcast(ipaddr, netif) || ip_addr_ismulticast(ipaddr)) { LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_update_arp_entry: will not add non-unicast IP address to ARP cache\n")); return ERR_ARG; } /* find or create ARP entry */ i = etharp_find_entry(ipaddr, flags); /* bail out if no entry could be found */ if (i < 0) { return (err_t)i; } #if ETHARP_SUPPORT_STATIC_ENTRIES if (flags & ETHARP_FLAG_STATIC_ENTRY) { /* record static type */ arp_table[i].state = ETHARP_STATE_STATIC; } else #endif /* ETHARP_SUPPORT_STATIC_ENTRIES */ { /* mark it stable */ arp_table[i].state = ETHARP_STATE_STABLE; } /* record network interface */ arp_table[i].netif = netif; /* insert in SNMP ARP index tree */ snmp_insert_arpidx_tree(netif, &arp_table[i].ipaddr); LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_update_arp_entry: updating stable entry %"S16_F"\n", (s16_t)i)); /* update address */ ETHADDR32_COPY(&arp_table[i].ethaddr, ethaddr); /* reset time stamp */ arp_table[i].ctime = 0; /* this is where we will send out queued packets! */ #if ARP_QUEUEING while (arp_table[i].q != NULL) { struct pbuf *p; /* remember remainder of queue */ struct etharp_q_entry *q = arp_table[i].q; /* pop first item off the queue */ arp_table[i].q = q->next; /* get the packet pointer */ p = q->p; /* now queue entry can be freed */ memp_free(MEMP_ARP_QUEUE, q); #else /* ARP_QUEUEING */ if (arp_table[i].q != NULL) { struct pbuf *p = arp_table[i].q; arp_table[i].q = NULL; #endif /* ARP_QUEUEING */ /* send the queued IP packet */ etharp_send_ip(netif, p, (struct eth_addr*)(netif->hwaddr), ethaddr); /* free the queued IP packet */ pbuf_free(p); } return ERR_OK; } #if ETHARP_SUPPORT_STATIC_ENTRIES /** Add a new static entry to the ARP table. If an entry exists for the * specified IP address, this entry is overwritten. * If packets are queued for the specified IP address, they are sent out. * * @param ipaddr IP address for the new static entry * @param ethaddr ethernet address for the new static entry * @return @see return values of etharp_add_static_entry */ err_t etharp_add_static_entry(ip_addr_t *ipaddr, struct eth_addr *ethaddr) { struct netif *netif; LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_add_static_entry: %"U16_F".%"U16_F".%"U16_F".%"U16_F" - %02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F"\n", ip4_addr1_16(ipaddr), ip4_addr2_16(ipaddr), ip4_addr3_16(ipaddr), ip4_addr4_16(ipaddr), ethaddr->addr[0], ethaddr->addr[1], ethaddr->addr[2], ethaddr->addr[3], ethaddr->addr[4], ethaddr->addr[5])); netif = ip_route(ipaddr); if (netif == NULL) { return ERR_RTE; } return etharp_update_arp_entry(netif, ipaddr, ethaddr, ETHARP_FLAG_TRY_HARD | ETHARP_FLAG_STATIC_ENTRY); } /** Remove a static entry from the ARP table previously added with a call to * etharp_add_static_entry. * * @param ipaddr IP address of the static entry to remove * @return ERR_OK: entry removed * ERR_MEM: entry wasn't found * ERR_ARG: entry wasn't a static entry but a dynamic one */ err_t etharp_remove_static_entry(ip_addr_t *ipaddr) { s8_t i; LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_remove_static_entry: %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", ip4_addr1_16(ipaddr), ip4_addr2_16(ipaddr), ip4_addr3_16(ipaddr), ip4_addr4_16(ipaddr))); /* find or create ARP entry */ i = etharp_find_entry(ipaddr, ETHARP_FLAG_FIND_ONLY); /* bail out if no entry could be found */ if (i < 0) { return (err_t)i; } if (arp_table[i].state != ETHARP_STATE_STATIC) { /* entry wasn't a static entry, cannot remove it */ return ERR_ARG; } /* entry found, free it */ etharp_free_entry(i); return ERR_OK; } #endif /* ETHARP_SUPPORT_STATIC_ENTRIES */ /** * Remove all ARP table entries of the specified netif. * * @param netif points to a network interface */ void etharp_cleanup_netif(struct netif *netif) { u8_t i; for (i = 0; i < ARP_TABLE_SIZE; ++i) { u8_t state = arp_table[i].state; if ((state != ETHARP_STATE_EMPTY) && (arp_table[i].netif == netif)) { etharp_free_entry(i); } } } /** * Finds (stable) ethernet/IP address pair from ARP table * using interface and IP address index. * @note the addresses in the ARP table are in network order! * * @param netif points to interface index * @param ipaddr points to the (network order) IP address index * @param eth_ret points to return pointer * @param ip_ret points to return pointer * @return table index if found, -1 otherwise */ s8_t etharp_find_addr(struct netif *netif, ip_addr_t *ipaddr, struct eth_addr **eth_ret, ip_addr_t **ip_ret) { s8_t i; LWIP_ASSERT("eth_ret != NULL && ip_ret != NULL", eth_ret != NULL && ip_ret != NULL); LWIP_UNUSED_ARG(netif); i = etharp_find_entry(ipaddr, ETHARP_FLAG_FIND_ONLY); if((i >= 0) && (arp_table[i].state >= ETHARP_STATE_STABLE)) { *eth_ret = &arp_table[i].ethaddr; *ip_ret = &arp_table[i].ipaddr; return i; } return -1; } #if ETHARP_TRUST_IP_MAC /** * Updates the ARP table using the given IP packet. * * Uses the incoming IP packet's source address to update the * ARP cache for the local network. The function does not alter * or free the packet. This function must be called before the * packet p is passed to the IP layer. * * @param netif The lwIP network interface on which the IP packet pbuf arrived. * @param p The IP packet that arrived on netif. * * @return NULL * * @see pbuf_free() */ static void etharp_ip_input(struct netif *netif, struct pbuf *p) { struct eth_hdr *ethhdr; struct ip_hdr *iphdr; ip_addr_t iphdr_src; LWIP_ERROR("netif != NULL", (netif != NULL), return;); /* Only insert an entry if the source IP address of the incoming IP packet comes from a host on the local network. */ ethhdr = (struct eth_hdr *)p->payload; iphdr = (struct ip_hdr *)((u8_t*)ethhdr + SIZEOF_ETH_HDR); #if ETHARP_SUPPORT_VLAN if (ethhdr->type == PP_HTONS(ETHTYPE_VLAN)) { iphdr = (struct ip_hdr *)((u8_t*)ethhdr + SIZEOF_ETH_HDR + SIZEOF_VLAN_HDR); } #endif /* ETHARP_SUPPORT_VLAN */ ip_addr_copy(iphdr_src, iphdr->src); /* source is not on the local network? */ if (!ip_addr_netcmp(&iphdr_src, &(netif->ip_addr), &(netif->netmask))) { /* do nothing */ return; } LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_ip_input: updating ETHARP table.\n")); /* update the source IP address in the cache, if present */ /* @todo We could use ETHARP_FLAG_TRY_HARD if we think we are going to talk * back soon (for example, if the destination IP address is ours. */ etharp_update_arp_entry(netif, &iphdr_src, &(ethhdr->src), ETHARP_FLAG_FIND_ONLY); } #endif /* ETHARP_TRUST_IP_MAC */ /** * Responds to ARP requests to us. Upon ARP replies to us, add entry to cache * send out queued IP packets. Updates cache with snooped address pairs. * * Should be called for incoming ARP packets. The pbuf in the argument * is freed by this function. * * @param netif The lwIP network interface on which the ARP packet pbuf arrived. * @param ethaddr Ethernet address of netif. * @param p The ARP packet that arrived on netif. Is freed by this function. * * @return NULL * * @see pbuf_free() */ static void etharp_arp_input(struct netif *netif, struct eth_addr *ethaddr, struct pbuf *p) { struct etharp_hdr *hdr; struct eth_hdr *ethhdr; /* these are aligned properly, whereas the ARP header fields might not be */ ip_addr_t sipaddr, dipaddr; u8_t for_us; #if LWIP_AUTOIP const u8_t * ethdst_hwaddr; #endif /* LWIP_AUTOIP */ LWIP_ERROR("netif != NULL", (netif != NULL), return;); /* drop short ARP packets: we have to check for p->len instead of p->tot_len here since a struct etharp_hdr is pointed to p->payload, so it musn't be chained! */ if (p->len < SIZEOF_ETHARP_PACKET) { LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("etharp_arp_input: packet dropped, too short (%"S16_F"/%"S16_F")\n", p->tot_len, (s16_t)SIZEOF_ETHARP_PACKET)); ETHARP_STATS_INC(etharp.lenerr); ETHARP_STATS_INC(etharp.drop); pbuf_free(p); return; } ethhdr = (struct eth_hdr *)p->payload; hdr = (struct etharp_hdr *)((u8_t*)ethhdr + SIZEOF_ETH_HDR); #if ETHARP_SUPPORT_VLAN if (ethhdr->type == PP_HTONS(ETHTYPE_VLAN)) { hdr = (struct etharp_hdr *)(((u8_t*)ethhdr) + SIZEOF_ETH_HDR + SIZEOF_VLAN_HDR); } #endif /* ETHARP_SUPPORT_VLAN */ /* RFC 826 "Packet Reception": */ if ((hdr->hwtype != PP_HTONS(HWTYPE_ETHERNET)) || (hdr->hwlen != ETHARP_HWADDR_LEN) || (hdr->protolen != sizeof(ip_addr_t)) || (hdr->proto != PP_HTONS(ETHTYPE_IP))) { LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("etharp_arp_input: packet dropped, wrong hw type, hwlen, proto, protolen or ethernet type (%"U16_F"/%"U16_F"/%"U16_F"/%"U16_F")\n", hdr->hwtype, hdr->hwlen, hdr->proto, hdr->protolen)); ETHARP_STATS_INC(etharp.proterr); ETHARP_STATS_INC(etharp.drop); pbuf_free(p); return; } ETHARP_STATS_INC(etharp.recv); #if LWIP_AUTOIP /* We have to check if a host already has configured our random * created link local address and continously check if there is * a host with this IP-address so we can detect collisions */ autoip_arp_reply(netif, hdr); #endif /* LWIP_AUTOIP */ /* Copy struct ip_addr2 to aligned ip_addr, to support compilers without * structure packing (not using structure copy which breaks strict-aliasing rules). */ IPADDR2_COPY(&sipaddr, &hdr->sipaddr); IPADDR2_COPY(&dipaddr, &hdr->dipaddr); /* this interface is not configured? */ if (ip_addr_isany(&netif->ip_addr)) { for_us = 0; } else { /* ARP packet directed to us? */ for_us = (u8_t)ip_addr_cmp(&dipaddr, &(netif->ip_addr)); } /* ARP message directed to us? -> add IP address in ARP cache; assume requester wants to talk to us, can result in directly sending the queued packets for this host. ARP message not directed to us? -> update the source IP address in the cache, if present */ etharp_update_arp_entry(netif, &sipaddr, &(hdr->shwaddr), for_us ? ETHARP_FLAG_TRY_HARD : ETHARP_FLAG_FIND_ONLY); /* now act on the message itself */ switch (hdr->opcode) { /* ARP request? */ case PP_HTONS(ARP_REQUEST): /* ARP request. If it asked for our address, we send out a * reply. In any case, we time-stamp any existing ARP entry, * and possiby send out an IP packet that was queued on it. */ LWIP_DEBUGF (ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_arp_input: incoming ARP request\n")); /* ARP request for our address? */ if (for_us) { LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_arp_input: replying to ARP request for our IP address\n")); /* Re-use pbuf to send ARP reply. Since we are re-using an existing pbuf, we can't call etharp_raw since that would allocate a new pbuf. */ hdr->opcode = htons(ARP_REPLY); IPADDR2_COPY(&hdr->dipaddr, &hdr->sipaddr); IPADDR2_COPY(&hdr->sipaddr, &netif->ip_addr); LWIP_ASSERT("netif->hwaddr_len must be the same as ETHARP_HWADDR_LEN for etharp!", (netif->hwaddr_len == ETHARP_HWADDR_LEN)); #if LWIP_AUTOIP /* If we are using Link-Local, all ARP packets that contain a Link-Local * 'sender IP address' MUST be sent using link-layer broadcast instead of * link-layer unicast. (See RFC3927 Section 2.5, last paragraph) */ ethdst_hwaddr = ip_addr_islinklocal(&netif->ip_addr) ? (u8_t*)(ethbroadcast.addr) : hdr->shwaddr.addr; #endif /* LWIP_AUTOIP */ ETHADDR16_COPY(&hdr->dhwaddr, &hdr->shwaddr); #if LWIP_AUTOIP ETHADDR16_COPY(ðhdr->dest, ethdst_hwaddr); #else /* LWIP_AUTOIP */ ETHADDR16_COPY(ðhdr->dest, &hdr->shwaddr); #endif /* LWIP_AUTOIP */ ETHADDR16_COPY(&hdr->shwaddr, ethaddr); ETHADDR16_COPY(ðhdr->src, ethaddr); /* hwtype, hwaddr_len, proto, protolen and the type in the ethernet header are already correct, we tested that before */ /* return ARP reply */ netif->linkoutput(netif, p); /* we are not configured? */ } else if (ip_addr_isany(&netif->ip_addr)) { /* { for_us == 0 and netif->ip_addr.addr == 0 } */ LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_arp_input: we are unconfigured, ARP request ignored.\n")); /* request was not directed to us */ } else { /* { for_us == 0 and netif->ip_addr.addr != 0 } */ LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_arp_input: ARP request was not for us.\n")); } break; case PP_HTONS(ARP_REPLY): /* ARP reply. We already updated the ARP cache earlier. */ LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_arp_input: incoming ARP reply\n")); #if (LWIP_DHCP && DHCP_DOES_ARP_CHECK) /* DHCP wants to know about ARP replies from any host with an * IP address also offered to us by the DHCP server. We do not * want to take a duplicate IP address on a single network. * @todo How should we handle redundant (fail-over) interfaces? */ dhcp_arp_reply(netif, &sipaddr); #endif /* (LWIP_DHCP && DHCP_DOES_ARP_CHECK) */ break; default: LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_arp_input: ARP unknown opcode type %"S16_F"\n", htons(hdr->opcode))); ETHARP_STATS_INC(etharp.err); break; } /* free ARP packet */ pbuf_free(p); } /** Just a small helper function that sends a pbuf to an ethernet address * in the arp_table specified by the index 'arp_idx'. */ static err_t etharp_output_to_arp_index(struct netif *netif, struct pbuf *q, u8_t arp_idx) { LWIP_ASSERT("arp_table[arp_idx].state >= ETHARP_STATE_STABLE", arp_table[arp_idx].state >= ETHARP_STATE_STABLE); /* if arp table entry is about to expire: re-request it, but only if its state is ETHARP_STATE_STABLE to prevent flooding the network with ARP requests if this address is used frequently. */ if ((arp_table[arp_idx].state == ETHARP_STATE_STABLE) && (arp_table[arp_idx].ctime >= ARP_AGE_REREQUEST_USED)) { if (etharp_request(netif, &arp_table[arp_idx].ipaddr) == ERR_OK) { arp_table[arp_idx].state = ETHARP_STATE_STABLE_REREQUESTING; } } return etharp_send_ip(netif, q, (struct eth_addr*)(netif->hwaddr), &arp_table[arp_idx].ethaddr); } /** * Resolve and fill-in Ethernet address header for outgoing IP packet. * * For IP multicast and broadcast, corresponding Ethernet addresses * are selected and the packet is transmitted on the link. * * For unicast addresses, the packet is submitted to etharp_query(). In * case the IP address is outside the local network, the IP address of * the gateway is used. * * @param netif The lwIP network interface which the IP packet will be sent on. * @param q The pbuf(s) containing the IP packet to be sent. * @param ipaddr The IP address of the packet destination. * * @return * - ERR_RTE No route to destination (no gateway to external networks), * or the return type of either etharp_query() or etharp_send_ip(). */ err_t etharp_output(struct netif *netif, struct pbuf *q, ip_addr_t *ipaddr) { struct eth_addr *dest; struct eth_addr mcastaddr; ip_addr_t *dst_addr = ipaddr; LWIP_ASSERT("netif != NULL", netif != NULL); LWIP_ASSERT("q != NULL", q != NULL); LWIP_ASSERT("ipaddr != NULL", ipaddr != NULL); /* make room for Ethernet header - should not fail */ #if ETHARP_SUPPORT_VLAN && defined(LWIP_HOOK_VLAN_SET) if (pbuf_header(q, sizeof(struct eth_hdr) + SIZEOF_VLAN_HDR) != 0) { #else /* ETHARP_SUPPORT_VLAN && defined(LWIP_HOOK_VLAN_SET) */ if (pbuf_header(q, sizeof(struct eth_hdr)) != 0) { #endif /* ETHARP_SUPPORT_VLAN && defined(LWIP_HOOK_VLAN_SET) */ /* bail out */ LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("etharp_output: could not allocate room for header.\n")); LINK_STATS_INC(link.lenerr); return ERR_BUF; } /* Determine on destination hardware address. Broadcasts and multicasts * are special, other IP addresses are looked up in the ARP table. */ /* broadcast destination IP address? */ if (ip_addr_isbroadcast(ipaddr, netif)) { /* broadcast on Ethernet also */ dest = (struct eth_addr *)ðbroadcast; /* multicast destination IP address? */ } else if (ip_addr_ismulticast(ipaddr)) { /* Hash IP multicast address to MAC address.*/ mcastaddr.addr[0] = LL_MULTICAST_ADDR_0; mcastaddr.addr[1] = LL_MULTICAST_ADDR_1; mcastaddr.addr[2] = LL_MULTICAST_ADDR_2; mcastaddr.addr[3] = ip4_addr2(ipaddr) & 0x7f; mcastaddr.addr[4] = ip4_addr3(ipaddr); mcastaddr.addr[5] = ip4_addr4(ipaddr); /* destination Ethernet address is multicast */ dest = &mcastaddr; /* unicast destination IP address? */ } else { s8_t i; /* outside local network? if so, this can neither be a global broadcast nor a subnet broadcast. */ if (!ip_addr_netcmp(ipaddr, &(netif->ip_addr), &(netif->netmask)) && !ip_addr_islinklocal(ipaddr)) { #if LWIP_AUTOIP struct ip_hdr *iphdr = (struct ip_hdr*)((u8_t*)q->payload + #if ETHARP_SUPPORT_VLAN && defined(LWIP_HOOK_VLAN_SET) SIZEOF_VLAN_HDR + #endif /* ETHARP_SUPPORT_VLAN && defined(LWIP_HOOK_VLAN_SET) */ sizeof(struct eth_hdr)); /* According to RFC 3297, chapter 2.6.2 (Forwarding Rules), a packet with a link-local source address must always be "directly to its destination on the same physical link. The host MUST NOT send the packet to any router for forwarding". */ if (!ip_addr_islinklocal(&iphdr->src)) #endif /* LWIP_AUTOIP */ { #ifdef LWIP_HOOK_ETHARP_GET_GW /* For advanced routing, a single default gateway might not be enough, so get the IP address of the gateway to handle the current destination address. */ dst_addr = LWIP_HOOK_ETHARP_GET_GW(netif, ipaddr); if(dst_addr == NULL) #endif /* LWIP_HOOK_ETHARP_GET_GW */ { /* interface has default gateway? */ if (!ip_addr_isany(&netif->gw)) { /* send to hardware address of default gateway IP address */ dst_addr = &(netif->gw); /* no default gateway available */ } else { /* no route to destination error (default gateway missing) */ return ERR_RTE; } } } } #if LWIP_NETIF_HWADDRHINT if (netif->addr_hint != NULL) { /* per-pcb cached entry was given */ u8_t etharp_cached_entry = *(netif->addr_hint); if (etharp_cached_entry < ARP_TABLE_SIZE) { #endif /* LWIP_NETIF_HWADDRHINT */ if ((arp_table[etharp_cached_entry].state >= ETHARP_STATE_STABLE) && (ip_addr_cmp(dst_addr, &arp_table[etharp_cached_entry].ipaddr))) { /* the per-pcb-cached entry is stable and the right one! */ ETHARP_STATS_INC(etharp.cachehit); return etharp_output_to_arp_index(netif, q, etharp_cached_entry); } #if LWIP_NETIF_HWADDRHINT } } #endif /* LWIP_NETIF_HWADDRHINT */ /* find stable entry: do this here since this is a critical path for throughput and etharp_find_entry() is kind of slow */ for (i = 0; i < ARP_TABLE_SIZE; i++) { if ((arp_table[i].state >= ETHARP_STATE_STABLE) && (ip_addr_cmp(dst_addr, &arp_table[i].ipaddr))) { /* found an existing, stable entry */ ETHARP_SET_HINT(netif, i); return etharp_output_to_arp_index(netif, q, i); } } /* no stable entry found, use the (slower) query function: queue on destination Ethernet address belonging to ipaddr */ return etharp_query(netif, dst_addr, q); } /* continuation for multicast/broadcast destinations */ /* obtain source Ethernet address of the given interface */ /* send packet directly on the link */ return etharp_send_ip(netif, q, (struct eth_addr*)(netif->hwaddr), dest); } /** * Send an ARP request for the given IP address and/or queue a packet. * * If the IP address was not yet in the cache, a pending ARP cache entry * is added and an ARP request is sent for the given address. The packet * is queued on this entry. * * If the IP address was already pending in the cache, a new ARP request * is sent for the given address. The packet is queued on this entry. * * If the IP address was already stable in the cache, and a packet is * given, it is directly sent and no ARP request is sent out. * * If the IP address was already stable in the cache, and no packet is * given, an ARP request is sent out. * * @param netif The lwIP network interface on which ipaddr * must be queried for. * @param ipaddr The IP address to be resolved. * @param q If non-NULL, a pbuf that must be delivered to the IP address. * q is not freed by this function. * * @note q must only be ONE packet, not a packet queue! * * @return * - ERR_BUF Could not make room for Ethernet header. * - ERR_MEM Hardware address unknown, and no more ARP entries available * to query for address or queue the packet. * - ERR_MEM Could not queue packet due to memory shortage. * - ERR_RTE No route to destination (no gateway to external networks). * - ERR_ARG Non-unicast address given, those will not appear in ARP cache. * */ err_t etharp_query(struct netif *netif, ip_addr_t *ipaddr, struct pbuf *q) { struct eth_addr * srcaddr = (struct eth_addr *)netif->hwaddr; err_t result = ERR_MEM; int is_new_entry = 0; s8_t i; /* ARP entry index */ /* non-unicast address? */ if (ip_addr_isbroadcast(ipaddr, netif) || ip_addr_ismulticast(ipaddr) || ip_addr_isany(ipaddr)) { LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: will not add non-unicast IP address to ARP cache\n")); return ERR_ARG; } /* find entry in ARP cache, ask to create entry if queueing packet */ i = etharp_find_entry(ipaddr, ETHARP_FLAG_TRY_HARD); /* could not find or create entry? */ if (i < 0) { LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: could not create ARP entry\n")); if (q) { LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: packet dropped\n")); ETHARP_STATS_INC(etharp.memerr); } return (err_t)i; } /* mark a fresh entry as pending (we just sent a request) */ if (arp_table[i].state == ETHARP_STATE_EMPTY) { is_new_entry = 1; arp_table[i].state = ETHARP_STATE_PENDING; /* record network interface for re-sending arp request in etharp_tmr */ arp_table[i].netif = netif; } /* { i is either a STABLE or (new or existing) PENDING entry } */ LWIP_ASSERT("arp_table[i].state == PENDING or STABLE", ((arp_table[i].state == ETHARP_STATE_PENDING) || (arp_table[i].state >= ETHARP_STATE_STABLE))); /* do we have a new entry? or an implicit query request? */ if (is_new_entry || (q == NULL)) { /* try to resolve it; send out ARP request */ result = etharp_request(netif, ipaddr); if (result != ERR_OK) { /* ARP request couldn't be sent */ /* We don't re-send arp request in etharp_tmr, but we still queue packets, since this failure could be temporary, and the next packet calling etharp_query again could lead to sending the queued packets. */ } if (q == NULL) { return result; } } /* packet given? */ LWIP_ASSERT("q != NULL", q != NULL); /* stable entry? */ if (arp_table[i].state >= ETHARP_STATE_STABLE) { /* we have a valid IP->Ethernet address mapping */ ETHARP_SET_HINT(netif, i); /* send the packet */ result = etharp_send_ip(netif, q, srcaddr, &(arp_table[i].ethaddr)); /* pending entry? (either just created or already pending */ } else if (arp_table[i].state == ETHARP_STATE_PENDING) { /* entry is still pending, queue the given packet 'q' */ struct pbuf *p; int copy_needed = 0; /* IF q includes a PBUF_REF, PBUF_POOL or PBUF_RAM, we have no choice but * to copy the whole queue into a new PBUF_RAM (see bug #11400) * PBUF_ROMs can be left as they are, since ROM must not get changed. */ p = q; while (p) { LWIP_ASSERT("no packet queues allowed!", (p->len != p->tot_len) || (p->next == 0)); if(p->type != PBUF_ROM) { copy_needed = 1; break; } p = p->next; } if(copy_needed) { /* copy the whole packet into new pbufs */ p = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM); if(p != NULL) { if (pbuf_copy(p, q) != ERR_OK) { pbuf_free(p); p = NULL; } } } else { /* referencing the old pbuf is enough */ p = q; pbuf_ref(p); } /* packet could be taken over? */ if (p != NULL) { /* queue packet ... */ #if ARP_QUEUEING struct etharp_q_entry *new_entry; /* allocate a new arp queue entry */ new_entry = (struct etharp_q_entry *)memp_malloc(MEMP_ARP_QUEUE); if (new_entry != NULL) { unsigned int qlen = 0; new_entry->next = 0; new_entry->p = p; if(arp_table[i].q != NULL) { /* queue was already existent, append the new entry to the end */ struct etharp_q_entry *r; r = arp_table[i].q; qlen++; while (r->next != NULL) { r = r->next; qlen++; } r->next = new_entry; } else { /* queue did not exist, first item in queue */ arp_table[i].q = new_entry; } #if ARP_QUEUE_LEN if (qlen >= ARP_QUEUE_LEN) { struct etharp_q_entry *old; old = arp_table[i].q; arp_table[i].q = arp_table[i].q->next; pbuf_free(old->p); memp_free(MEMP_ARP_QUEUE, old); } #endif LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: queued packet %p on ARP entry %"S16_F"\n", (void *)q, (s16_t)i)); result = ERR_OK; } else { /* the pool MEMP_ARP_QUEUE is empty */ pbuf_free(p); LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: could not queue a copy of PBUF_REF packet %p (out of memory)\n", (void *)q)); result = ERR_MEM; } #else /* ARP_QUEUEING */ /* always queue one packet per ARP request only, freeing a previously queued packet */ if (arp_table[i].q != NULL) { LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: dropped previously queued packet %p for ARP entry %"S16_F"\n", (void *)q, (s16_t)i)); pbuf_free(arp_table[i].q); } arp_table[i].q = p; result = ERR_OK; LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: queued packet %p on ARP entry %"S16_F"\n", (void *)q, (s16_t)i)); #endif /* ARP_QUEUEING */ } else { ETHARP_STATS_INC(etharp.memerr); LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: could not queue a copy of PBUF_REF packet %p (out of memory)\n", (void *)q)); result = ERR_MEM; } } return result; } /** * Send a raw ARP packet (opcode and all addresses can be modified) * * @param netif the lwip network interface on which to send the ARP packet * @param ethsrc_addr the source MAC address for the ethernet header * @param ethdst_addr the destination MAC address for the ethernet header * @param hwsrc_addr the source MAC address for the ARP protocol header * @param ipsrc_addr the source IP address for the ARP protocol header * @param hwdst_addr the destination MAC address for the ARP protocol header * @param ipdst_addr the destination IP address for the ARP protocol header * @param opcode the type of the ARP packet * @return ERR_OK if the ARP packet has been sent * ERR_MEM if the ARP packet couldn't be allocated * any other err_t on failure */ #if !LWIP_AUTOIP static #endif /* LWIP_AUTOIP */ err_t etharp_raw(struct netif *netif, const struct eth_addr *ethsrc_addr, const struct eth_addr *ethdst_addr, const struct eth_addr *hwsrc_addr, const ip_addr_t *ipsrc_addr, const struct eth_addr *hwdst_addr, const ip_addr_t *ipdst_addr, const u16_t opcode) { struct pbuf *p; err_t result = ERR_OK; struct eth_hdr *ethhdr; #if ETHARP_SUPPORT_VLAN && defined(LWIP_HOOK_VLAN_SET) struct eth_vlan_hdr *vlanhdr; #endif /* ETHARP_SUPPORT_VLAN && defined(LWIP_HOOK_VLAN_SET) */ struct etharp_hdr *hdr; #if LWIP_AUTOIP const u8_t * ethdst_hwaddr; #endif /* LWIP_AUTOIP */ LWIP_ASSERT("netif != NULL", netif != NULL); /* allocate a pbuf for the outgoing ARP request packet */ p = pbuf_alloc(PBUF_RAW, SIZEOF_ETHARP_PACKET_TX, PBUF_RAM); /* could allocate a pbuf for an ARP request? */ if (p == NULL) { LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("etharp_raw: could not allocate pbuf for ARP request.\n")); ETHARP_STATS_INC(etharp.memerr); return ERR_MEM; } LWIP_ASSERT("check that first pbuf can hold struct etharp_hdr", (p->len >= SIZEOF_ETHARP_PACKET_TX)); ethhdr = (struct eth_hdr *)p->payload; #if ETHARP_SUPPORT_VLAN && defined(LWIP_HOOK_VLAN_SET) vlanhdr = (struct eth_vlan_hdr*)(((u8_t*)ethhdr) + SIZEOF_ETH_HDR); hdr = (struct etharp_hdr *)((u8_t*)ethhdr + SIZEOF_ETH_HDR + SIZEOF_VLAN_HDR); #else /* ETHARP_SUPPORT_VLAN && defined(LWIP_HOOK_VLAN_SET) */ hdr = (struct etharp_hdr *)((u8_t*)ethhdr + SIZEOF_ETH_HDR); #endif /* ETHARP_SUPPORT_VLAN && defined(LWIP_HOOK_VLAN_SET) */ LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_raw: sending raw ARP packet.\n")); hdr->opcode = htons(opcode); LWIP_ASSERT("netif->hwaddr_len must be the same as ETHARP_HWADDR_LEN for etharp!", (netif->hwaddr_len == ETHARP_HWADDR_LEN)); #if LWIP_AUTOIP /* If we are using Link-Local, all ARP packets that contain a Link-Local * 'sender IP address' MUST be sent using link-layer broadcast instead of * link-layer unicast. (See RFC3927 Section 2.5, last paragraph) */ ethdst_hwaddr = ip_addr_islinklocal(ipsrc_addr) ? (u8_t*)(ethbroadcast.addr) : ethdst_addr->addr; #endif /* LWIP_AUTOIP */ /* Write the ARP MAC-Addresses */ ETHADDR16_COPY(&hdr->shwaddr, hwsrc_addr); ETHADDR16_COPY(&hdr->dhwaddr, hwdst_addr); /* Copy struct ip_addr2 to aligned ip_addr, to support compilers without * structure packing. */ IPADDR2_COPY(&hdr->sipaddr, ipsrc_addr); IPADDR2_COPY(&hdr->dipaddr, ipdst_addr); hdr->hwtype = PP_HTONS(HWTYPE_ETHERNET); hdr->proto = PP_HTONS(ETHTYPE_IP); /* set hwlen and protolen */ hdr->hwlen = ETHARP_HWADDR_LEN; hdr->protolen = sizeof(ip_addr_t); #if ETHARP_SUPPORT_VLAN && defined(LWIP_HOOK_VLAN_SET) ethhdr->type = PP_HTONS(ETHTYPE_VLAN); vlanhdr->tpid = PP_HTONS(ETHTYPE_ARP); vlanhdr->prio_vid = 0; if (!LWIP_HOOK_VLAN_SET(netif, ethhdr, vlanhdr)) { /* packet shall not contain VLAN header, so hide it and set correct ethertype */ pbuf_header(p, -SIZEOF_VLAN_HDR); ethhdr = (struct eth_hdr *)p->payload; #endif /* ETHARP_SUPPORT_VLAN && defined(LWIP_HOOK_VLAN_SET) */ ethhdr->type = PP_HTONS(ETHTYPE_ARP); #if ETHARP_SUPPORT_VLAN && defined(LWIP_HOOK_VLAN_SET) } #endif /* ETHARP_SUPPORT_VLAN && defined(LWIP_HOOK_VLAN_SET) */ /* Write the Ethernet MAC-Addresses */ #if LWIP_AUTOIP ETHADDR16_COPY(ðhdr->dest, ethdst_hwaddr); #else /* LWIP_AUTOIP */ ETHADDR16_COPY(ðhdr->dest, ethdst_addr); #endif /* LWIP_AUTOIP */ ETHADDR16_COPY(ðhdr->src, ethsrc_addr); /* send ARP query */ result = netif->linkoutput(netif, p); ETHARP_STATS_INC(etharp.xmit); /* free ARP query packet */ pbuf_free(p); p = NULL; /* could not allocate pbuf for ARP request */ return result; } /** * Send an ARP request packet asking for ipaddr. * * @param netif the lwip network interface on which to send the request * @param ipaddr the IP address for which to ask * @return ERR_OK if the request has been sent * ERR_MEM if the ARP packet couldn't be allocated * any other err_t on failure */ err_t etharp_request(struct netif *netif, ip_addr_t *ipaddr) { LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_request: sending ARP request.\n")); return etharp_raw(netif, (struct eth_addr *)netif->hwaddr, ðbroadcast, (struct eth_addr *)netif->hwaddr, &netif->ip_addr, ðzero, ipaddr, ARP_REQUEST); } #endif /* LWIP_ARP */ /** * Process received ethernet frames. Using this function instead of directly * calling ip_input and passing ARP frames through etharp in ethernetif_input, * the ARP cache is protected from concurrent access. * * @param p the recevied packet, p->payload pointing to the ethernet header * @param netif the network interface on which the packet was received */ err_t ethernet_input(struct pbuf *p, struct netif *netif) { struct eth_hdr* ethhdr; u16_t type; #if LWIP_ARP || ETHARP_SUPPORT_VLAN s16_t ip_hdr_offset = SIZEOF_ETH_HDR; #endif /* LWIP_ARP || ETHARP_SUPPORT_VLAN */ if (p->len <= SIZEOF_ETH_HDR) { /* a packet with only an ethernet header (or less) is not valid for us */ ETHARP_STATS_INC(etharp.proterr); ETHARP_STATS_INC(etharp.drop); goto free_and_return; } /* points to packet payload, which starts with an Ethernet header */ ethhdr = (struct eth_hdr *)p->payload; LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("ethernet_input: dest:%"X8_F":%"X8_F":%"X8_F":%"X8_F":%"X8_F":%"X8_F", src:%"X8_F":%"X8_F":%"X8_F":%"X8_F":%"X8_F":%"X8_F", type:%"X16_F"\n", (unsigned)ethhdr->dest.addr[0], (unsigned)ethhdr->dest.addr[1], (unsigned)ethhdr->dest.addr[2], (unsigned)ethhdr->dest.addr[3], (unsigned)ethhdr->dest.addr[4], (unsigned)ethhdr->dest.addr[5], (unsigned)ethhdr->src.addr[0], (unsigned)ethhdr->src.addr[1], (unsigned)ethhdr->src.addr[2], (unsigned)ethhdr->src.addr[3], (unsigned)ethhdr->src.addr[4], (unsigned)ethhdr->src.addr[5], (unsigned)htons(ethhdr->type))); type = ethhdr->type; #if ETHARP_SUPPORT_VLAN if (type == PP_HTONS(ETHTYPE_VLAN)) { struct eth_vlan_hdr *vlan = (struct eth_vlan_hdr*)(((char*)ethhdr) + SIZEOF_ETH_HDR); if (p->len <= SIZEOF_ETH_HDR + SIZEOF_VLAN_HDR) { /* a packet with only an ethernet/vlan header (or less) is not valid for us */ ETHARP_STATS_INC(etharp.proterr); ETHARP_STATS_INC(etharp.drop); goto free_and_return; } #if defined(LWIP_HOOK_VLAN_CHECK) || defined(ETHARP_VLAN_CHECK) || defined(ETHARP_VLAN_CHECK_FN) /* if not, allow all VLANs */ #ifdef LWIP_HOOK_VLAN_CHECK if (!LWIP_HOOK_VLAN_CHECK(netif, ethhdr, vlan)) { #elif defined(ETHARP_VLAN_CHECK_FN) if (!ETHARP_VLAN_CHECK_FN(ethhdr, vlan)) { #elif defined(ETHARP_VLAN_CHECK) if (VLAN_ID(vlan) != ETHARP_VLAN_CHECK) { #endif /* silently ignore this packet: not for our VLAN */ pbuf_free(p); return ERR_OK; } #endif /* defined(LWIP_HOOK_VLAN_CHECK) || defined(ETHARP_VLAN_CHECK) || defined(ETHARP_VLAN_CHECK_FN) */ type = vlan->tpid; ip_hdr_offset = SIZEOF_ETH_HDR + SIZEOF_VLAN_HDR; } #endif /* ETHARP_SUPPORT_VLAN */ #if LWIP_ARP_FILTER_NETIF netif = LWIP_ARP_FILTER_NETIF_FN(p, netif, htons(type)); #endif /* LWIP_ARP_FILTER_NETIF*/ if (ethhdr->dest.addr[0] & 1) { /* this might be a multicast or broadcast packet */ if (ethhdr->dest.addr[0] == LL_MULTICAST_ADDR_0) { if ((ethhdr->dest.addr[1] == LL_MULTICAST_ADDR_1) && (ethhdr->dest.addr[2] == LL_MULTICAST_ADDR_2)) { /* mark the pbuf as link-layer multicast */ p->flags |= PBUF_FLAG_LLMCAST; } } else if (eth_addr_cmp(ðhdr->dest, ðbroadcast)) { /* mark the pbuf as link-layer broadcast */ p->flags |= PBUF_FLAG_LLBCAST; } } switch (type) { #if LWIP_ARP /* IP packet? */ case PP_HTONS(ETHTYPE_IP): if (!(netif->flags & NETIF_FLAG_ETHARP)) { goto free_and_return; } #if ETHARP_TRUST_IP_MAC /* update ARP table */ etharp_ip_input(netif, p); #endif /* ETHARP_TRUST_IP_MAC */ /* skip Ethernet header */ if(pbuf_header(p, -ip_hdr_offset)) { LWIP_ASSERT("Can't move over header in packet", 0); goto free_and_return; } else { /* pass to IP layer */ ip_input(p, netif); } break; case PP_HTONS(ETHTYPE_ARP): if (!(netif->flags & NETIF_FLAG_ETHARP)) { goto free_and_return; } /* pass p to ARP module */ etharp_arp_input(netif, (struct eth_addr*)(netif->hwaddr), p); break; #endif /* LWIP_ARP */ #if PPPOE_SUPPORT case PP_HTONS(ETHTYPE_PPPOEDISC): /* PPP Over Ethernet Discovery Stage */ pppoe_disc_input(netif, p); break; case PP_HTONS(ETHTYPE_PPPOE): /* PPP Over Ethernet Session Stage */ pppoe_data_input(netif, p); break; #endif /* PPPOE_SUPPORT */ #if LWIP_IPV6 case PP_HTONS(ETHTYPE_IPV6): /* IPv6 */ /* skip Ethernet header */ if(pbuf_header(p, -(s16_t)SIZEOF_ETH_HDR)) { LWIP_ASSERT("Can't move over header in packet", 0); goto free_and_return; } else { /* pass to IPv6 layer */ ip6_input(p, netif); } break; #endif /* LWIP_IPV6 */ default: ETHARP_STATS_INC(etharp.proterr); ETHARP_STATS_INC(etharp.drop); goto free_and_return; } /* This means the pbuf is freed or consumed, so the caller doesn't have to free it again */ return ERR_OK; free_and_return: pbuf_free(p); return ERR_OK; } #endif /* LWIP_ARP || LWIP_ETHERNET */ ocproxy-1.60/lwip/src/netif/ethernetif.c000066400000000000000000000231461303453231400203170ustar00rootroot00000000000000/** * @file * Ethernet Interface Skeleton * */ /* * Copyright (c) 2001-2004 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ /* * This file is a skeleton for developing Ethernet network interface * drivers for lwIP. Add code to the low_level functions and do a * search-and-replace for the word "ethernetif" to replace it with * something that better describes your network interface. */ #include "lwip/opt.h" #if 0 /* don't build, this is only a skeleton, see previous comment */ #include "lwip/def.h" #include "lwip/mem.h" #include "lwip/pbuf.h" #include "lwip/stats.h" #include "lwip/snmp.h" #include "lwip/ethip6.h" #include "netif/etharp.h" #include "netif/ppp/pppoe.h" /* Define those to better describe your network interface. */ #define IFNAME0 'e' #define IFNAME1 'n' /** * Helper struct to hold private data used to operate your ethernet interface. * Keeping the ethernet address of the MAC in this struct is not necessary * as it is already kept in the struct netif. * But this is only an example, anyway... */ struct ethernetif { struct eth_addr *ethaddr; /* Add whatever per-interface state that is needed here. */ }; /* Forward declarations. */ static void ethernetif_input(struct netif *netif); /** * In this function, the hardware should be initialized. * Called from ethernetif_init(). * * @param netif the already initialized lwip network interface structure * for this ethernetif */ static void low_level_init(struct netif *netif) { struct ethernetif *ethernetif = netif->state; /* set MAC hardware address length */ netif->hwaddr_len = ETHARP_HWADDR_LEN; /* set MAC hardware address */ netif->hwaddr[0] = ; ... netif->hwaddr[5] = ; /* maximum transfer unit */ netif->mtu = 1500; /* device capabilities */ /* don't set NETIF_FLAG_ETHARP if this device is not an ethernet one */ netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP; /* Do whatever else is needed to initialize interface. */ } /** * This function should do the actual transmission of the packet. The packet is * contained in the pbuf that is passed to the function. This pbuf * might be chained. * * @param netif the lwip network interface structure for this ethernetif * @param p the MAC packet to send (e.g. IP packet including MAC addresses and type) * @return ERR_OK if the packet could be sent * an err_t value if the packet couldn't be sent * * @note Returning ERR_MEM here if a DMA queue of your MAC is full can lead to * strange results. You might consider waiting for space in the DMA queue * to become availale since the stack doesn't retry to send a packet * dropped because of memory failure (except for the TCP timers). */ static err_t low_level_output(struct netif *netif, struct pbuf *p) { struct ethernetif *ethernetif = netif->state; struct pbuf *q; initiate transfer(); #if ETH_PAD_SIZE pbuf_header(p, -ETH_PAD_SIZE); /* drop the padding word */ #endif for(q = p; q != NULL; q = q->next) { /* Send the data from the pbuf to the interface, one pbuf at a time. The size of the data in each pbuf is kept in the ->len variable. */ send data from(q->payload, q->len); } signal that packet should be sent(); #if ETH_PAD_SIZE pbuf_header(p, ETH_PAD_SIZE); /* reclaim the padding word */ #endif LINK_STATS_INC(link.xmit); return ERR_OK; } /** * Should allocate a pbuf and transfer the bytes of the incoming * packet from the interface into the pbuf. * * @param netif the lwip network interface structure for this ethernetif * @return a pbuf filled with the received packet (including MAC header) * NULL on memory error */ static struct pbuf * low_level_input(struct netif *netif) { struct ethernetif *ethernetif = netif->state; struct pbuf *p, *q; u16_t len; /* Obtain the size of the packet and put it into the "len" variable. */ len = ; #if ETH_PAD_SIZE len += ETH_PAD_SIZE; /* allow room for Ethernet padding */ #endif /* We allocate a pbuf chain of pbufs from the pool. */ p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL); if (p != NULL) { #if ETH_PAD_SIZE pbuf_header(p, -ETH_PAD_SIZE); /* drop the padding word */ #endif /* We iterate over the pbuf chain until we have read the entire * packet into the pbuf. */ for(q = p; q != NULL; q = q->next) { /* Read enough bytes to fill this pbuf in the chain. The * available data in the pbuf is given by the q->len * variable. * This does not necessarily have to be a memcpy, you can also preallocate * pbufs for a DMA-enabled MAC and after receiving truncate it to the * actually received size. In this case, ensure the tot_len member of the * pbuf is the sum of the chained pbuf len members. */ read data into(q->payload, q->len); } acknowledge that packet has been read(); #if ETH_PAD_SIZE pbuf_header(p, ETH_PAD_SIZE); /* reclaim the padding word */ #endif LINK_STATS_INC(link.recv); } else { drop packet(); LINK_STATS_INC(link.memerr); LINK_STATS_INC(link.drop); } return p; } /** * This function should be called when a packet is ready to be read * from the interface. It uses the function low_level_input() that * should handle the actual reception of bytes from the network * interface. Then the type of the received packet is determined and * the appropriate input function is called. * * @param netif the lwip network interface structure for this ethernetif */ static void ethernetif_input(struct netif *netif) { struct ethernetif *ethernetif; struct eth_hdr *ethhdr; struct pbuf *p; ethernetif = netif->state; /* move received packet into a new pbuf */ p = low_level_input(netif); /* no packet could be read, silently ignore this */ if (p == NULL) return; /* points to packet payload, which starts with an Ethernet header */ ethhdr = p->payload; switch (htons(ethhdr->type)) { /* IP or ARP packet? */ case ETHTYPE_IP: case ETHTYPE_IPV6: case ETHTYPE_ARP: #if PPPOE_SUPPORT /* PPPoE packet? */ case ETHTYPE_PPPOEDISC: case ETHTYPE_PPPOE: #endif /* PPPOE_SUPPORT */ /* full packet send to tcpip_thread to process */ if (netif->input(p, netif)!=ERR_OK) { LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_input: IP input error\n")); pbuf_free(p); p = NULL; } break; default: pbuf_free(p); p = NULL; break; } } /** * Should be called at the beginning of the program to set up the * network interface. It calls the function low_level_init() to do the * actual setup of the hardware. * * This function should be passed as a parameter to netif_add(). * * @param netif the lwip network interface structure for this ethernetif * @return ERR_OK if the loopif is initialized * ERR_MEM if private data couldn't be allocated * any other err_t on error */ err_t ethernetif_init(struct netif *netif) { struct ethernetif *ethernetif; LWIP_ASSERT("netif != NULL", (netif != NULL)); ethernetif = mem_malloc(sizeof(struct ethernetif)); if (ethernetif == NULL) { LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_init: out of memory\n")); return ERR_MEM; } #if LWIP_NETIF_HOSTNAME /* Initialize interface hostname */ netif->hostname = "lwip"; #endif /* LWIP_NETIF_HOSTNAME */ /* * Initialize the snmp variables and counters inside the struct netif. * The last argument should be replaced with your link speed, in units * of bits per second. */ NETIF_INIT_SNMP(netif, snmp_ifType_ethernet_csmacd, LINK_SPEED_OF_YOUR_NETIF_IN_BPS); netif->state = ethernetif; netif->name[0] = IFNAME0; netif->name[1] = IFNAME1; /* We directly use etharp_output() here to save a function call. * You can instead declare your own function an call etharp_output() * from it if you have to do some checks before sending (e.g. if link * is available...) */ netif->output = etharp_output; #if LWIP_IPV6 netif->output_ip6 = ethip6_output; #endif /* LWIP_IPV6 */ netif->linkoutput = low_level_output; ethernetif->ethaddr = (struct eth_addr *)&(netif->hwaddr[0]); /* initialize the hardware */ low_level_init(netif); return ERR_OK; } #endif /* 0 */ ocproxy-1.60/lwip/src/netif/ppp/000077500000000000000000000000001303453231400166075ustar00rootroot00000000000000ocproxy-1.60/lwip/src/netif/ppp/PPPD_FOLLOWUP000066400000000000000000000207451303453231400206340ustar00rootroot00000000000000The lwIP PPP support is based from pppd 2.4.5 (http://ppp.samba.org) with huge changes to match code size and memory requirements for embedded devices. Anyway, pppd has a mature codebase for years and the average commit count is getting low on their Git repositories, meaning that we can follow what is happening on their side and merge what is relevant for lwIP. So, here is the pppd follow up, so that we don't get away too far from pppd. == Patch fetched from from pppd Debian packages == This has nothing to do with pppd, but we merged some good patch from Debian and this is a good place to be. - LCP adaptive echo, so that we don't send LCP echo request if we are receiving data from peer, can be enabled by setting PPP_LCP_ADAPTIVE to true. - IPCP no/replace default route option, were added in the early stage of the ppp port, but it wasn't really helpful and was disabled when adding the new API ppp_set_default() call, which gives the lwIP user control over which one is the default interface, it was actually a requirement if you are doing PPP over PPP (i.e. PPPoL2TP, VPN link, over PPPoE, ADSL link). - using rp-pppoe pppd exits with EXIT_OK after receiving a timeout waiting for PADO due to no modem attached, bug reported to pppd bug tracker, fixed in Debian but not in the latest (at the time when the port were started) pppd release. == Commits on pppd == 2010-03-06 - Document +ipv6 and ipv6cp-accept-local e7537958aee79b3f653c601e903cb31d78fb7dcc Don't care. 2010-03-06 - Install pppol2tp plugins with sane permissions 406215672cfadc03017341fe03802d1c7294b903 Don't care. 2010-03-07 - pppd: Terminate correctly if lcp_lowerup delayed calling fsm_lowerup 3eb9e810cfa515543655659b72dde30c54fea0a5 Merged 2012-05-17. 2010-03-07 - rp_pppoe: Copy acName and pppd_pppoe_service after option parsing cab58617fd9d328029fffabc788020264b4fa91f Don't care, is a patch for pppd/plugins/rp-pppoe/plugin.c which is not part of the port. 2010-08-23 - set and reset options to control environment variables for scripts. 2b6310fd24dba8e0fca8999916a162f0a1842a84 We can't fork processes in embedded, therefore all the pppd process run feature is disabled in the port, so we don't care about the new "environment variables" pppd feature. 2010-08-23 - Nit: use _exit when exec fails and restrict values to 0-255 per POSIX. 2b4ea140432eeba5a007c0d4e6236bd0e0c12ba4 Again, we are not running as a heavy process, so all exit() or _exit() calls were removed. 2010-08-23 - Fix quote handling in configuration files to be more like shell quoting. 3089132cdf5b58dbdfc2daf08ec5c08eb47f8aca We are not parsing config file, all the filesystem I/O stuff were disabled in our port. 2010-08-24 - rp-pppoe: allow MTU to be increased up to 1500 fd1dcdf758418f040da3ed801ab001b5e46854e7 Only concern changes on RP-PPPoE plugin, which we don't use. 2010-09-11 - chat: Allow TIMEOUT value to come from environment variable ae80bf833e48a6202f44a935a68083ae52ad3824 See 2b6310fd24dba8e0fca8999916a162f0a1842a84. 2011-03-05 - pppdump: Fix printfs with insufficient arguments 7b8db569642c83ba3283745034f2e2c95e459423 pppdump is a ppp tool outside pppd source tree. 2012-05-06 - pppd: Don't unconditionally disable VJ compression under Linux d8a66adf98a0e525cf38031b42098d539da6eeb6 Patch for sys-linux.c, which we don't use. 2012-05-20 - Remove old version of Linux if_pppol2tp.h c41092dd4c49267f232f6cba3d31c6c68bfdf68d Not in the port. 2012-05-20 - pppd: Make MSCHAP-v2 cope better with packet loss 08ef47ca532294eb428238c831616748940e24a2 This is an interesting patch. However it consumes much more memory for MSCHAP and I am not sure if the benefit worth it. The PPP client can always start the authentication again if it failed for whatever reason. 2012-05-20 - scripts: Make poff ignore extra arguments to pppd 18f515f32c9f5723a9c2c912601e04335106534b Again, we are not running scripts. 2012-05-20 - rp-pppoe plugin: Print leading zeros in MAC address f5dda0cfc220c4b52e26144096d729e27b30f0f7 Again, we are not using the RP-PPPoE plugin. 2012-05-20 - pppd: Notify IPv6 up/down as we do for IPv4 845cda8fa18939cf56e60b073f63a7efa65336fc This is just a patch that adds plugins hooks for IPv6, the plugin interface was disabled because we don't have .so plugins in embedded. 2012-05-20 - pppd: Enable IPV6 by default and fix some warnings 0b6118239615e98959f7e0b4e746bdd197533248 Change on Makefile for IPv6, warnings were already cleared during port. 2012-05-20 - contrib: Fix pppgetpass.gtk compilation 80a8e2ce257ca12cce723519a0f20ea1d663b14a Change on Makefile, don't care. 2012-05-20 - pppd: Don't crash if crypt() returns NULL 04c4348108d847e034dd91066cc6843f60d71731 We are using the PolarSSL DES implementation that does not return NULL. 2012-05-20 - pppd: Eliminate some warnings c44ae5e6a7338c96eb463881fe709b2dfaffe568 Again, we are handling compilation warnings on our own. 2012-05-20 - rp-pppoe plugin: Import some fixes from rp-pppoe-3.10 1817d83e51a411044e730ba89ebdb0480e1c8cd4 Once more, we are not using the RP-PPPoE plugin. 2013-01-23 - pppd: Clarify circumstances where DNS1/DNS2 environment variables are set cf2f5c9538b9400ade23446a194729b0a4113b3a Documentation only. 2013-02-03 - ppp: ignore unrecognised radiusclient configuration directives 7f736dde0da3c19855997d9e67370e351e15e923 Radius plugin, not in the port. 2013-02-03 - pppd: Take out unused %r conversion completely 356d8d558d844412119aa18c8e5a113bc6459c7b Merged 2014-04-15. 2013-02-03 - pppd: Arrange to use logwtmp from libutil on Linux 9617a7eb137f4fee62799a677a9ecf8d834db3f5 Patch for sys-linux.c, which we don't use. 2013-02-03 - pppdump: Eliminate some compiler warnings 3e3acf1ba2b3046c072a42c19164788a9e419bd1 pppdump is a ppp tool outside pppd source tree. 2013-02-03 - chat: Correct spelling errors in the man page 8dea1b969d266ccbf6f3a8c5474eb6dcd8838e3b Documentation only. 2013-02-03 - pppd: Fix spelling errors in man page 9e05a25d76b3f83096c661678010320df673df6b Documentation only. 2013-02-03 - plugins/passprompt: Fix potential out-of-bounds array reference 8edb889b753056a691a3e4b217a110a35f9fdedb Plugin patch, we do not have plugins. 2013-02-03 - chat: Fix *roff errors in the man page a7c3489eeaf44e83ce592143c7c8a5b5c29f4c48 Documentation only. 2013-03-02 - pppd: Fix man page description of case when remote IP address isn't known 224841f4799f4f1e2e71bc490c54448d66740f4f Documentation only. 2013-03-02 - pppd: Add master_detach option 398ed2585640d198c53e736ee5bbd67f7ce8168e Option for multilink support, we do not support multilink and this option is about detaching from the terminal, which is out of the embedded scope. 2013-03-11 - pppd: Default exit status to EXIT_CONNECT_FAILED during connection phase 225361d64ae737afdc8cb57579a2f33525461bc9 Commented out in our port, and already fixed by a previously applied Debian patch. 2013-03-11 - pppstats: Fix undefined macro in man page d16a3985eade5280b8e171f5dd0670a91cba0d39 Documentation only. 2013-05-11 - plugins/radius: Handle bindaddr keyword in radiusclient.conf d883b2dbafeed3ebd9d7a56ab1469373bd001a3b Radius plugin, not in the port. 2013-06-09 - pppoatm: Remove explicit loading of pppoatm kernel module 52cd43a84bea524033b918b603698104f221bbb7 PPPoATM plugin, not in the port. 2013-06-09 - pppd: Fix segfault in update_db_entry() 37476164f15a45015310b9d4b197c2d7db1f7f8f We do not use the samba db. 2013-06-09 - chat: Fix some text that was intended to be literal cd9683676618adcee8add2c3cfa3382341b5a1f6 Documentation only. 2013-06-09 - README.pppoe: Minor semantic fix b5b8898af6fd3d44e873cfc66810ace5f1f47e17 Documentation only. 2013-06-10 - radius: Handle additional attributes 2f581cd986a56f2ec4a95abad4f8297a1b10d7e2 Radius plugin, not in the port. 2013-06-10 - chat, pppd: Use \e instead of \\ in man pages 8d6942415d22f6ca4377340ca26e345c3f5fa5db Documentation only. 2014-01-02 - pppd: Don't crash if NULL pointer passed to vslprintf for %q or %v 906814431bddeb2061825fa1ebad1a967b6d87a9 Merged 2014-04-15. 2014-01-02 - pppd: Accept IPCP ConfAck packets containing MS-WINS options a243f217f1c6ac1aa7793806bc88590d077f490a Merged 2014-04-15. 2014-01-02 - config: Update Solaris compiler options and enable CHAPMS and IPV6 99c46caaed01b7edba87962aa52b77fad61bfd7b Solaris port, don't care. 2014-01-02 - Update README and patchlevel for 2.4.6 release 4043750fca36e7e0eb90d702e048ad1da4929418 Just release stuff. ocproxy-1.60/lwip/src/netif/ppp/auth.c000066400000000000000000002005321303453231400177160ustar00rootroot00000000000000/* * auth.c - PPP authentication and phase control. * * Copyright (c) 1993-2002 Paul Mackerras. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. The name(s) of the authors of this software must not be used to * endorse or promote products derived from this software without * prior written permission. * * 3. Redistributions of any form whatsoever must retain the following * acknowledgment: * "This product includes software developed by Paul Mackerras * ". * * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Derived from main.c, which is: * * Copyright (c) 1984-2000 Carnegie Mellon University. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The name "Carnegie Mellon University" must not be used to * endorse or promote products derived from this software without * prior written permission. For permission or any legal * details, please contact * Office of Technology Transfer * Carnegie Mellon University * 5000 Forbes Avenue * Pittsburgh, PA 15213-3890 * (412) 268-4387, fax: (412) 268-7395 * tech-transfer@andrew.cmu.edu * * 4. Redistributions of any form whatsoever must retain the following * acknowledgment: * "This product includes software developed by Computing Services * at Carnegie Mellon University (http://www.cmu.edu/computing/)." * * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "lwip/opt.h" #if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */ #if 0 /* UNUSED */ #include #include #include #include #include #include #include #include #include #include #include #include #include #if defined(_PATH_LASTLOG) && defined(__linux__) #include #endif #include #include #include #ifdef HAS_SHADOW #include #ifndef PW_PPP #define PW_PPP PW_LOGIN #endif #endif #include #endif /* UNUSED */ #include "netif/ppp/ppp_impl.h" #include "netif/ppp/fsm.h" #include "netif/ppp/lcp.h" #if CCP_SUPPORT #include "netif/ppp/ccp.h" #endif /* CCP_SUPPORT */ #if ECP_SUPPORT #include "netif/ppp/ecp.h" #endif /* ECP_SUPPORT */ #include "netif/ppp/ipcp.h" #if PAP_SUPPORT #include "netif/ppp/upap.h" #endif /* PAP_SUPPORT */ #if CHAP_SUPPORT #include "netif/ppp/chap-new.h" #endif /* CHAP_SUPPORT */ #if EAP_SUPPORT #include "netif/ppp/eap.h" #endif /* EAP_SUPPORT */ #if CBCP_SUPPORT #include "netif/ppp/cbcp.h" #endif #if 0 /* UNUSED */ #include "session.h" #endif /* UNUSED */ #if 0 /* UNUSED */ /* Bits in scan_authfile return value */ #define NONWILD_SERVER 1 #define NONWILD_CLIENT 2 #define ISWILD(word) (word[0] == '*' && word[1] == 0) #endif /* UNUSED */ #if 0 /* UNUSED */ /* List of addresses which the peer may use. */ static struct permitted_ip *addresses[NUM_PPP]; /* Wordlist giving addresses which the peer may use without authenticating itself. */ static struct wordlist *noauth_addrs; /* Remote telephone number, if available */ char remote_number[MAXNAMELEN]; /* Wordlist giving remote telephone numbers which may connect. */ static struct wordlist *permitted_numbers; /* Extra options to apply, from the secrets file entry for the peer. */ static struct wordlist *extra_options; #endif /* UNUSED */ #if 0 /* UNUSED */ /* Set if we require authentication only because we have a default route. */ static bool default_auth; /* Hook to enable a plugin to control the idle time limit */ int (*idle_time_hook) (struct ppp_idle *) = NULL; /* Hook for a plugin to say whether we can possibly authenticate any peer */ int (*pap_check_hook) (void) = NULL; /* Hook for a plugin to check the PAP user and password */ int (*pap_auth_hook) (char *user, char *passwd, char **msgp, struct wordlist **paddrs, struct wordlist **popts) = NULL; /* Hook for a plugin to know about the PAP user logout */ void (*pap_logout_hook) (void) = NULL; /* Hook for a plugin to get the PAP password for authenticating us */ int (*pap_passwd_hook) (char *user, char *passwd) = NULL; /* Hook for a plugin to say if we can possibly authenticate a peer using CHAP */ int (*chap_check_hook) (void) = NULL; /* Hook for a plugin to get the CHAP password for authenticating us */ int (*chap_passwd_hook) (char *user, char *passwd) = NULL; /* Hook for a plugin to say whether it is OK if the peer refuses to authenticate. */ int (*null_auth_hook) (struct wordlist **paddrs, struct wordlist **popts) = NULL; int (*allowed_address_hook) (u32_t addr) = NULL; #endif /* UNUSED */ #ifdef HAVE_MULTILINK /* Hook for plugin to hear when an interface joins a multilink bundle */ void (*multilink_join_hook) (void) = NULL; #endif #if PPP_NOTIFY /* A notifier for when the peer has authenticated itself, and we are proceeding to the network phase. */ struct notifier *auth_up_notifier = NULL; /* A notifier for when the link goes down. */ struct notifier *link_down_notifier = NULL; #endif /* PPP_NOTIFY */ /* * Option variables. */ #if 0 /* MOVED TO ppp_settings */ bool uselogin = 0; /* Use /etc/passwd for checking PAP */ bool session_mgmt = 0; /* Do session management (login records) */ bool cryptpap = 0; /* Passwords in pap-secrets are encrypted */ bool refuse_pap = 0; /* Don't wanna auth. ourselves with PAP */ bool refuse_chap = 0; /* Don't wanna auth. ourselves with CHAP */ bool refuse_eap = 0; /* Don't wanna auth. ourselves with EAP */ #if MSCHAP_SUPPORT bool refuse_mschap = 0; /* Don't wanna auth. ourselves with MS-CHAP */ bool refuse_mschap_v2 = 0; /* Don't wanna auth. ourselves with MS-CHAPv2 */ #else /* MSCHAP_SUPPORT */ bool refuse_mschap = 1; /* Don't wanna auth. ourselves with MS-CHAP */ bool refuse_mschap_v2 = 1; /* Don't wanna auth. ourselves with MS-CHAPv2 */ #endif /* MSCHAP_SUPPORT */ bool usehostname = 0; /* Use hostname for our_name */ bool auth_required = 0; /* Always require authentication from peer */ bool allow_any_ip = 0; /* Allow peer to use any IP address */ bool explicit_remote = 0; /* User specified explicit remote name */ bool explicit_user = 0; /* Set if "user" option supplied */ bool explicit_passwd = 0; /* Set if "password" option supplied */ char remote_name[MAXNAMELEN]; /* Peer's name for authentication */ static char *uafname; /* name of most recent +ua file */ extern char *crypt (const char *, const char *); #endif /* UNUSED */ /* Prototypes for procedures local to this file. */ static void network_phase(ppp_pcb *pcb); #if PPP_IDLETIMELIMIT static void check_idle(void *arg); #endif /* PPP_IDLETIMELIMIT */ #if PPP_MAXCONNECT static void connect_time_expired(void *arg); #endif /* PPP_MAXCONNECT */ #if 0 /* UNUSED */ static int null_login (int); /* static int get_pap_passwd (char *); */ static int have_pap_secret (int *); static int have_chap_secret (char *, char *, int, int *); static int have_srp_secret (char *client, char *server, int need_ip, int *lacks_ipp); static int ip_addr_check (u32_t, struct permitted_ip *); static int scan_authfile (FILE *, char *, char *, char *, struct wordlist **, struct wordlist **, char *, int); static void free_wordlist (struct wordlist *); static void set_allowed_addrs (int, struct wordlist *, struct wordlist *); static int some_ip_ok (struct wordlist *); static int setupapfile (char **); static int privgroup (char **); static int set_noauth_addr (char **); static int set_permitted_number (char **); static void check_access (FILE *, char *); static int wordlist_count (struct wordlist *); #endif /* UNUSED */ #ifdef MAXOCTETS static void check_maxoctets (void *); #endif #if PPP_OPTIONS /* * Authentication-related options. */ option_t auth_options[] = { { "auth", o_bool, &auth_required, "Require authentication from peer", OPT_PRIO | 1 }, { "noauth", o_bool, &auth_required, "Don't require peer to authenticate", OPT_PRIOSUB | OPT_PRIV, &allow_any_ip }, { "require-pap", o_bool, &lcp_wantoptions[0].neg_upap, "Require PAP authentication from peer", OPT_PRIOSUB | 1, &auth_required }, { "+pap", o_bool, &lcp_wantoptions[0].neg_upap, "Require PAP authentication from peer", OPT_ALIAS | OPT_PRIOSUB | 1, &auth_required }, { "require-chap", o_bool, &auth_required, "Require CHAP authentication from peer", OPT_PRIOSUB | OPT_A2OR | MDTYPE_MD5, &lcp_wantoptions[0].chap_mdtype }, { "+chap", o_bool, &auth_required, "Require CHAP authentication from peer", OPT_ALIAS | OPT_PRIOSUB | OPT_A2OR | MDTYPE_MD5, &lcp_wantoptions[0].chap_mdtype }, #if MSCHAP_SUPPORT { "require-mschap", o_bool, &auth_required, "Require MS-CHAP authentication from peer", OPT_PRIOSUB | OPT_A2OR | MDTYPE_MICROSOFT, &lcp_wantoptions[0].chap_mdtype }, { "+mschap", o_bool, &auth_required, "Require MS-CHAP authentication from peer", OPT_ALIAS | OPT_PRIOSUB | OPT_A2OR | MDTYPE_MICROSOFT, &lcp_wantoptions[0].chap_mdtype }, { "require-mschap-v2", o_bool, &auth_required, "Require MS-CHAPv2 authentication from peer", OPT_PRIOSUB | OPT_A2OR | MDTYPE_MICROSOFT_V2, &lcp_wantoptions[0].chap_mdtype }, { "+mschap-v2", o_bool, &auth_required, "Require MS-CHAPv2 authentication from peer", OPT_ALIAS | OPT_PRIOSUB | OPT_A2OR | MDTYPE_MICROSOFT_V2, &lcp_wantoptions[0].chap_mdtype }, #endif /* MSCHAP_SUPPORT */ #if 0 { "refuse-pap", o_bool, &refuse_pap, "Don't agree to auth to peer with PAP", 1 }, { "-pap", o_bool, &refuse_pap, "Don't allow PAP authentication with peer", OPT_ALIAS | 1 }, { "refuse-chap", o_bool, &refuse_chap, "Don't agree to auth to peer with CHAP", OPT_A2CLRB | MDTYPE_MD5, &lcp_allowoptions[0].chap_mdtype }, { "-chap", o_bool, &refuse_chap, "Don't allow CHAP authentication with peer", OPT_ALIAS | OPT_A2CLRB | MDTYPE_MD5, &lcp_allowoptions[0].chap_mdtype }, #endif #if MSCHAP_SUPPORT #if 0 { "refuse-mschap", o_bool, &refuse_mschap, "Don't agree to auth to peer with MS-CHAP", OPT_A2CLRB | MDTYPE_MICROSOFT, &lcp_allowoptions[0].chap_mdtype }, { "-mschap", o_bool, &refuse_mschap, "Don't allow MS-CHAP authentication with peer", OPT_ALIAS | OPT_A2CLRB | MDTYPE_MICROSOFT, &lcp_allowoptions[0].chap_mdtype }, { "refuse-mschap-v2", o_bool, &refuse_mschap_v2, "Don't agree to auth to peer with MS-CHAPv2", OPT_A2CLRB | MDTYPE_MICROSOFT_V2, &lcp_allowoptions[0].chap_mdtype }, { "-mschap-v2", o_bool, &refuse_mschap_v2, "Don't allow MS-CHAPv2 authentication with peer", OPT_ALIAS | OPT_A2CLRB | MDTYPE_MICROSOFT_V2, &lcp_allowoptions[0].chap_mdtype }, #endif #endif /* MSCHAP_SUPPORT*/ #if EAP_SUPPORT { "require-eap", o_bool, &lcp_wantoptions[0].neg_eap, "Require EAP authentication from peer", OPT_PRIOSUB | 1, &auth_required }, #if 0 { "refuse-eap", o_bool, &refuse_eap, "Don't agree to authenticate to peer with EAP", 1 }, #endif #endif /* EAP_SUPPORT */ { "name", o_string, our_name, "Set local name for authentication", OPT_PRIO | OPT_PRIV | OPT_STATIC, NULL, MAXNAMELEN }, { "+ua", o_special, (void *)setupapfile, "Get PAP user and password from file", OPT_PRIO | OPT_A2STRVAL, &uafname }, #if 0 { "user", o_string, user, "Set name for auth with peer", OPT_PRIO | OPT_STATIC, &explicit_user, MAXNAMELEN }, { "password", o_string, passwd, "Password for authenticating us to the peer", OPT_PRIO | OPT_STATIC | OPT_HIDE, &explicit_passwd, MAXSECRETLEN }, #endif { "usehostname", o_bool, &usehostname, "Must use hostname for authentication", 1 }, { "remotename", o_string, remote_name, "Set remote name for authentication", OPT_PRIO | OPT_STATIC, &explicit_remote, MAXNAMELEN }, { "login", o_bool, &uselogin, "Use system password database for PAP", OPT_A2COPY | 1 , &session_mgmt }, { "enable-session", o_bool, &session_mgmt, "Enable session accounting for remote peers", OPT_PRIV | 1 }, { "papcrypt", o_bool, &cryptpap, "PAP passwords are encrypted", 1 }, { "privgroup", o_special, (void *)privgroup, "Allow group members to use privileged options", OPT_PRIV | OPT_A2LIST }, { "allow-ip", o_special, (void *)set_noauth_addr, "Set IP address(es) which can be used without authentication", OPT_PRIV | OPT_A2LIST }, { "remotenumber", o_string, remote_number, "Set remote telephone number for authentication", OPT_PRIO | OPT_STATIC, NULL, MAXNAMELEN }, { "allow-number", o_special, (void *)set_permitted_number, "Set telephone number(s) which are allowed to connect", OPT_PRIV | OPT_A2LIST }, { NULL } }; #endif /* PPP_OPTIONS */ #if 0 /* UNUSED */ /* * setupapfile - specifies UPAP info for authenticating with peer. */ static int setupapfile(argv) char **argv; { FILE *ufile; int l; uid_t euid; char u[MAXNAMELEN], p[MAXSECRETLEN]; char *fname; lcp_allowoptions[0].neg_upap = 1; /* open user info file */ fname = strdup(*argv); if (fname == NULL) novm("+ua file name"); euid = geteuid(); if (seteuid(getuid()) == -1) { option_error("unable to reset uid before opening %s: %m", fname); return 0; } ufile = fopen(fname, "r"); if (seteuid(euid) == -1) fatal("unable to regain privileges: %m"); if (ufile == NULL) { option_error("unable to open user login data file %s", fname); return 0; } check_access(ufile, fname); uafname = fname; /* get username */ if (fgets(u, MAXNAMELEN - 1, ufile) == NULL || fgets(p, MAXSECRETLEN - 1, ufile) == NULL) { fclose(ufile); option_error("unable to read user login data file %s", fname); return 0; } fclose(ufile); /* get rid of newlines */ l = strlen(u); if (l > 0 && u[l-1] == '\n') u[l-1] = 0; l = strlen(p); if (l > 0 && p[l-1] == '\n') p[l-1] = 0; if (override_value("user", option_priority, fname)) { strlcpy(ppp_settings.user, u, sizeof(ppp_settings.user)); explicit_user = 1; } if (override_value("passwd", option_priority, fname)) { strlcpy(ppp_settings.passwd, p, sizeof(ppp_settings.passwd)); explicit_passwd = 1; } return (1); } /* * privgroup - allow members of the group to have privileged access. */ static int privgroup(argv) char **argv; { struct group *g; int i; g = getgrnam(*argv); if (g == 0) { option_error("group %s is unknown", *argv); return 0; } for (i = 0; i < ngroups; ++i) { if (groups[i] == g->gr_gid) { privileged = 1; break; } } return 1; } /* * set_noauth_addr - set address(es) that can be used without authentication. * Equivalent to specifying an entry like `"" * "" addr' in pap-secrets. */ static int set_noauth_addr(argv) char **argv; { char *addr = *argv; int l = strlen(addr) + 1; struct wordlist *wp; wp = (struct wordlist *) malloc(sizeof(struct wordlist) + l); if (wp == NULL) novm("allow-ip argument"); wp->word = (char *) (wp + 1); wp->next = noauth_addrs; MEMCPY(wp->word, addr, l); noauth_addrs = wp; return 1; } /* * set_permitted_number - set remote telephone number(s) that may connect. */ static int set_permitted_number(argv) char **argv; { char *number = *argv; int l = strlen(number) + 1; struct wordlist *wp; wp = (struct wordlist *) malloc(sizeof(struct wordlist) + l); if (wp == NULL) novm("allow-number argument"); wp->word = (char *) (wp + 1); wp->next = permitted_numbers; MEMCPY(wp->word, number, l); permitted_numbers = wp; return 1; } #endif /* * An Open on LCP has requested a change from Dead to Establish phase. */ void link_required(ppp_pcb *pcb) { } #if 0 /* * Bring the link up to the point of being able to do ppp. */ void start_link(unit) int unit; { ppp_pcb *pcb = &ppp_pcb_list[unit]; char *msg; status = EXIT_NEGOTIATION_FAILED; new_phase(pcb, PPP_PHASE_SERIALCONN); hungup = 0; devfd = the_channel->connect(); msg = "Connect script failed"; if (devfd < 0) goto fail; /* set up the serial device as a ppp interface */ /* * N.B. we used to do tdb_writelock/tdb_writeunlock around this * (from establish_ppp to set_ifunit). However, we won't be * doing the set_ifunit in multilink mode, which is the only time * we need the atomicity that the tdb_writelock/tdb_writeunlock * gives us. Thus we don't need the tdb_writelock/tdb_writeunlock. */ fd_ppp = the_channel->establish_ppp(devfd); msg = "ppp establishment failed"; if (fd_ppp < 0) { status = EXIT_FATAL_ERROR; goto disconnect; } if (!demand && ifunit >= 0) set_ifunit(1); /* * Start opening the connection and wait for * incoming events (reply, timeout, etc.). */ if (ifunit >= 0) ppp_notice("Connect: %s <--> %s", ifname, ppp_devnam); else ppp_notice("Starting negotiation on %s", ppp_devnam); add_fd(fd_ppp); new_phase(pcb, PPP_PHASE_ESTABLISH); lcp_lowerup(pcb); return; disconnect: new_phase(pcb, PPP_PHASE_DISCONNECT); if (the_channel->disconnect) the_channel->disconnect(); fail: new_phase(pcb, PPP_PHASE_DEAD); if (the_channel->cleanup) (*the_channel->cleanup)(); } #endif /* * LCP has terminated the link; go to the Dead phase and take the * physical layer down. */ void link_terminated(ppp_pcb *pcb) { if (pcb->phase == PPP_PHASE_DEAD || pcb->phase == PPP_PHASE_MASTER) return; new_phase(pcb, PPP_PHASE_DISCONNECT); #if 0 /* UNUSED */ if (pap_logout_hook) { pap_logout_hook(); } session_end(devnam); #endif /* UNUSED */ if (!doing_multilink) { ppp_notice("Connection terminated."); #if PPP_STATS_SUPPORT print_link_stats(); #endif /* PPP_STATS_SUPPORT */ } else ppp_notice("Link terminated."); lcp_lowerdown(pcb); new_phase(pcb, PPP_PHASE_DEAD); ppp_link_terminated(pcb); #if 0 /* * Delete pid files before disestablishing ppp. Otherwise it * can happen that another pppd gets the same unit and then * we delete its pid file. */ if (!doing_multilink && !demand) remove_pidfiles(); /* * If we may want to bring the link up again, transfer * the ppp unit back to the loopback. Set the * real serial device back to its normal mode of operation. */ if (fd_ppp >= 0) { remove_fd(fd_ppp); clean_check(); the_channel->disestablish_ppp(devfd); if (doing_multilink) mp_exit_bundle(); fd_ppp = -1; } if (!hungup) lcp_lowerdown(pcb); if (!doing_multilink && !demand) script_unsetenv("IFNAME"); /* * Run disconnector script, if requested. * XXX we may not be able to do this if the line has hung up! */ if (devfd >= 0 && the_channel->disconnect) { the_channel->disconnect(); devfd = -1; } if (the_channel->cleanup) (*the_channel->cleanup)(); if (doing_multilink && multilink_master) { if (!bundle_terminating) new_phase(pcb, PPP_PHASE_MASTER); else mp_bundle_terminated(); } else new_phase(pcb, PPP_PHASE_DEAD); #endif } /* * LCP has gone down; it will either die or try to re-establish. */ void link_down(ppp_pcb *pcb) { #if PPP_NOTIFY notify(link_down_notifier, 0); #endif /* PPP_NOTIFY */ if (!doing_multilink) { upper_layers_down(pcb); if (pcb->phase != PPP_PHASE_DEAD && pcb->phase != PPP_PHASE_MASTER) new_phase(pcb, PPP_PHASE_ESTABLISH); } /* XXX if doing_multilink, should do something to stop network-layer traffic on the link */ ppp_link_down(pcb); } void upper_layers_down(ppp_pcb *pcb) { int i; const struct protent *protp; for (i = 0; (protp = protocols[i]) != NULL; ++i) { if (!protp->enabled_flag) continue; if (protp->protocol != PPP_LCP && protp->lowerdown != NULL) (*protp->lowerdown)(pcb); if (protp->protocol < 0xC000 && protp->close != NULL) (*protp->close)(pcb, "LCP down"); } pcb->num_np_open = 0; pcb->num_np_up = 0; } /* * The link is established. * Proceed to the Dead, Authenticate or Network phase as appropriate. */ void link_established(ppp_pcb *pcb) { int auth; #if PPP_SERVER lcp_options *wo = &pcb->lcp_wantoptions; lcp_options *go = &pcb->lcp_gotoptions; #endif /* PPP_SERVER */ lcp_options *ho = &pcb->lcp_hisoptions; int i; const struct protent *protp; #if PPP_SERVER int errcode; #endif /* PPP_SERVER */ /* * Tell higher-level protocols that LCP is up. */ if (!doing_multilink) { for (i = 0; (protp = protocols[i]) != NULL; ++i) if (protp->protocol != PPP_LCP && protp->enabled_flag && protp->lowerup != NULL) (*protp->lowerup)(pcb); } #if PPP_SERVER #if PPP_ALLOWED_ADDRS if (!auth_required && noauth_addrs != NULL) set_allowed_addrs(unit, NULL, NULL); #endif /* PPP_ALLOWED_ADDRS */ if (pcb->settings.auth_required && !(0 #if PAP_SUPPORT || go->neg_upap #endif /* PAP_SUPPORT */ #if CHAP_SUPPORT || go->neg_chap #endif /* CHAP_SUPPORT */ #if EAP_SUPPORT || go->neg_eap #endif /* EAP_SUPPORT */ )) { #if PPP_ALLOWED_ADDRS /* * We wanted the peer to authenticate itself, and it refused: * if we have some address(es) it can use without auth, fine, * otherwise treat it as though it authenticated with PAP using * a username of "" and a password of "". If that's not OK, * boot it out. */ if (noauth_addrs != NULL) { set_allowed_addrs(unit, NULL, NULL); } else #endif /* PPP_ALLOWED_ADDRS */ if (!wo->neg_upap || !pcb->settings.null_login) { ppp_warn("peer refused to authenticate: terminating link"); #if 0 /* UNUSED */ status = EXIT_PEER_AUTH_FAILED; #endif /* UNUSED */ errcode = PPPERR_AUTHFAIL; ppp_ioctl(pcb, PPPCTLS_ERRCODE, &errcode); lcp_close(pcb, "peer refused to authenticate"); return; } } #endif /* PPP_SERVER */ new_phase(pcb, PPP_PHASE_AUTHENTICATE); auth = 0; #if PPP_SERVER #if EAP_SUPPORT if (go->neg_eap) { eap_authpeer(pcb, pcb->settings.our_name); auth |= EAP_PEER; } else #endif /* EAP_SUPPORT */ #if CHAP_SUPPORT if (go->neg_chap) { chap_auth_peer(pcb, pcb->settings.our_name, CHAP_DIGEST(go->chap_mdtype)); auth |= CHAP_PEER; } else #endif /* CHAP_SUPPORT */ #if PAP_SUPPORT if (go->neg_upap) { upap_authpeer(pcb); auth |= PAP_PEER; } else #endif /* PAP_SUPPORT */ {} #endif /* PPP_SERVER */ #if EAP_SUPPORT if (ho->neg_eap) { eap_authwithpeer(pcb, pcb->settings.user); auth |= EAP_WITHPEER; } else #endif /* EAP_SUPPORT */ #if CHAP_SUPPORT if (ho->neg_chap) { chap_auth_with_peer(pcb, pcb->settings.user, CHAP_DIGEST(ho->chap_mdtype)); auth |= CHAP_WITHPEER; } else #endif /* CHAP_SUPPORT */ #if PAP_SUPPORT if (ho->neg_upap) { upap_authwithpeer(pcb, pcb->settings.user, pcb->settings.passwd); auth |= PAP_WITHPEER; } else #endif /* PAP_SUPPORT */ {} pcb->auth_pending = auth; pcb->auth_done = 0; if (!auth) network_phase(pcb); } /* * Proceed to the network phase. */ static void network_phase(ppp_pcb *pcb) { #if CBCP_SUPPORT ppp_pcb *pcb = &ppp_pcb_list[unit]; #endif #if 0 /* UNUSED */ lcp_options *go = &lcp_gotoptions[unit]; #endif /* UNUSED */ #if 0 /* UNUSED */ /* Log calling number. */ if (*remote_number) ppp_notice("peer from calling number %q authorized", remote_number); #endif /* UNUSED */ #if PPP_NOTIFY /* * If the peer had to authenticate, notify it now. */ if (0 #if CHAP_SUPPORT || go->neg_chap #endif /* CHAP_SUPPORT */ #if PAP_SUPPORT || go->neg_upap #endif /* PAP_SUPPORT */ #if EAP_SUPPORT || go->neg_eap #endif /* EAP_SUPPORT */ ) { notify(auth_up_notifier, 0); } #endif /* PPP_NOTIFY */ #if CBCP_SUPPORT /* * If we negotiated callback, do it now. */ if (go->neg_cbcp) { new_phase(pcb, PPP_PHASE_CALLBACK); (*cbcp_protent.open)(pcb); return; } #endif #if PPP_OPTIONS /* * Process extra options from the secrets file */ if (extra_options) { options_from_list(extra_options, 1); free_wordlist(extra_options); extra_options = 0; } #endif /* PPP_OPTIONS */ start_networks(pcb); } void start_networks(ppp_pcb *pcb) { #if CCP_SUPPORT || ECP_SUPPORT int i; const struct protent *protp; #endif /* CCP_SUPPORT || ECP_SUPPORT */ #if ECP_SUPPORT int ecp_required; #endif /* ECP_SUPPORT */ #ifdef MPPE int mppe_required; #endif /* MPPE */ new_phase(pcb, PPP_PHASE_NETWORK); #ifdef HAVE_MULTILINK if (multilink) { if (mp_join_bundle()) { if (multilink_join_hook) (*multilink_join_hook)(); if (updetach && !nodetach) detach(); return; } } #endif /* HAVE_MULTILINK */ #ifdef PPP_FILTER if (!demand) set_filters(&pass_filter, &active_filter); #endif #if CCP_SUPPORT || ECP_SUPPORT /* Start CCP and ECP */ for (i = 0; (protp = protocols[i]) != NULL; ++i) if ( (0 #if ECP_SUPPORT || protp->protocol == PPP_ECP #endif /* ECP_SUPPORT */ #if CCP_SUPPORT || protp->protocol == PPP_CCP #endif /* CCP_SUPPORT */ ) && protp->enabled_flag && protp->open != NULL) (*protp->open)(pcb); #endif /* CCP_SUPPORT || ECP_SUPPORT */ /* * Bring up other network protocols iff encryption is not required. */ #if ECP_SUPPORT ecp_required = ecp_gotoptions[unit].required; #endif /* ECP_SUPPORT */ #ifdef MPPE mppe_required = ccp_gotoptions[unit].mppe; #endif /* MPPE */ if (1 #if ECP_SUPPORT && !ecp_required #endif /* ECP_SUPPORT */ #ifdef MPPE && !mppe_required #endif /* MPPE */ ) continue_networks(pcb); } void continue_networks(ppp_pcb *pcb) { int i; const struct protent *protp; /* * Start the "real" network protocols. */ for (i = 0; (protp = protocols[i]) != NULL; ++i) if (protp->protocol < 0xC000 #if CCP_SUPPORT && protp->protocol != PPP_CCP #endif /* CCP_SUPPORT */ #if ECP_SUPPORT && protp->protocol != PPP_ECP #endif /* ECP_SUPPORT */ && protp->enabled_flag && protp->open != NULL) { (*protp->open)(pcb); ++pcb->num_np_open; } if (pcb->num_np_open == 0) /* nothing to do */ lcp_close(pcb, "No network protocols running"); } #if PPP_SERVER /* * The peer has failed to authenticate himself using `protocol'. */ void auth_peer_fail(ppp_pcb *pcb, int protocol) { int errcode = PPPERR_AUTHFAIL; /* * Authentication failure: take the link down */ #if 0 /* UNUSED */ status = EXIT_PEER_AUTH_FAILED; #endif /* UNUSED */ ppp_ioctl(pcb, PPPCTLS_ERRCODE, &errcode); lcp_close(pcb, "Authentication failed"); } /* * The peer has been successfully authenticated using `protocol'. */ void auth_peer_success(ppp_pcb *pcb, int protocol, int prot_flavor, char *name, int namelen) { int bit; switch (protocol) { #if CHAP_SUPPORT case PPP_CHAP: bit = CHAP_PEER; switch (prot_flavor) { case CHAP_MD5: bit |= CHAP_MD5_PEER; break; #if MSCHAP_SUPPORT case CHAP_MICROSOFT: bit |= CHAP_MS_PEER; break; case CHAP_MICROSOFT_V2: bit |= CHAP_MS2_PEER; break; #endif /* MSCHAP_SUPPORT */ } break; #endif /* CHAP_SUPPORT */ #if PAP_SUPPORT case PPP_PAP: bit = PAP_PEER; break; #endif /* PAP_SUPPORT */ #if EAP_SUPPORT case PPP_EAP: bit = EAP_PEER; break; #endif /* EAP_SUPPORT */ default: ppp_warn("auth_peer_success: unknown protocol %x", protocol); return; } /* * Save the authenticated name of the peer for later. */ /* FIXME: do we need that ? */ if (namelen > sizeof(pcb->peer_authname) - 1) namelen = sizeof(pcb->peer_authname) - 1; MEMCPY(pcb->peer_authname, name, namelen); pcb->peer_authname[namelen] = 0; #if 0 /* UNUSED */ script_setenv("PEERNAME", , 0); #endif /* UNUSED */ /* Save the authentication method for later. */ pcb->auth_done |= bit; /* * If there is no more authentication still to be done, * proceed to the network (or callback) phase. */ if ((pcb->auth_pending &= ~bit) == 0) network_phase(pcb); } #endif /* PPP_SERVER */ /* * We have failed to authenticate ourselves to the peer using `protocol'. */ void auth_withpeer_fail(ppp_pcb *pcb, int protocol) { int errcode = PPPERR_AUTHFAIL; /* * We've failed to authenticate ourselves to our peer. * * Some servers keep sending CHAP challenges, but there * is no point in persisting without any way to get updated * authentication secrets. * * He'll probably take the link down, and there's not much * we can do except wait for that. */ ppp_ioctl(pcb, PPPCTLS_ERRCODE, &errcode); lcp_close(pcb, "Failed to authenticate ourselves to peer"); } /* * We have successfully authenticated ourselves with the peer using `protocol'. */ void auth_withpeer_success(ppp_pcb *pcb, int protocol, int prot_flavor) { int bit; const char *prot = ""; switch (protocol) { #if CHAP_SUPPORT case PPP_CHAP: bit = CHAP_WITHPEER; prot = "CHAP"; switch (prot_flavor) { case CHAP_MD5: bit |= CHAP_MD5_WITHPEER; break; #if MSCHAP_SUPPORT case CHAP_MICROSOFT: bit |= CHAP_MS_WITHPEER; break; case CHAP_MICROSOFT_V2: bit |= CHAP_MS2_WITHPEER; break; #endif /* MSCHAP_SUPPORT */ } break; #endif /* CHAP_SUPPORT */ #if PAP_SUPPORT case PPP_PAP: bit = PAP_WITHPEER; prot = "PAP"; break; #endif /* PAP_SUPPORT */ #if EAP_SUPPORT case PPP_EAP: bit = EAP_WITHPEER; prot = "EAP"; break; #endif /* EAP_SUPPORT */ default: ppp_warn("auth_withpeer_success: unknown protocol %x", protocol); bit = 0; /* no break */ } ppp_notice("%s authentication succeeded", prot); /* Save the authentication method for later. */ pcb->auth_done |= bit; /* * If there is no more authentication still being done, * proceed to the network (or callback) phase. */ if ((pcb->auth_pending &= ~bit) == 0) network_phase(pcb); } /* * np_up - a network protocol has come up. */ void np_up(ppp_pcb *pcb, int proto) { #if PPP_IDLETIMELIMIT int tlim; #endif /* PPP_IDLETIMELIMIT */ if (pcb->num_np_up == 0) { /* * At this point we consider that the link has come up successfully. */ new_phase(pcb, PPP_PHASE_RUNNING); #if PPP_IDLETIMELIMIT #if 0 /* UNUSED */ if (idle_time_hook != 0) tlim = (*idle_time_hook)(NULL); else #endif /* UNUSED */ tlim = pcb->settings.idle_time_limit; if (tlim > 0) TIMEOUT(check_idle, (void*)pcb, tlim); #endif /* PPP_IDLETIMELIMIT */ #if PPP_MAXCONNECT /* * Set a timeout to close the connection once the maximum * connect time has expired. */ if (pcb->settings.maxconnect > 0) TIMEOUT(connect_time_expired, (void*)pcb, pcb->settings.maxconnect); #endif /* PPP_MAXCONNECT */ #ifdef MAXOCTETS if (maxoctets > 0) TIMEOUT(check_maxoctets, NULL, maxoctets_timeout); #endif #if 0 /* Unused */ /* * Detach now, if the updetach option was given. */ if (updetach && !nodetach) detach(); #endif /* Unused */ } ++pcb->num_np_up; } /* * np_down - a network protocol has gone down. */ void np_down(ppp_pcb *pcb, int proto) { if (--pcb->num_np_up == 0) { #if PPP_IDLETIMELIMIT UNTIMEOUT(check_idle, (void*)pcb); #endif /* PPP_IDLETIMELIMIT */ #if PPP_MAXCONNECT UNTIMEOUT(connect_time_expired, NULL); #endif /* PPP_MAXCONNECT */ #ifdef MAXOCTETS UNTIMEOUT(check_maxoctets, NULL); #endif new_phase(pcb, PPP_PHASE_NETWORK); } } /* * np_finished - a network protocol has finished using the link. */ void np_finished(ppp_pcb *pcb, int proto) { if (--pcb->num_np_open <= 0) { /* no further use for the link: shut up shop. */ lcp_close(pcb, "No network protocols running"); } } #ifdef MAXOCTETS static void check_maxoctets(arg) void *arg; { #if PPP_STATS_SUPPORT unsigned int used; update_link_stats(ifunit); link_stats_valid=0; switch(maxoctets_dir) { case PPP_OCTETS_DIRECTION_IN: used = link_stats.bytes_in; break; case PPP_OCTETS_DIRECTION_OUT: used = link_stats.bytes_out; break; case PPP_OCTETS_DIRECTION_MAXOVERAL: case PPP_OCTETS_DIRECTION_MAXSESSION: used = (link_stats.bytes_in > link_stats.bytes_out) ? link_stats.bytes_in : link_stats.bytes_out; break; default: used = link_stats.bytes_in+link_stats.bytes_out; break; } if (used > maxoctets) { ppp_notice("Traffic limit reached. Limit: %u Used: %u", maxoctets, used); status = EXIT_TRAFFIC_LIMIT; lcp_close(pcb, "Traffic limit"); #if 0 /* UNUSED */ need_holdoff = 0; #endif /* UNUSED */ } else { TIMEOUT(check_maxoctets, NULL, maxoctets_timeout); } #endif /* PPP_STATS_SUPPORT */ } #endif /* MAXOCTETS */ #if PPP_IDLETIMELIMIT /* * check_idle - check whether the link has been idle for long * enough that we can shut it down. */ static void check_idle(void *arg) { ppp_pcb *pcb = (ppp_pcb*)arg; struct ppp_idle idle; time_t itime; int tlim; if (!get_idle_time(pcb, &idle)) return; #if 0 /* UNUSED */ if (idle_time_hook != 0) { tlim = idle_time_hook(&idle); } else { #endif /* UNUSED */ itime = LWIP_MIN(idle.xmit_idle, idle.recv_idle); tlim = pcb->settings.idle_time_limit - itime; #if 0 /* UNUSED */ } #endif /* UNUSED */ if (tlim <= 0) { int errcode = PPPERR_IDLETIMEOUT; /* link is idle: shut it down. */ ppp_notice("Terminating connection due to lack of activity."); ppp_ioctl(pcb, PPPCTLS_ERRCODE, &errcode); lcp_close(pcb, "Link inactive"); #if 0 /* UNUSED */ need_holdoff = 0; #endif /* UNUSED */ } else { TIMEOUT(check_idle, (void*)pcb, tlim); } } #endif /* PPP_IDLETIMELIMIT */ #if PPP_MAXCONNECT /* * connect_time_expired - log a message and close the connection. */ static void connect_time_expired(void *arg) { int errcode = PPPERR_CONNECTTIME; ppp_pcb *pcb = (ppp_pcb*)arg; ppp_info("Connect time expired"); ppp_ioctl(pcb, PPPCTLS_ERRCODE, &errcode); lcp_close(pcb, "Connect time expired"); /* Close connection */ } #endif /* PPP_MAXCONNECT */ #if PPP_OPTIONS /* * auth_check_options - called to check authentication options. */ void auth_check_options() { lcp_options *wo = &lcp_wantoptions[0]; int can_auth; int lacks_ip; /* Default our_name to hostname, and user to our_name */ if (our_name[0] == 0 || usehostname) strlcpy(our_name, hostname, sizeof(our_name)); /* If a blank username was explicitly given as an option, trust the user and don't use our_name */ if (ppp_settings.user[0] == 0 && !explicit_user) strlcpy(ppp_settings.user, our_name, sizeof(ppp_settings.user)); /* * If we have a default route, require the peer to authenticate * unless the noauth option was given or the real user is root. */ if (!auth_required && !allow_any_ip && have_route_to(0) && !privileged) { auth_required = 1; default_auth = 1; } #if CHAP_SUPPORT /* If we selected any CHAP flavors, we should probably negotiate it. :-) */ if (wo->chap_mdtype) wo->neg_chap = 1; #endif /* CHAP_SUPPORT */ /* If authentication is required, ask peer for CHAP, PAP, or EAP. */ if (auth_required) { allow_any_ip = 0; if (1 #if CHAP_SUPPORT && !wo->neg_chap #endif /* CHAP_SUPPORT */ #if PAP_SUPPORT && !wo->neg_upap #endif /* PAP_SUPPORT */ #if EAP_SUPPORT && !wo->neg_eap #endif /* EAP_SUPPORT */ ) { #if CHAP_SUPPORT wo->neg_chap = CHAP_MDTYPE_SUPPORTED != MDTYPE_NONE; wo->chap_mdtype = CHAP_MDTYPE_SUPPORTED; #endif /* CHAP_SUPPORT */ #if PAP_SUPPORT wo->neg_upap = 1; #endif /* PAP_SUPPORT */ #if EAP_SUPPORT wo->neg_eap = 1; #endif /* EAP_SUPPORT */ } } else { #if CHAP_SUPPORT wo->neg_chap = 0; wo->chap_mdtype = MDTYPE_NONE; #endif /* CHAP_SUPPORT */ #if PAP_SUPPORT wo->neg_upap = 0; #endif /* PAP_SUPPORT */ #if EAP_SUPPORT wo->neg_eap = 0; #endif /* EAP_SUPPORT */ } /* * Check whether we have appropriate secrets to use * to authenticate the peer. Note that EAP can authenticate by way * of a CHAP-like exchanges as well as SRP. */ lacks_ip = 0; #if PAP_SUPPORT can_auth = wo->neg_upap && (uselogin || have_pap_secret(&lacks_ip)); #else can_auth = 0; #endif /* PAP_SUPPORT */ if (!can_auth && (0 #if CHAP_SUPPORT || wo->neg_chap #endif /* CHAP_SUPPORT */ #if EAP_SUPPORT || wo->neg_eap #endif /* EAP_SUPPORT */ )) { #if CHAP_SUPPORT can_auth = have_chap_secret((explicit_remote? remote_name: NULL), our_name, 1, &lacks_ip); #else can_auth = 0; #endif } if (!can_auth #if EAP_SUPPORT && wo->neg_eap #endif /* EAP_SUPPORT */ ) { can_auth = have_srp_secret((explicit_remote? remote_name: NULL), our_name, 1, &lacks_ip); } if (auth_required && !can_auth && noauth_addrs == NULL) { if (default_auth) { option_error( "By default the remote system is required to authenticate itself"); option_error( "(because this system has a default route to the internet)"); } else if (explicit_remote) option_error( "The remote system (%s) is required to authenticate itself", remote_name); else option_error( "The remote system is required to authenticate itself"); option_error( "but I couldn't find any suitable secret (password) for it to use to do so."); if (lacks_ip) option_error( "(None of the available passwords would let it use an IP address.)"); exit(1); } /* * Early check for remote number authorization. */ if (!auth_number()) { ppp_warn("calling number %q is not authorized", remote_number); exit(EXIT_CNID_AUTH_FAILED); } } #endif /* PPP_OPTIONS */ /* * auth_reset - called when LCP is starting negotiations to recheck * authentication options, i.e. whether we have appropriate secrets * to use for authenticating ourselves and/or the peer. */ void auth_reset(ppp_pcb *pcb) { lcp_options *go = &pcb->lcp_gotoptions; lcp_options *ao = &pcb->lcp_allowoptions; if(pcb->settings.passwd) { #if PAP_SUPPORT ao->neg_upap = !pcb->settings.refuse_pap; #endif /* PAP_SUPPORT */ #if EAP_SUPPORT ao->neg_eap = !pcb->settings.refuse_eap; #endif /* EAP_SUPPORT */ #if CHAP_SUPPORT ao->chap_mdtype = MDTYPE_NONE; if(!pcb->settings.refuse_chap) ao->chap_mdtype |= MDTYPE_MD5; #if MSCHAP_SUPPORT if(!pcb->settings.refuse_mschap) ao->chap_mdtype |= MDTYPE_MICROSOFT; if(!pcb->settings.refuse_mschap_v2) ao->chap_mdtype |= MDTYPE_MICROSOFT_V2; #endif /* MSCHAP_SUPPORT */ ao->neg_chap = (ao->chap_mdtype != MDTYPE_NONE); #endif /* CHAP_SUPPORT */ } else { #if PAP_SUPPORT ao->neg_upap = 0; #endif /* PAP_SUPPORT */ #if CHAP_SUPPORT ao->neg_chap = 0; ao->chap_mdtype = MDTYPE_NONE; #endif /* CHAP_SUPPORT */ #if EAP_SUPPORT ao->neg_eap = 0; #endif /* EAP_SUPPORT */ } #if PAP_SUPPORT PPPDEBUG(LOG_DEBUG, ("neg_upap: %d\n", ao->neg_upap) ); #endif /* PAP_SUPPORT */ #if CHAP_SUPPORT PPPDEBUG(LOG_DEBUG, ("neg_chap: %d\n", ao->neg_chap) ); PPPDEBUG(LOG_DEBUG, ("neg_chap_md5: %d\n", !!(ao->chap_mdtype&MDTYPE_MD5)) ); #if MSCHAP_SUPPORT PPPDEBUG(LOG_DEBUG, ("neg_chap_ms: %d\n", !!(ao->chap_mdtype&MDTYPE_MICROSOFT)) ); PPPDEBUG(LOG_DEBUG, ("neg_chap_ms2: %d\n", !!(ao->chap_mdtype&MDTYPE_MICROSOFT_V2)) ); #endif /* MSCHAP_SUPPORT */ #endif /* CHAP_SUPPORT */ #if EAP_SUPPORT PPPDEBUG(LOG_DEBUG, ("neg_eap: %d\n", ao->neg_eap) ); #endif /* EAP_SUPPORT */ #if 0 /* OLD CODE */ ao->neg_upap = !ppp_settings.refuse_pap && (ppp_settings.passwd[0] != 0 || get_pap_passwd(NULL)); /* ao->neg_chap = (!ppp_settings.refuse_chap || !refuse_mschap || !refuse_mschap_v2) && (passwd[0] != 0 || (hadchap = have_chap_secret(user, (explicit_remote? remote_name: NULL), 0, NULL))); */ /* ao->neg_eap = !refuse_eap && ( passwd[0] != 0 || (hadchap == 1 || (hadchap == -1 && have_chap_secret(ppp_settings.user, (explicit_remote? remote_name: NULL), 0, NULL))) || have_srp_secret(ppp_settings.user, (explicit_remote? remote_name: NULL), 0, NULL)); */ #endif /* OLD CODE */ #if PAP_SUPPORT go->neg_upap = 0; #endif /* PAP_SUPPORT */ #if CHAP_SUPPORT go->neg_chap = 0; go->chap_mdtype = MDTYPE_NONE; #endif /* CHAP_SUPPORT */ #if EAP_SUPPORT go->neg_eap = 0; #endif /* EAP_SUPPORT */ return; #if 0 /* FIXME: find what the below stuff do */ int hadchap; hadchap = -1; hadchap = -1; if (go->neg_upap && !uselogin && !have_pap_secret(NULL)) go->neg_upap = 0; if (go->neg_chap) { if (!(hadchap = have_chap_secret((explicit_remote? remote_name: NULL), our_name, 1, NULL))) go->neg_chap = 0; } if (go->neg_eap && (hadchap == 0 || (hadchap == -1 && !have_chap_secret((explicit_remote? remote_name: NULL), our_name, 1, NULL))) && !have_srp_secret((explicit_remote? remote_name: NULL), our_name, 1, NULL)) go->neg_eap = 0; #endif } #if 0 /* UNUSED */ /* * check_passwd - Check the user name and passwd against the PAP secrets * file. If requested, also check against the system password database, * and login the user if OK. * * returns: * UPAP_AUTHNAK: Authentication failed. * UPAP_AUTHACK: Authentication succeeded. * In either case, msg points to an appropriate message. */ int check_passwd(unit, auser, userlen, apasswd, passwdlen, msg) int unit; char *auser; int userlen; char *apasswd; int passwdlen; char **msg; { return UPAP_AUTHNAK; int ret; char *filename; FILE *f; struct wordlist *addrs = NULL, *opts = NULL; char passwd[256], user[256]; char secret[MAXWORDLEN]; static int attempts = 0; /* * Make copies of apasswd and auser, then null-terminate them. * If there are unprintable characters in the password, make * them visible. */ slprintf(ppp_settings.passwd, sizeof(ppp_settings.passwd), "%.*v", passwdlen, apasswd); slprintf(ppp_settings.user, sizeof(ppp_settings.user), "%.*v", userlen, auser); *msg = ""; /* * Check if a plugin wants to handle this. */ if (pap_auth_hook) { ret = (*pap_auth_hook)(ppp_settings.user, ppp_settings.passwd, msg, &addrs, &opts); if (ret >= 0) { /* note: set_allowed_addrs() saves opts (but not addrs): don't free it! */ if (ret) set_allowed_addrs(unit, addrs, opts); else if (opts != 0) free_wordlist(opts); if (addrs != 0) free_wordlist(addrs); BZERO(ppp_settings.passwd, sizeof(ppp_settings.passwd)); return ret? UPAP_AUTHACK: UPAP_AUTHNAK; } } /* * Open the file of pap secrets and scan for a suitable secret * for authenticating this user. */ filename = _PATH_UPAPFILE; addrs = opts = NULL; ret = UPAP_AUTHNAK; f = fopen(filename, "r"); if (f == NULL) { ppp_error("Can't open PAP password file %s: %m", filename); } else { check_access(f, filename); if (scan_authfile(f, ppp_settings.user, our_name, secret, &addrs, &opts, filename, 0) < 0) { ppp_warn("no PAP secret found for %s", user); } else { /* * If the secret is "@login", it means to check * the password against the login database. */ int login_secret = strcmp(secret, "@login") == 0; ret = UPAP_AUTHACK; if (uselogin || login_secret) { /* login option or secret is @login */ if (session_full(ppp_settings.user, ppp_settings.passwd, devnam, msg) == 0) { ret = UPAP_AUTHNAK; } } else if (session_mgmt) { if (session_check(ppp_settings.user, NULL, devnam, NULL) == 0) { ppp_warn("Peer %q failed PAP Session verification", user); ret = UPAP_AUTHNAK; } } if (secret[0] != 0 && !login_secret) { /* password given in pap-secrets - must match */ if ((cryptpap || strcmp(ppp_settings.passwd, secret) != 0) && strcmp(crypt(ppp_settings.passwd, secret), secret) != 0) ret = UPAP_AUTHNAK; } } fclose(f); } if (ret == UPAP_AUTHNAK) { if (**msg == 0) *msg = "Login incorrect"; /* * XXX can we ever get here more than once?? * Frustrate passwd stealer programs. * Allow 10 tries, but start backing off after 3 (stolen from login). * On 10'th, drop the connection. */ if (attempts++ >= 10) { ppp_warn("%d LOGIN FAILURES ON %s, %s", attempts, devnam, user); lcp_close(pcb, "login failed"); } if (attempts > 3) sleep((u_int) (attempts - 3) * 5); if (opts != NULL) free_wordlist(opts); } else { attempts = 0; /* Reset count */ if (**msg == 0) *msg = "Login ok"; set_allowed_addrs(unit, addrs, opts); } if (addrs != NULL) free_wordlist(addrs); BZERO(ppp_settings.passwd, sizeof(ppp_settings.passwd)); BZERO(secret, sizeof(secret)); return ret; } /* * null_login - Check if a username of "" and a password of "" are * acceptable, and iff so, set the list of acceptable IP addresses * and return 1. */ static int null_login(unit) int unit; { char *filename; FILE *f; int i, ret; struct wordlist *addrs, *opts; char secret[MAXWORDLEN]; /* * Check if a plugin wants to handle this. */ ret = -1; if (null_auth_hook) ret = (*null_auth_hook)(&addrs, &opts); /* * Open the file of pap secrets and scan for a suitable secret. */ if (ret <= 0) { filename = _PATH_UPAPFILE; addrs = NULL; f = fopen(filename, "r"); if (f == NULL) return 0; check_access(f, filename); i = scan_authfile(f, "", our_name, secret, &addrs, &opts, filename, 0); ret = i >= 0 && secret[0] == 0; BZERO(secret, sizeof(secret)); fclose(f); } if (ret) set_allowed_addrs(unit, addrs, opts); else if (opts != 0) free_wordlist(opts); if (addrs != 0) free_wordlist(addrs); return ret; } /* * get_pap_passwd - get a password for authenticating ourselves with * our peer using PAP. Returns 1 on success, 0 if no suitable password * could be found. * Assumes passwd points to MAXSECRETLEN bytes of space (if non-null). */ static int get_pap_passwd(passwd) char *passwd; { char *filename; FILE *f; int ret; char secret[MAXWORDLEN]; /* * Check whether a plugin wants to supply this. */ if (pap_passwd_hook) { ret = (*pap_passwd_hook)(ppp_settings,user, ppp_settings.passwd); if (ret >= 0) return ret; } filename = _PATH_UPAPFILE; f = fopen(filename, "r"); if (f == NULL) return 0; check_access(f, filename); ret = scan_authfile(f, user, (remote_name[0]? remote_name: NULL), secret, NULL, NULL, filename, 0); fclose(f); if (ret < 0) return 0; if (passwd != NULL) strlcpy(passwd, secret, MAXSECRETLEN); BZERO(secret, sizeof(secret)); return 1; } /* * have_pap_secret - check whether we have a PAP file with any * secrets that we could possibly use for authenticating the peer. */ static int have_pap_secret(lacks_ipp) int *lacks_ipp; { FILE *f; int ret; char *filename; struct wordlist *addrs; /* let the plugin decide, if there is one */ if (pap_check_hook) { ret = (*pap_check_hook)(); if (ret >= 0) return ret; } filename = _PATH_UPAPFILE; f = fopen(filename, "r"); if (f == NULL) return 0; ret = scan_authfile(f, (explicit_remote? remote_name: NULL), our_name, NULL, &addrs, NULL, filename, 0); fclose(f); if (ret >= 0 && !some_ip_ok(addrs)) { if (lacks_ipp != 0) *lacks_ipp = 1; ret = -1; } if (addrs != 0) free_wordlist(addrs); return ret >= 0; } /* * have_chap_secret - check whether we have a CHAP file with a * secret that we could possibly use for authenticating `client' * on `server'. Either can be the null string, meaning we don't * know the identity yet. */ static int have_chap_secret(client, server, need_ip, lacks_ipp) char *client; char *server; int need_ip; int *lacks_ipp; { FILE *f; int ret; char *filename; struct wordlist *addrs; if (chap_check_hook) { ret = (*chap_check_hook)(); if (ret >= 0) { return ret; } } filename = _PATH_CHAPFILE; f = fopen(filename, "r"); if (f == NULL) return 0; if (client != NULL && client[0] == 0) client = NULL; else if (server != NULL && server[0] == 0) server = NULL; ret = scan_authfile(f, client, server, NULL, &addrs, NULL, filename, 0); fclose(f); if (ret >= 0 && need_ip && !some_ip_ok(addrs)) { if (lacks_ipp != 0) *lacks_ipp = 1; ret = -1; } if (addrs != 0) free_wordlist(addrs); return ret >= 0; } /* * have_srp_secret - check whether we have a SRP file with a * secret that we could possibly use for authenticating `client' * on `server'. Either can be the null string, meaning we don't * know the identity yet. */ static int have_srp_secret(client, server, need_ip, lacks_ipp) char *client; char *server; int need_ip; int *lacks_ipp; { FILE *f; int ret; char *filename; struct wordlist *addrs; filename = _PATH_SRPFILE; f = fopen(filename, "r"); if (f == NULL) return 0; if (client != NULL && client[0] == 0) client = NULL; else if (server != NULL && server[0] == 0) server = NULL; ret = scan_authfile(f, client, server, NULL, &addrs, NULL, filename, 0); fclose(f); if (ret >= 0 && need_ip && !some_ip_ok(addrs)) { if (lacks_ipp != 0) *lacks_ipp = 1; ret = -1; } if (addrs != 0) free_wordlist(addrs); return ret >= 0; } #endif /* UNUSED */ /* * get_secret - open the CHAP secret file and return the secret * for authenticating the given client on the given server. * (We could be either client or server). */ int get_secret(ppp_pcb *pcb, char *client, char *server, char *secret, int *secret_len, int am_server) { int len; LWIP_UNUSED_ARG(server); LWIP_UNUSED_ARG(am_server); if(!client || !client[0] || !pcb->settings.user || !pcb->settings.passwd || strcmp(client, pcb->settings.user)) { return 0; } len = (int)strlen(pcb->settings.passwd); if (len > MAXSECRETLEN) { ppp_error("Secret for %s on %s is too long", client, server); len = MAXSECRETLEN; } MEMCPY(secret, pcb->settings.passwd, len); *secret_len = len; return 1; /* FIXME: clean that */ #if 0 strlcpy(rname, ppp_settings.user, sizeof(rname)); /* strlcpy(rname, ppp_settings.user, sizeof(rname)); strlcpy(secret, ppp_settings.passwd, sizeof(secret)); secret_len = strlen(secret); */ FILE *f; int ret, len; char *filename; struct wordlist *addrs, *opts; char secbuf[MAXWORDLEN]; struct wordlist *addrs; addrs = NULL; if (!am_server && ppp_settings.passwd[0] != 0) { strlcpy(secbuf, ppp_settings.passwd, sizeof(secbuf)); } else if (!am_server && chap_passwd_hook) { if ( (*chap_passwd_hook)(client, secbuf) < 0) { ppp_error("Unable to obtain CHAP password for %s on %s from plugin", client, server); return 0; } } else { filename = _PATH_CHAPFILE; addrs = NULL; secbuf[0] = 0; f = fopen(filename, "r"); if (f == NULL) { ppp_error("Can't open chap secret file %s: %m", filename); return 0; } check_access(f, filename); ret = scan_authfile(f, client, server, secbuf, &addrs, &opts, filename, 0); fclose(f); if (ret < 0) return 0; if (am_server) set_allowed_addrs(unit, addrs, opts); else if (opts != 0) free_wordlist(opts); if (addrs != 0) free_wordlist(addrs); } len = strlen(secbuf); if (len > MAXSECRETLEN) { ppp_error("Secret for %s on %s is too long", client, server); len = MAXSECRETLEN; } MEMCPY(secret, secbuf, len); BZERO(secbuf, sizeof(secbuf)); *secret_len = len; return 1; #endif } #if 0 /* UNUSED */ /* * get_srp_secret - open the SRP secret file and return the secret * for authenticating the given client on the given server. * (We could be either client or server). */ int get_srp_secret(unit, client, server, secret, am_server) int unit; char *client; char *server; char *secret; int am_server; { FILE *fp; int ret; char *filename; struct wordlist *addrs, *opts; if (!am_server && ppp_settings.passwd[0] != '\0') { strlcpy(secret, ppp_settings.passwd, MAXWORDLEN); } else { filename = _PATH_SRPFILE; addrs = NULL; fp = fopen(filename, "r"); if (fp == NULL) { ppp_error("Can't open srp secret file %s: %m", filename); return 0; } check_access(fp, filename); secret[0] = '\0'; ret = scan_authfile(fp, client, server, secret, &addrs, &opts, filename, am_server); fclose(fp); if (ret < 0) return 0; if (am_server) set_allowed_addrs(unit, addrs, opts); else if (opts != NULL) free_wordlist(opts); if (addrs != NULL) free_wordlist(addrs); } return 1; } /* * set_allowed_addrs() - set the list of allowed addresses. * Also looks for `--' indicating options to apply for this peer * and leaves the following words in extra_options. */ static void set_allowed_addrs(unit, addrs, opts) int unit; struct wordlist *addrs; struct wordlist *opts; { int n; struct wordlist *ap, **plink; struct permitted_ip *ip; char *ptr_word, *ptr_mask; struct hostent *hp; struct netent *np; u32_t a, mask, ah, offset; struct ipcp_options *wo = &ipcp_wantoptions[unit]; u32_t suggested_ip = 0; if (addresses[unit] != NULL) free(addresses[unit]); addresses[unit] = NULL; if (extra_options != NULL) free_wordlist(extra_options); extra_options = opts; /* * Count the number of IP addresses given. */ n = wordlist_count(addrs) + wordlist_count(noauth_addrs); if (n == 0) return; ip = (struct permitted_ip *) malloc((n + 1) * sizeof(struct permitted_ip)); if (ip == 0) return; /* temporarily append the noauth_addrs list to addrs */ for (plink = &addrs; *plink != NULL; plink = &(*plink)->next) ; *plink = noauth_addrs; n = 0; for (ap = addrs; ap != NULL; ap = ap->next) { /* "-" means no addresses authorized, "*" means any address allowed */ ptr_word = ap->word; if (strcmp(ptr_word, "-") == 0) break; if (strcmp(ptr_word, "*") == 0) { ip[n].permit = 1; ip[n].base = ip[n].mask = 0; ++n; break; } ip[n].permit = 1; if (*ptr_word == '!') { ip[n].permit = 0; ++ptr_word; } mask = ~ (u32_t) 0; offset = 0; ptr_mask = strchr (ptr_word, '/'); if (ptr_mask != NULL) { int bit_count; char *endp; bit_count = (int) strtol (ptr_mask+1, &endp, 10); if (bit_count <= 0 || bit_count > 32) { ppp_warn("invalid address length %v in auth. address list", ptr_mask+1); continue; } bit_count = 32 - bit_count; /* # bits in host part */ if (*endp == '+') { offset = ifunit + 1; ++endp; } if (*endp != 0) { ppp_warn("invalid address length syntax: %v", ptr_mask+1); continue; } *ptr_mask = '\0'; mask <<= bit_count; } hp = gethostbyname(ptr_word); if (hp != NULL && hp->h_addrtype == AF_INET) { a = *(u32_t *)hp->h_addr; } else { np = getnetbyname (ptr_word); if (np != NULL && np->n_addrtype == AF_INET) { a = htonl ((u32_t)np->n_net); if (ptr_mask == NULL) { /* calculate appropriate mask for net */ ah = ntohl(a); if (IN_CLASSA(ah)) mask = IN_CLASSA_NET; else if (IN_CLASSB(ah)) mask = IN_CLASSB_NET; else if (IN_CLASSC(ah)) mask = IN_CLASSC_NET; } } else { a = inet_addr (ptr_word); } } if (ptr_mask != NULL) *ptr_mask = '/'; if (a == (u32_t)-1L) { ppp_warn("unknown host %s in auth. address list", ap->word); continue; } if (offset != 0) { if (offset >= ~mask) { ppp_warn("interface unit %d too large for subnet %v", ifunit, ptr_word); continue; } a = htonl((ntohl(a) & mask) + offset); mask = ~(u32_t)0; } ip[n].mask = htonl(mask); ip[n].base = a & ip[n].mask; ++n; if (~mask == 0 && suggested_ip == 0) suggested_ip = a; } *plink = NULL; ip[n].permit = 0; /* make the last entry forbid all addresses */ ip[n].base = 0; /* to terminate the list */ ip[n].mask = 0; addresses[unit] = ip; /* * If the address given for the peer isn't authorized, or if * the user hasn't given one, AND there is an authorized address * which is a single host, then use that if we find one. */ if (suggested_ip != 0 && (wo->hisaddr == 0 || !auth_ip_addr(unit, wo->hisaddr))) { wo->hisaddr = suggested_ip; /* * Do we insist on this address? No, if there are other * addresses authorized than the suggested one. */ if (n > 1) wo->accept_remote = 1; } } /* * auth_ip_addr - check whether the peer is authorized to use * a given IP address. Returns 1 if authorized, 0 otherwise. */ int auth_ip_addr(unit, addr) int unit; u32_t addr; { int ok; /* don't allow loopback or multicast address */ if (bad_ip_adrs(addr)) return 0; if (allowed_address_hook) { ok = allowed_address_hook(addr); if (ok >= 0) return ok; } if (addresses[unit] != NULL) { ok = ip_addr_check(addr, addresses[unit]); if (ok >= 0) return ok; } if (auth_required) return 0; /* no addresses authorized */ return allow_any_ip || privileged || !have_route_to(addr); } static int ip_addr_check(addr, addrs) u32_t addr; struct permitted_ip *addrs; { for (; ; ++addrs) if ((addr & addrs->mask) == addrs->base) return addrs->permit; } /* * bad_ip_adrs - return 1 if the IP address is one we don't want * to use, such as an address in the loopback net or a multicast address. * addr is in network byte order. */ int bad_ip_adrs(addr) u32_t addr; { addr = ntohl(addr); return (addr >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET || IN_MULTICAST(addr) || IN_BADCLASS(addr); } /* * some_ip_ok - check a wordlist to see if it authorizes any * IP address(es). */ static int some_ip_ok(addrs) struct wordlist *addrs; { for (; addrs != 0; addrs = addrs->next) { if (addrs->word[0] == '-') break; if (addrs->word[0] != '!') return 1; /* some IP address is allowed */ } return 0; } /* * auth_number - check whether the remote number is allowed to connect. * Returns 1 if authorized, 0 otherwise. */ int auth_number() { struct wordlist *wp = permitted_numbers; int l; /* Allow all if no authorization list. */ if (!wp) return 1; /* Allow if we have a match in the authorization list. */ while (wp) { /* trailing '*' wildcard */ l = strlen(wp->word); if ((wp->word)[l - 1] == '*') l--; if (!strncasecmp(wp->word, remote_number, l)) return 1; wp = wp->next; } return 0; } /* * check_access - complain if a secret file has too-liberal permissions. */ static void check_access(f, filename) FILE *f; char *filename; { struct stat sbuf; if (fstat(fileno(f), &sbuf) < 0) { ppp_warn("cannot stat secret file %s: %m", filename); } else if ((sbuf.st_mode & (S_IRWXG | S_IRWXO)) != 0) { ppp_warn("Warning - secret file %s has world and/or group access", filename); } } /* * scan_authfile - Scan an authorization file for a secret suitable * for authenticating `client' on `server'. The return value is -1 * if no secret is found, otherwise >= 0. The return value has * NONWILD_CLIENT set if the secret didn't have "*" for the client, and * NONWILD_SERVER set if the secret didn't have "*" for the server. * Any following words on the line up to a "--" (i.e. address authorization * info) are placed in a wordlist and returned in *addrs. Any * following words (extra options) are placed in a wordlist and * returned in *opts. * We assume secret is NULL or points to MAXWORDLEN bytes of space. * Flags are non-zero if we need two colons in the secret in order to * match. */ static int scan_authfile(f, client, server, secret, addrs, opts, filename, flags) FILE *f; char *client; char *server; char *secret; struct wordlist **addrs; struct wordlist **opts; char *filename; int flags; { int newline, xxx; int got_flag, best_flag; FILE *sf; struct wordlist *ap, *addr_list, *alist, **app; char word[MAXWORDLEN]; char atfile[MAXWORDLEN]; char lsecret[MAXWORDLEN]; char *cp; if (addrs != NULL) *addrs = NULL; if (opts != NULL) *opts = NULL; addr_list = NULL; if (!getword(f, word, &newline, filename)) return -1; /* file is empty??? */ newline = 1; best_flag = -1; for (;;) { /* * Skip until we find a word at the start of a line. */ while (!newline && getword(f, word, &newline, filename)) ; if (!newline) break; /* got to end of file */ /* * Got a client - check if it's a match or a wildcard. */ got_flag = 0; if (client != NULL && strcmp(word, client) != 0 && !ISWILD(word)) { newline = 0; continue; } if (!ISWILD(word)) got_flag = NONWILD_CLIENT; /* * Now get a server and check if it matches. */ if (!getword(f, word, &newline, filename)) break; if (newline) continue; if (!ISWILD(word)) { if (server != NULL && strcmp(word, server) != 0) continue; got_flag |= NONWILD_SERVER; } /* * Got some sort of a match - see if it's better than what * we have already. */ if (got_flag <= best_flag) continue; /* * Get the secret. */ if (!getword(f, word, &newline, filename)) break; if (newline) continue; /* * SRP-SHA1 authenticator should never be reading secrets from * a file. (Authenticatee may, though.) */ if (flags && ((cp = strchr(word, ':')) == NULL || strchr(cp + 1, ':') == NULL)) continue; if (secret != NULL) { /* * Special syntax: @/pathname means read secret from file. */ if (word[0] == '@' && word[1] == '/') { strlcpy(atfile, word+1, sizeof(atfile)); if ((sf = fopen(atfile, "r")) == NULL) { ppp_warn("can't open indirect secret file %s", atfile); continue; } check_access(sf, atfile); if (!getword(sf, word, &xxx, atfile)) { ppp_warn("no secret in indirect secret file %s", atfile); fclose(sf); continue; } fclose(sf); } strlcpy(lsecret, word, sizeof(lsecret)); } /* * Now read address authorization info and make a wordlist. */ app = &alist; for (;;) { if (!getword(f, word, &newline, filename) || newline) break; ap = (struct wordlist *) malloc(sizeof(struct wordlist) + strlen(word) + 1); if (ap == NULL) novm("authorized addresses"); ap->word = (char *) (ap + 1); strcpy(ap->word, word); *app = ap; app = &ap->next; } *app = NULL; /* * This is the best so far; remember it. */ best_flag = got_flag; if (addr_list) free_wordlist(addr_list); addr_list = alist; if (secret != NULL) strlcpy(secret, lsecret, MAXWORDLEN); if (!newline) break; } /* scan for a -- word indicating the start of options */ for (app = &addr_list; (ap = *app) != NULL; app = &ap->next) if (strcmp(ap->word, "--") == 0) break; /* ap = start of options */ if (ap != NULL) { ap = ap->next; /* first option */ free(*app); /* free the "--" word */ *app = NULL; /* terminate addr list */ } if (opts != NULL) *opts = ap; else if (ap != NULL) free_wordlist(ap); if (addrs != NULL) *addrs = addr_list; else if (addr_list != NULL) free_wordlist(addr_list); return best_flag; } /* * wordlist_count - return the number of items in a wordlist */ static int wordlist_count(wp) struct wordlist *wp; { int n; for (n = 0; wp != NULL; wp = wp->next) ++n; return n; } /* * free_wordlist - release memory allocated for a wordlist. */ static void free_wordlist(wp) struct wordlist *wp; { struct wordlist *next; while (wp != NULL) { next = wp->next; free(wp); wp = next; } } #endif /* UNUSED */ #endif /* PPP_SUPPORT */ ocproxy-1.60/lwip/src/netif/ppp/ccp.c000066400000000000000000001304211303453231400175210ustar00rootroot00000000000000/* * ccp.c - PPP Compression Control Protocol. * * Copyright (c) 1994-2002 Paul Mackerras. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. The name(s) of the authors of this software must not be used to * endorse or promote products derived from this software without * prior written permission. * * 3. Redistributions of any form whatsoever must retain the following * acknowledgment: * "This product includes software developed by Paul Mackerras * ". * * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "lwip/opt.h" #if PPP_SUPPORT && CCP_SUPPORT /* don't build if not configured for use in lwipopts.h */ #include #include #include "netif/ppp/ppp_impl.h" #include "netif/ppp/fsm.h" #include "netif/ppp/ccp.h" #include #ifdef MPPE #include "netif/ppp/chap_ms.h" /* mppe_xxxx_key, mppe_keys_set */ #include "netif/ppp/lcp.h" /* lcp_close(), lcp_fsm */ #endif /* * Unfortunately there is a bug in zlib which means that using a * size of 8 (window size = 256) for Deflate compression will cause * buffer overruns and kernel crashes in the deflate module. * Until this is fixed we only accept sizes in the range 9 .. 15. * Thanks to James Carlson for pointing this out. */ #define DEFLATE_MIN_WORKS 9 /* * Command-line options. */ static int setbsdcomp (char **); static int setdeflate (char **); static char bsd_value[8]; static char deflate_value[8]; /* * Option variables. */ #ifdef MPPE bool refuse_mppe_stateful = 1; /* Allow stateful mode? */ #endif #if PPP_OPTIONS static option_t ccp_option_list[] = { { "noccp", o_bool, &ccp_protent.enabled_flag, "Disable CCP negotiation" }, { "-ccp", o_bool, &ccp_protent.enabled_flag, "Disable CCP negotiation", OPT_ALIAS }, { "bsdcomp", o_special, (void *)setbsdcomp, "Request BSD-Compress packet compression", OPT_PRIO | OPT_A2STRVAL | OPT_STATIC, bsd_value }, { "nobsdcomp", o_bool, &ccp_wantoptions[0].bsd_compress, "don't allow BSD-Compress", OPT_PRIOSUB | OPT_A2CLR, &ccp_allowoptions[0].bsd_compress }, { "-bsdcomp", o_bool, &ccp_wantoptions[0].bsd_compress, "don't allow BSD-Compress", OPT_ALIAS | OPT_PRIOSUB | OPT_A2CLR, &ccp_allowoptions[0].bsd_compress }, { "deflate", o_special, (void *)setdeflate, "request Deflate compression", OPT_PRIO | OPT_A2STRVAL | OPT_STATIC, deflate_value }, { "nodeflate", o_bool, &ccp_wantoptions[0].deflate, "don't allow Deflate compression", OPT_PRIOSUB | OPT_A2CLR, &ccp_allowoptions[0].deflate }, { "-deflate", o_bool, &ccp_wantoptions[0].deflate, "don't allow Deflate compression", OPT_ALIAS | OPT_PRIOSUB | OPT_A2CLR, &ccp_allowoptions[0].deflate }, { "nodeflatedraft", o_bool, &ccp_wantoptions[0].deflate_draft, "don't use draft deflate #", OPT_A2COPY, &ccp_allowoptions[0].deflate_draft }, { "predictor1", o_bool, &ccp_wantoptions[0].predictor_1, "request Predictor-1", OPT_PRIO | 1 }, { "nopredictor1", o_bool, &ccp_wantoptions[0].predictor_1, "don't allow Predictor-1", OPT_PRIOSUB | OPT_A2CLR, &ccp_allowoptions[0].predictor_1 }, { "-predictor1", o_bool, &ccp_wantoptions[0].predictor_1, "don't allow Predictor-1", OPT_ALIAS | OPT_PRIOSUB | OPT_A2CLR, &ccp_allowoptions[0].predictor_1 }, #ifdef MPPE /* MPPE options are symmetrical ... we only set wantoptions here */ { "require-mppe", o_bool, &ccp_wantoptions[0].mppe, "require MPPE encryption", OPT_PRIO | MPPE_OPT_40 | MPPE_OPT_128 }, { "+mppe", o_bool, &ccp_wantoptions[0].mppe, "require MPPE encryption", OPT_ALIAS | OPT_PRIO | MPPE_OPT_40 | MPPE_OPT_128 }, { "nomppe", o_bool, &ccp_wantoptions[0].mppe, "don't allow MPPE encryption", OPT_PRIO }, { "-mppe", o_bool, &ccp_wantoptions[0].mppe, "don't allow MPPE encryption", OPT_ALIAS | OPT_PRIO }, /* We use ccp_allowoptions[0].mppe as a junk var ... it is reset later */ { "require-mppe-40", o_bool, &ccp_allowoptions[0].mppe, "require MPPE 40-bit encryption", OPT_PRIO | OPT_A2OR | MPPE_OPT_40, &ccp_wantoptions[0].mppe }, { "+mppe-40", o_bool, &ccp_allowoptions[0].mppe, "require MPPE 40-bit encryption", OPT_PRIO | OPT_A2OR | MPPE_OPT_40, &ccp_wantoptions[0].mppe }, { "nomppe-40", o_bool, &ccp_allowoptions[0].mppe, "don't allow MPPE 40-bit encryption", OPT_PRIOSUB | OPT_A2CLRB | MPPE_OPT_40, &ccp_wantoptions[0].mppe }, { "-mppe-40", o_bool, &ccp_allowoptions[0].mppe, "don't allow MPPE 40-bit encryption", OPT_ALIAS | OPT_PRIOSUB | OPT_A2CLRB | MPPE_OPT_40, &ccp_wantoptions[0].mppe }, { "require-mppe-128", o_bool, &ccp_allowoptions[0].mppe, "require MPPE 128-bit encryption", OPT_PRIO | OPT_A2OR | MPPE_OPT_128, &ccp_wantoptions[0].mppe }, { "+mppe-128", o_bool, &ccp_allowoptions[0].mppe, "require MPPE 128-bit encryption", OPT_ALIAS | OPT_PRIO | OPT_A2OR | MPPE_OPT_128, &ccp_wantoptions[0].mppe }, { "nomppe-128", o_bool, &ccp_allowoptions[0].mppe, "don't allow MPPE 128-bit encryption", OPT_PRIOSUB | OPT_A2CLRB | MPPE_OPT_128, &ccp_wantoptions[0].mppe }, { "-mppe-128", o_bool, &ccp_allowoptions[0].mppe, "don't allow MPPE 128-bit encryption", OPT_ALIAS | OPT_PRIOSUB | OPT_A2CLRB | MPPE_OPT_128, &ccp_wantoptions[0].mppe }, /* strange one; we always request stateless, but will we allow stateful? */ { "mppe-stateful", o_bool, &refuse_mppe_stateful, "allow MPPE stateful mode", OPT_PRIO }, { "nomppe-stateful", o_bool, &refuse_mppe_stateful, "disallow MPPE stateful mode", OPT_PRIO | 1 }, #endif /* MPPE */ { NULL } }; #endif /* PPP_OPTIONS */ /* * Protocol entry points from main code. */ static void ccp_init (int unit); static void ccp_open (int unit); static void ccp_close (int unit, char *); static void ccp_lowerup (int unit); static void ccp_lowerdown (int); static void ccp_input (int unit, u_char *pkt, int len); static void ccp_protrej (int unit); #if PRINTPKT_SUPPORT static int ccp_printpkt (u_char *pkt, int len, void (*printer) (void *, char *, ...), void *arg); #endif /* PRINTPKT_SUPPORT */ static void ccp_datainput (int unit, u_char *pkt, int len); const struct protent ccp_protent = { PPP_CCP, ccp_init, ccp_input, ccp_protrej, ccp_lowerup, ccp_lowerdown, ccp_open, ccp_close, #if PRINTPKT_SUPPORT ccp_printpkt, #endif /* PRINTPKT_SUPPORT */ ccp_datainput, 1, #if PRINTPKT_SUPPORT "CCP", "Compressed", #endif /* PRINTPKT_SUPPORT */ #if PPP_OPTIONS ccp_option_list, NULL, #endif /* PPP_OPTIONS */ #if DEMAND_SUPPORT NULL, NULL #endif /* DEMAND_SUPPORT */ }; fsm ccp_fsm[NUM_PPP]; ccp_options ccp_wantoptions[NUM_PPP]; /* what to request the peer to use */ ccp_options ccp_gotoptions[NUM_PPP]; /* what the peer agreed to do */ ccp_options ccp_allowoptions[NUM_PPP]; /* what we'll agree to do */ ccp_options ccp_hisoptions[NUM_PPP]; /* what we agreed to do */ /* * Callbacks for fsm code. */ static void ccp_resetci (fsm *); static int ccp_cilen (fsm *); static void ccp_addci (fsm *, u_char *, int *); static int ccp_ackci (fsm *, u_char *, int); static int ccp_nakci (fsm *, u_char *, int, int); static int ccp_rejci (fsm *, u_char *, int); static int ccp_reqci (fsm *, u_char *, int *, int); static void ccp_up (fsm *); static void ccp_down (fsm *); static int ccp_extcode (fsm *, int, int, u_char *, int); static void ccp_rack_timeout (void *); static char *method_name (ccp_options *, ccp_options *); static const fsm_callbacks ccp_callbacks = { ccp_resetci, ccp_cilen, ccp_addci, ccp_ackci, ccp_nakci, ccp_rejci, ccp_reqci, ccp_up, ccp_down, NULL, NULL, NULL, NULL, ccp_extcode, "CCP" }; /* * Do we want / did we get any compression? */ #define ANY_COMPRESS(opt) ((opt).deflate || (opt).bsd_compress \ || (opt).predictor_1 || (opt).predictor_2 \ || (opt).mppe) /* * Local state (mainly for handling reset-reqs and reset-acks). */ static int ccp_localstate[NUM_PPP]; #define RACK_PENDING 1 /* waiting for reset-ack */ #define RREQ_REPEAT 2 /* send another reset-req if no reset-ack */ #define RACKTIMEOUT 1 /* second */ static int all_rejected[NUM_PPP]; /* we rejected all peer's options */ /* * Option parsing */ static int setbsdcomp(argv) char **argv; { int rbits, abits; char *str, *endp; str = *argv; abits = rbits = strtol(str, &endp, 0); if (endp != str && *endp == ',') { str = endp + 1; abits = strtol(str, &endp, 0); } if (*endp != 0 || endp == str) { option_error("invalid parameter '%s' for bsdcomp option", *argv); return 0; } if ((rbits != 0 && (rbits < BSD_MIN_BITS || rbits > BSD_MAX_BITS)) || (abits != 0 && (abits < BSD_MIN_BITS || abits > BSD_MAX_BITS))) { option_error("bsdcomp option values must be 0 or %d .. %d", BSD_MIN_BITS, BSD_MAX_BITS); return 0; } if (rbits > 0) { ccp_wantoptions[0].bsd_compress = 1; ccp_wantoptions[0].bsd_bits = rbits; } else ccp_wantoptions[0].bsd_compress = 0; if (abits > 0) { ccp_allowoptions[0].bsd_compress = 1; ccp_allowoptions[0].bsd_bits = abits; } else ccp_allowoptions[0].bsd_compress = 0; slprintf(bsd_value, sizeof(bsd_value), rbits == abits? "%d": "%d,%d", rbits, abits); return 1; } static int setdeflate(argv) char **argv; { int rbits, abits; char *str, *endp; str = *argv; abits = rbits = strtol(str, &endp, 0); if (endp != str && *endp == ',') { str = endp + 1; abits = strtol(str, &endp, 0); } if (*endp != 0 || endp == str) { option_error("invalid parameter '%s' for deflate option", *argv); return 0; } if ((rbits != 0 && (rbits < DEFLATE_MIN_SIZE || rbits > DEFLATE_MAX_SIZE)) || (abits != 0 && (abits < DEFLATE_MIN_SIZE || abits > DEFLATE_MAX_SIZE))) { option_error("deflate option values must be 0 or %d .. %d", DEFLATE_MIN_SIZE, DEFLATE_MAX_SIZE); return 0; } if (rbits == DEFLATE_MIN_SIZE || abits == DEFLATE_MIN_SIZE) { if (rbits == DEFLATE_MIN_SIZE) rbits = DEFLATE_MIN_WORKS; if (abits == DEFLATE_MIN_SIZE) abits = DEFLATE_MIN_WORKS; warn("deflate option value of %d changed to %d to avoid zlib bug", DEFLATE_MIN_SIZE, DEFLATE_MIN_WORKS); } if (rbits > 0) { ccp_wantoptions[0].deflate = 1; ccp_wantoptions[0].deflate_size = rbits; } else ccp_wantoptions[0].deflate = 0; if (abits > 0) { ccp_allowoptions[0].deflate = 1; ccp_allowoptions[0].deflate_size = abits; } else ccp_allowoptions[0].deflate = 0; slprintf(deflate_value, sizeof(deflate_value), rbits == abits? "%d": "%d,%d", rbits, abits); return 1; } /* * ccp_init - initialize CCP. */ static void ccp_init(unit) int unit; { fsm *f = &ccp_fsm[unit]; f->unit = unit; f->protocol = PPP_CCP; f->callbacks = &ccp_callbacks; fsm_init(f); memset(&ccp_wantoptions[unit], 0, sizeof(ccp_options)); memset(&ccp_gotoptions[unit], 0, sizeof(ccp_options)); memset(&ccp_allowoptions[unit], 0, sizeof(ccp_options)); memset(&ccp_hisoptions[unit], 0, sizeof(ccp_options)); ccp_wantoptions[0].deflate = 1; ccp_wantoptions[0].deflate_size = DEFLATE_MAX_SIZE; ccp_wantoptions[0].deflate_correct = 1; ccp_wantoptions[0].deflate_draft = 1; ccp_allowoptions[0].deflate = 1; ccp_allowoptions[0].deflate_size = DEFLATE_MAX_SIZE; ccp_allowoptions[0].deflate_correct = 1; ccp_allowoptions[0].deflate_draft = 1; ccp_wantoptions[0].bsd_compress = 1; ccp_wantoptions[0].bsd_bits = BSD_MAX_BITS; ccp_allowoptions[0].bsd_compress = 1; ccp_allowoptions[0].bsd_bits = BSD_MAX_BITS; ccp_allowoptions[0].predictor_1 = 1; } /* * ccp_open - CCP is allowed to come up. */ static void ccp_open(unit) int unit; { fsm *f = &ccp_fsm[unit]; if (f->state != OPENED) ccp_flags_set(unit, 1, 0); /* * Find out which compressors the kernel supports before * deciding whether to open in silent mode. */ ccp_resetci(f); if (!ANY_COMPRESS(ccp_gotoptions[unit])) f->flags |= OPT_SILENT; fsm_open(f); } /* * ccp_close - Terminate CCP. */ static void ccp_close(unit, reason) int unit; char *reason; { ccp_flags_set(unit, 0, 0); fsm_close(&ccp_fsm[unit], reason); } /* * ccp_lowerup - we may now transmit CCP packets. */ static void ccp_lowerup(unit) int unit; { fsm_lowerup(&ccp_fsm[unit]); } /* * ccp_lowerdown - we may not transmit CCP packets. */ static void ccp_lowerdown(unit) int unit; { fsm_lowerdown(&ccp_fsm[unit]); } /* * ccp_input - process a received CCP packet. */ static void ccp_input(unit, p, len) int unit; u_char *p; int len; { fsm *f = &ccp_fsm[unit]; int oldstate; /* * Check for a terminate-request so we can print a message. */ oldstate = f->state; fsm_input(f, p, len); if (oldstate == OPENED && p[0] == TERMREQ && f->state != OPENED) { notice("Compression disabled by peer."); #ifdef MPPE if (ccp_gotoptions[unit].mppe) { error("MPPE disabled, closing LCP"); lcp_close(unit, "MPPE disabled by peer"); } #endif } /* * If we get a terminate-ack and we're not asking for compression, * close CCP. */ if (oldstate == REQSENT && p[0] == TERMACK && !ANY_COMPRESS(ccp_gotoptions[unit])) ccp_close(unit, "No compression negotiated"); } /* * Handle a CCP-specific code. */ static int ccp_extcode(f, code, id, p, len) fsm *f; int code, id; u_char *p; int len; { switch (code) { case CCP_RESETREQ: if (f->state != OPENED) break; /* send a reset-ack, which the transmitter will see and reset its compression state. */ fsm_sdata(f, CCP_RESETACK, id, NULL, 0); break; case CCP_RESETACK: if (ccp_localstate[f->unit] & RACK_PENDING && id == f->reqid) { ccp_localstate[f->unit] &= ~(RACK_PENDING | RREQ_REPEAT); UNTIMEOUT(ccp_rack_timeout, f); } break; default: return 0; } return 1; } /* * ccp_protrej - peer doesn't talk CCP. */ static void ccp_protrej(unit) int unit; { ccp_flags_set(unit, 0, 0); fsm_lowerdown(&ccp_fsm[unit]); #ifdef MPPE if (ccp_gotoptions[unit].mppe) { error("MPPE required but peer negotiation failed"); lcp_close(unit, "MPPE required but peer negotiation failed"); } #endif } /* * ccp_resetci - initialize at start of negotiation. */ static void ccp_resetci(f) fsm *f; { ccp_options *go = &ccp_gotoptions[f->unit]; u_char opt_buf[CCP_MAX_OPTION_LENGTH]; *go = ccp_wantoptions[f->unit]; all_rejected[f->unit] = 0; #ifdef MPPE if (go->mppe) { ccp_options *ao = &ccp_allowoptions[f->unit]; int auth_mschap_bits = auth_done[f->unit]; int numbits; /* * Start with a basic sanity check: mschap[v2] auth must be in * exactly one direction. RFC 3079 says that the keys are * 'derived from the credentials of the peer that initiated the call', * however the PPP protocol doesn't have such a concept, and pppd * cannot get this info externally. Instead we do the best we can. * NB: If MPPE is required, all other compression opts are invalid. * So, we return right away if we can't do it. */ /* Leave only the mschap auth bits set */ auth_mschap_bits &= (CHAP_MS_WITHPEER | CHAP_MS_PEER | CHAP_MS2_WITHPEER | CHAP_MS2_PEER); /* Count the mschap auths */ auth_mschap_bits >>= CHAP_MS_SHIFT; numbits = 0; do { numbits += auth_mschap_bits & 1; auth_mschap_bits >>= 1; } while (auth_mschap_bits); if (numbits > 1) { error("MPPE required, but auth done in both directions."); lcp_close(f->unit, "MPPE required but not available"); return; } if (!numbits) { error("MPPE required, but MS-CHAP[v2] auth not performed."); lcp_close(f->unit, "MPPE required but not available"); return; } /* A plugin (eg radius) may not have obtained key material. */ if (!mppe_keys_set) { error("MPPE required, but keys are not available. " "Possible plugin problem?"); lcp_close(f->unit, "MPPE required but not available"); return; } /* LM auth not supported for MPPE */ if (auth_done[f->unit] & (CHAP_MS_WITHPEER | CHAP_MS_PEER)) { /* This might be noise */ if (go->mppe & MPPE_OPT_40) { notice("Disabling 40-bit MPPE; MS-CHAP LM not supported"); go->mppe &= ~MPPE_OPT_40; ccp_wantoptions[f->unit].mppe &= ~MPPE_OPT_40; } } /* Last check: can we actually negotiate something? */ if (!(go->mppe & (MPPE_OPT_40 | MPPE_OPT_128))) { /* Could be misconfig, could be 40-bit disabled above. */ error("MPPE required, but both 40-bit and 128-bit disabled."); lcp_close(f->unit, "MPPE required but not available"); return; } /* sync options */ ao->mppe = go->mppe; /* MPPE is not compatible with other compression types */ ao->bsd_compress = go->bsd_compress = 0; ao->predictor_1 = go->predictor_1 = 0; ao->predictor_2 = go->predictor_2 = 0; ao->deflate = go->deflate = 0; } #endif /* MPPE */ /* * Check whether the kernel knows about the various * compression methods we might request. */ #ifdef MPPE if (go->mppe) { opt_buf[0] = CI_MPPE; opt_buf[1] = CILEN_MPPE; MPPE_OPTS_TO_CI(go->mppe, &opt_buf[2]); /* Key material unimportant here. */ if (ccp_test(f->unit, opt_buf, CILEN_MPPE + MPPE_MAX_KEY_LEN, 0) <= 0) { error("MPPE required, but kernel has no support."); lcp_close(f->unit, "MPPE required but not available"); } } #endif if (go->bsd_compress) { opt_buf[0] = CI_BSD_COMPRESS; opt_buf[1] = CILEN_BSD_COMPRESS; opt_buf[2] = BSD_MAKE_OPT(BSD_CURRENT_VERSION, BSD_MIN_BITS); if (ccp_test(f->unit, opt_buf, CILEN_BSD_COMPRESS, 0) <= 0) go->bsd_compress = 0; } if (go->deflate) { if (go->deflate_correct) { opt_buf[0] = CI_DEFLATE; opt_buf[1] = CILEN_DEFLATE; opt_buf[2] = DEFLATE_MAKE_OPT(DEFLATE_MIN_WORKS); opt_buf[3] = DEFLATE_CHK_SEQUENCE; if (ccp_test(f->unit, opt_buf, CILEN_DEFLATE, 0) <= 0) go->deflate_correct = 0; } if (go->deflate_draft) { opt_buf[0] = CI_DEFLATE_DRAFT; opt_buf[1] = CILEN_DEFLATE; opt_buf[2] = DEFLATE_MAKE_OPT(DEFLATE_MIN_WORKS); opt_buf[3] = DEFLATE_CHK_SEQUENCE; if (ccp_test(f->unit, opt_buf, CILEN_DEFLATE, 0) <= 0) go->deflate_draft = 0; } if (!go->deflate_correct && !go->deflate_draft) go->deflate = 0; } if (go->predictor_1) { opt_buf[0] = CI_PREDICTOR_1; opt_buf[1] = CILEN_PREDICTOR_1; if (ccp_test(f->unit, opt_buf, CILEN_PREDICTOR_1, 0) <= 0) go->predictor_1 = 0; } if (go->predictor_2) { opt_buf[0] = CI_PREDICTOR_2; opt_buf[1] = CILEN_PREDICTOR_2; if (ccp_test(f->unit, opt_buf, CILEN_PREDICTOR_2, 0) <= 0) go->predictor_2 = 0; } } /* * ccp_cilen - Return total length of our configuration info. */ static int ccp_cilen(f) fsm *f; { ccp_options *go = &ccp_gotoptions[f->unit]; return (go->bsd_compress? CILEN_BSD_COMPRESS: 0) + (go->deflate? CILEN_DEFLATE: 0) + (go->predictor_1? CILEN_PREDICTOR_1: 0) + (go->predictor_2? CILEN_PREDICTOR_2: 0) + (go->mppe? CILEN_MPPE: 0); } /* * ccp_addci - put our requests in a packet. */ static void ccp_addci(f, p, lenp) fsm *f; u_char *p; int *lenp; { int res; ccp_options *go = &ccp_gotoptions[f->unit]; u_char *p0 = p; /* * Add the compression types that we can receive, in decreasing * preference order. Get the kernel to allocate the first one * in case it gets Acked. */ #ifdef MPPE if (go->mppe) { u_char opt_buf[CILEN_MPPE + MPPE_MAX_KEY_LEN]; p[0] = opt_buf[0] = CI_MPPE; p[1] = opt_buf[1] = CILEN_MPPE; MPPE_OPTS_TO_CI(go->mppe, &p[2]); MPPE_OPTS_TO_CI(go->mppe, &opt_buf[2]); MEMCPY(&opt_buf[CILEN_MPPE], mppe_recv_key, MPPE_MAX_KEY_LEN); res = ccp_test(f->unit, opt_buf, CILEN_MPPE + MPPE_MAX_KEY_LEN, 0); if (res > 0) p += CILEN_MPPE; else /* This shouldn't happen, we've already tested it! */ lcp_close(f->unit, "MPPE required but not available in kernel"); } #endif if (go->deflate) { p[0] = go->deflate_correct? CI_DEFLATE: CI_DEFLATE_DRAFT; p[1] = CILEN_DEFLATE; p[2] = DEFLATE_MAKE_OPT(go->deflate_size); p[3] = DEFLATE_CHK_SEQUENCE; if (p != p0) { p += CILEN_DEFLATE; } else { for (;;) { if (go->deflate_size < DEFLATE_MIN_WORKS) { go->deflate = 0; break; } res = ccp_test(f->unit, p, CILEN_DEFLATE, 0); if (res > 0) { p += CILEN_DEFLATE; break; } else if (res < 0) { go->deflate = 0; break; } --go->deflate_size; p[2] = DEFLATE_MAKE_OPT(go->deflate_size); } } if (p != p0 && go->deflate_correct && go->deflate_draft) { p[0] = CI_DEFLATE_DRAFT; p[1] = CILEN_DEFLATE; p[2] = p[2 - CILEN_DEFLATE]; p[3] = DEFLATE_CHK_SEQUENCE; p += CILEN_DEFLATE; } } if (go->bsd_compress) { p[0] = CI_BSD_COMPRESS; p[1] = CILEN_BSD_COMPRESS; p[2] = BSD_MAKE_OPT(BSD_CURRENT_VERSION, go->bsd_bits); if (p != p0) { p += CILEN_BSD_COMPRESS; /* not the first option */ } else { for (;;) { if (go->bsd_bits < BSD_MIN_BITS) { go->bsd_compress = 0; break; } res = ccp_test(f->unit, p, CILEN_BSD_COMPRESS, 0); if (res > 0) { p += CILEN_BSD_COMPRESS; break; } else if (res < 0) { go->bsd_compress = 0; break; } --go->bsd_bits; p[2] = BSD_MAKE_OPT(BSD_CURRENT_VERSION, go->bsd_bits); } } } /* XXX Should Predictor 2 be preferable to Predictor 1? */ if (go->predictor_1) { p[0] = CI_PREDICTOR_1; p[1] = CILEN_PREDICTOR_1; if (p == p0 && ccp_test(f->unit, p, CILEN_PREDICTOR_1, 0) <= 0) { go->predictor_1 = 0; } else { p += CILEN_PREDICTOR_1; } } if (go->predictor_2) { p[0] = CI_PREDICTOR_2; p[1] = CILEN_PREDICTOR_2; if (p == p0 && ccp_test(f->unit, p, CILEN_PREDICTOR_2, 0) <= 0) { go->predictor_2 = 0; } else { p += CILEN_PREDICTOR_2; } } go->method = (p > p0)? p0[0]: -1; *lenp = p - p0; } /* * ccp_ackci - process a received configure-ack, and return * 1 iff the packet was OK. */ static int ccp_ackci(f, p, len) fsm *f; u_char *p; int len; { ccp_options *go = &ccp_gotoptions[f->unit]; u_char *p0 = p; #ifdef MPPE if (go->mppe) { u_char opt_buf[CILEN_MPPE]; opt_buf[0] = CI_MPPE; opt_buf[1] = CILEN_MPPE; MPPE_OPTS_TO_CI(go->mppe, &opt_buf[2]); if (len < CILEN_MPPE || memcmp(opt_buf, p, CILEN_MPPE)) return 0; p += CILEN_MPPE; len -= CILEN_MPPE; /* XXX Cope with first/fast ack */ if (len == 0) return 1; } #endif if (go->deflate) { if (len < CILEN_DEFLATE || p[0] != (go->deflate_correct? CI_DEFLATE: CI_DEFLATE_DRAFT) || p[1] != CILEN_DEFLATE || p[2] != DEFLATE_MAKE_OPT(go->deflate_size) || p[3] != DEFLATE_CHK_SEQUENCE) return 0; p += CILEN_DEFLATE; len -= CILEN_DEFLATE; /* XXX Cope with first/fast ack */ if (len == 0) return 1; if (go->deflate_correct && go->deflate_draft) { if (len < CILEN_DEFLATE || p[0] != CI_DEFLATE_DRAFT || p[1] != CILEN_DEFLATE || p[2] != DEFLATE_MAKE_OPT(go->deflate_size) || p[3] != DEFLATE_CHK_SEQUENCE) return 0; p += CILEN_DEFLATE; len -= CILEN_DEFLATE; } } if (go->bsd_compress) { if (len < CILEN_BSD_COMPRESS || p[0] != CI_BSD_COMPRESS || p[1] != CILEN_BSD_COMPRESS || p[2] != BSD_MAKE_OPT(BSD_CURRENT_VERSION, go->bsd_bits)) return 0; p += CILEN_BSD_COMPRESS; len -= CILEN_BSD_COMPRESS; /* XXX Cope with first/fast ack */ if (p == p0 && len == 0) return 1; } if (go->predictor_1) { if (len < CILEN_PREDICTOR_1 || p[0] != CI_PREDICTOR_1 || p[1] != CILEN_PREDICTOR_1) return 0; p += CILEN_PREDICTOR_1; len -= CILEN_PREDICTOR_1; /* XXX Cope with first/fast ack */ if (p == p0 && len == 0) return 1; } if (go->predictor_2) { if (len < CILEN_PREDICTOR_2 || p[0] != CI_PREDICTOR_2 || p[1] != CILEN_PREDICTOR_2) return 0; p += CILEN_PREDICTOR_2; len -= CILEN_PREDICTOR_2; /* XXX Cope with first/fast ack */ if (p == p0 && len == 0) return 1; } if (len != 0) return 0; return 1; } /* * ccp_nakci - process received configure-nak. * Returns 1 iff the nak was OK. */ static int ccp_nakci(f, p, len, treat_as_reject) fsm *f; u_char *p; int len; int treat_as_reject; { ccp_options *go = &ccp_gotoptions[f->unit]; ccp_options no; /* options we've seen already */ ccp_options try; /* options to ask for next time */ memset(&no, 0, sizeof(no)); try = *go; #ifdef MPPE if (go->mppe && len >= CILEN_MPPE && p[0] == CI_MPPE && p[1] == CILEN_MPPE) { no.mppe = 1; /* * Peer wants us to use a different strength or other setting. * Fail if we aren't willing to use his suggestion. */ MPPE_CI_TO_OPTS(&p[2], try.mppe); if ((try.mppe & MPPE_OPT_STATEFUL) && refuse_mppe_stateful) { error("Refusing MPPE stateful mode offered by peer"); try.mppe = 0; } else if (((go->mppe | MPPE_OPT_STATEFUL) & try.mppe) != try.mppe) { /* Peer must have set options we didn't request (suggest) */ try.mppe = 0; } if (!try.mppe) { error("MPPE required but peer negotiation failed"); lcp_close(f->unit, "MPPE required but peer negotiation failed"); } } #endif /* MPPE */ if (go->deflate && len >= CILEN_DEFLATE && p[0] == (go->deflate_correct? CI_DEFLATE: CI_DEFLATE_DRAFT) && p[1] == CILEN_DEFLATE) { no.deflate = 1; /* * Peer wants us to use a different code size or something. * Stop asking for Deflate if we don't understand his suggestion. */ if (DEFLATE_METHOD(p[2]) != DEFLATE_METHOD_VAL || DEFLATE_SIZE(p[2]) < DEFLATE_MIN_WORKS || p[3] != DEFLATE_CHK_SEQUENCE) try.deflate = 0; else if (DEFLATE_SIZE(p[2]) < go->deflate_size) try.deflate_size = DEFLATE_SIZE(p[2]); p += CILEN_DEFLATE; len -= CILEN_DEFLATE; if (go->deflate_correct && go->deflate_draft && len >= CILEN_DEFLATE && p[0] == CI_DEFLATE_DRAFT && p[1] == CILEN_DEFLATE) { p += CILEN_DEFLATE; len -= CILEN_DEFLATE; } } if (go->bsd_compress && len >= CILEN_BSD_COMPRESS && p[0] == CI_BSD_COMPRESS && p[1] == CILEN_BSD_COMPRESS) { no.bsd_compress = 1; /* * Peer wants us to use a different number of bits * or a different version. */ if (BSD_VERSION(p[2]) != BSD_CURRENT_VERSION) try.bsd_compress = 0; else if (BSD_NBITS(p[2]) < go->bsd_bits) try.bsd_bits = BSD_NBITS(p[2]); p += CILEN_BSD_COMPRESS; len -= CILEN_BSD_COMPRESS; } /* * Predictor-1 and 2 have no options, so they can't be Naked. * * There may be remaining options but we ignore them. */ if (f->state != OPENED) *go = try; return 1; } /* * ccp_rejci - reject some of our suggested compression methods. */ static int ccp_rejci(f, p, len) fsm *f; u_char *p; int len; { ccp_options *go = &ccp_gotoptions[f->unit]; ccp_options try; /* options to request next time */ try = *go; /* * Cope with empty configure-rejects by ceasing to send * configure-requests. */ if (len == 0 && all_rejected[f->unit]) return -1; #ifdef MPPE if (go->mppe && len >= CILEN_MPPE && p[0] == CI_MPPE && p[1] == CILEN_MPPE) { error("MPPE required but peer refused"); lcp_close(f->unit, "MPPE required but peer refused"); p += CILEN_MPPE; len -= CILEN_MPPE; } #endif if (go->deflate_correct && len >= CILEN_DEFLATE && p[0] == CI_DEFLATE && p[1] == CILEN_DEFLATE) { if (p[2] != DEFLATE_MAKE_OPT(go->deflate_size) || p[3] != DEFLATE_CHK_SEQUENCE) return 0; /* Rej is bad */ try.deflate_correct = 0; p += CILEN_DEFLATE; len -= CILEN_DEFLATE; } if (go->deflate_draft && len >= CILEN_DEFLATE && p[0] == CI_DEFLATE_DRAFT && p[1] == CILEN_DEFLATE) { if (p[2] != DEFLATE_MAKE_OPT(go->deflate_size) || p[3] != DEFLATE_CHK_SEQUENCE) return 0; /* Rej is bad */ try.deflate_draft = 0; p += CILEN_DEFLATE; len -= CILEN_DEFLATE; } if (!try.deflate_correct && !try.deflate_draft) try.deflate = 0; if (go->bsd_compress && len >= CILEN_BSD_COMPRESS && p[0] == CI_BSD_COMPRESS && p[1] == CILEN_BSD_COMPRESS) { if (p[2] != BSD_MAKE_OPT(BSD_CURRENT_VERSION, go->bsd_bits)) return 0; try.bsd_compress = 0; p += CILEN_BSD_COMPRESS; len -= CILEN_BSD_COMPRESS; } if (go->predictor_1 && len >= CILEN_PREDICTOR_1 && p[0] == CI_PREDICTOR_1 && p[1] == CILEN_PREDICTOR_1) { try.predictor_1 = 0; p += CILEN_PREDICTOR_1; len -= CILEN_PREDICTOR_1; } if (go->predictor_2 && len >= CILEN_PREDICTOR_2 && p[0] == CI_PREDICTOR_2 && p[1] == CILEN_PREDICTOR_2) { try.predictor_2 = 0; p += CILEN_PREDICTOR_2; len -= CILEN_PREDICTOR_2; } if (len != 0) return 0; if (f->state != OPENED) *go = try; return 1; } /* * ccp_reqci - processed a received configure-request. * Returns CONFACK, CONFNAK or CONFREJ and the packet modified * appropriately. */ static int ccp_reqci(f, p, lenp, dont_nak) fsm *f; u_char *p; int *lenp; int dont_nak; { ppp_pcb *pcb = &ppp_pcb_list[f->unit]; int ret, newret, res; u_char *p0, *retp; int len, clen, type, nb; ccp_options *ho = &ccp_hisoptions[f->unit]; ccp_options *ao = &ccp_allowoptions[f->unit]; #ifdef MPPE bool rej_for_ci_mppe = 1; /* Are we rejecting based on a bad/missing */ /* CI_MPPE, or due to other options? */ #endif ret = CONFACK; retp = p0 = p; len = *lenp; memset(ho, 0, sizeof(ccp_options)); ho->method = (len > 0)? p[0]: -1; while (len > 0) { newret = CONFACK; if (len < 2 || p[1] < 2 || p[1] > len) { /* length is bad */ clen = len; newret = CONFREJ; } else { type = p[0]; clen = p[1]; switch (type) { #ifdef MPPE case CI_MPPE: if (!ao->mppe || clen != CILEN_MPPE) { newret = CONFREJ; break; } MPPE_CI_TO_OPTS(&p[2], ho->mppe); /* Nak if anything unsupported or unknown are set. */ if (ho->mppe & MPPE_OPT_UNSUPPORTED) { newret = CONFNAK; ho->mppe &= ~MPPE_OPT_UNSUPPORTED; } if (ho->mppe & MPPE_OPT_UNKNOWN) { newret = CONFNAK; ho->mppe &= ~MPPE_OPT_UNKNOWN; } /* Check state opt */ if (ho->mppe & MPPE_OPT_STATEFUL) { /* * We can Nak and request stateless, but it's a * lot easier to just assume the peer will request * it if he can do it; stateful mode is bad over * the Internet -- which is where we expect MPPE. */ if (refuse_mppe_stateful) { error("Refusing MPPE stateful mode offered by peer"); newret = CONFREJ; break; } } /* Find out which of {S,L} are set. */ if ((ho->mppe & MPPE_OPT_128) && (ho->mppe & MPPE_OPT_40)) { /* Both are set, negotiate the strongest. */ newret = CONFNAK; if (ao->mppe & MPPE_OPT_128) ho->mppe &= ~MPPE_OPT_40; else if (ao->mppe & MPPE_OPT_40) ho->mppe &= ~MPPE_OPT_128; else { newret = CONFREJ; break; } } else if (ho->mppe & MPPE_OPT_128) { if (!(ao->mppe & MPPE_OPT_128)) { newret = CONFREJ; break; } } else if (ho->mppe & MPPE_OPT_40) { if (!(ao->mppe & MPPE_OPT_40)) { newret = CONFREJ; break; } } else { /* Neither are set. */ /* We cannot accept this. */ newret = CONFNAK; /* Give the peer our idea of what can be used, so it can choose and confirm */ ho->mppe = ao->mppe; } /* rebuild the opts */ MPPE_OPTS_TO_CI(ho->mppe, &p[2]); if (newret == CONFACK) { u_char opt_buf[CILEN_MPPE + MPPE_MAX_KEY_LEN]; int mtu; MEMCPY(opt_buf, p, CILEN_MPPE); MEMCPY(&opt_buf[CILEN_MPPE], mppe_send_key, MPPE_MAX_KEY_LEN); if (ccp_test(f->unit, opt_buf, CILEN_MPPE + MPPE_MAX_KEY_LEN, 1) <= 0) { /* This shouldn't happen, we've already tested it! */ error("MPPE required, but kernel has no support."); lcp_close(f->unit, "MPPE required but not available"); newret = CONFREJ; break; } /* * We need to decrease the interface MTU by MPPE_PAD * because MPPE frames **grow**. The kernel [must] * allocate MPPE_PAD extra bytes in xmit buffers. */ mtu = netif_get_mtu(pcb); if (mtu) netif_set_mtu(pcb, mtu - MPPE_PAD); else newret = CONFREJ; } /* * We have accepted MPPE or are willing to negotiate * MPPE parameters. A CONFREJ is due to subsequent * (non-MPPE) processing. */ rej_for_ci_mppe = 0; break; #endif /* MPPE */ case CI_DEFLATE: case CI_DEFLATE_DRAFT: if (!ao->deflate || clen != CILEN_DEFLATE || (!ao->deflate_correct && type == CI_DEFLATE) || (!ao->deflate_draft && type == CI_DEFLATE_DRAFT)) { newret = CONFREJ; break; } ho->deflate = 1; ho->deflate_size = nb = DEFLATE_SIZE(p[2]); if (DEFLATE_METHOD(p[2]) != DEFLATE_METHOD_VAL || p[3] != DEFLATE_CHK_SEQUENCE || nb > ao->deflate_size || nb < DEFLATE_MIN_WORKS) { newret = CONFNAK; if (!dont_nak) { p[2] = DEFLATE_MAKE_OPT(ao->deflate_size); p[3] = DEFLATE_CHK_SEQUENCE; /* fall through to test this #bits below */ } else break; } /* * Check whether we can do Deflate with the window * size they want. If the window is too big, reduce * it until the kernel can cope and nak with that. * We only check this for the first option. */ if (p == p0) { for (;;) { res = ccp_test(f->unit, p, CILEN_DEFLATE, 1); if (res > 0) break; /* it's OK now */ if (res < 0 || nb == DEFLATE_MIN_WORKS || dont_nak) { newret = CONFREJ; p[2] = DEFLATE_MAKE_OPT(ho->deflate_size); break; } newret = CONFNAK; --nb; p[2] = DEFLATE_MAKE_OPT(nb); } } break; case CI_BSD_COMPRESS: if (!ao->bsd_compress || clen != CILEN_BSD_COMPRESS) { newret = CONFREJ; break; } ho->bsd_compress = 1; ho->bsd_bits = nb = BSD_NBITS(p[2]); if (BSD_VERSION(p[2]) != BSD_CURRENT_VERSION || nb > ao->bsd_bits || nb < BSD_MIN_BITS) { newret = CONFNAK; if (!dont_nak) { p[2] = BSD_MAKE_OPT(BSD_CURRENT_VERSION, ao->bsd_bits); /* fall through to test this #bits below */ } else break; } /* * Check whether we can do BSD-Compress with the code * size they want. If the code size is too big, reduce * it until the kernel can cope and nak with that. * We only check this for the first option. */ if (p == p0) { for (;;) { res = ccp_test(f->unit, p, CILEN_BSD_COMPRESS, 1); if (res > 0) break; if (res < 0 || nb == BSD_MIN_BITS || dont_nak) { newret = CONFREJ; p[2] = BSD_MAKE_OPT(BSD_CURRENT_VERSION, ho->bsd_bits); break; } newret = CONFNAK; --nb; p[2] = BSD_MAKE_OPT(BSD_CURRENT_VERSION, nb); } } break; case CI_PREDICTOR_1: if (!ao->predictor_1 || clen != CILEN_PREDICTOR_1) { newret = CONFREJ; break; } ho->predictor_1 = 1; if (p == p0 && ccp_test(f->unit, p, CILEN_PREDICTOR_1, 1) <= 0) { newret = CONFREJ; } break; case CI_PREDICTOR_2: if (!ao->predictor_2 || clen != CILEN_PREDICTOR_2) { newret = CONFREJ; break; } ho->predictor_2 = 1; if (p == p0 && ccp_test(f->unit, p, CILEN_PREDICTOR_2, 1) <= 0) { newret = CONFREJ; } break; default: newret = CONFREJ; } } if (newret == CONFNAK && dont_nak) newret = CONFREJ; if (!(newret == CONFACK || (newret == CONFNAK && ret == CONFREJ))) { /* we're returning this option */ if (newret == CONFREJ && ret == CONFNAK) retp = p0; ret = newret; if (p != retp) MEMCPY(retp, p, clen); retp += clen; } p += clen; len -= clen; } if (ret != CONFACK) { if (ret == CONFREJ && *lenp == retp - p0) all_rejected[f->unit] = 1; else *lenp = retp - p0; } #ifdef MPPE if (ret == CONFREJ && ao->mppe && rej_for_ci_mppe) { error("MPPE required but peer negotiation failed"); lcp_close(f->unit, "MPPE required but peer negotiation failed"); } #endif return ret; } /* * Make a string name for a compression method (or 2). */ static char * method_name(opt, opt2) ccp_options *opt, *opt2; { static char result[64]; if (!ANY_COMPRESS(*opt)) return "(none)"; switch (opt->method) { #ifdef MPPE case CI_MPPE: { char *p = result; char *q = result + sizeof(result); /* 1 past result */ slprintf(p, q - p, "MPPE "); p += 5; if (opt->mppe & MPPE_OPT_128) { slprintf(p, q - p, "128-bit "); p += 8; } if (opt->mppe & MPPE_OPT_40) { slprintf(p, q - p, "40-bit "); p += 7; } if (opt->mppe & MPPE_OPT_STATEFUL) slprintf(p, q - p, "stateful"); else slprintf(p, q - p, "stateless"); break; } #endif case CI_DEFLATE: case CI_DEFLATE_DRAFT: if (opt2 != NULL && opt2->deflate_size != opt->deflate_size) slprintf(result, sizeof(result), "Deflate%s (%d/%d)", (opt->method == CI_DEFLATE_DRAFT? "(old#)": ""), opt->deflate_size, opt2->deflate_size); else slprintf(result, sizeof(result), "Deflate%s (%d)", (opt->method == CI_DEFLATE_DRAFT? "(old#)": ""), opt->deflate_size); break; case CI_BSD_COMPRESS: if (opt2 != NULL && opt2->bsd_bits != opt->bsd_bits) slprintf(result, sizeof(result), "BSD-Compress (%d/%d)", opt->bsd_bits, opt2->bsd_bits); else slprintf(result, sizeof(result), "BSD-Compress (%d)", opt->bsd_bits); break; case CI_PREDICTOR_1: return "Predictor 1"; case CI_PREDICTOR_2: return "Predictor 2"; default: slprintf(result, sizeof(result), "Method %d", opt->method); } return result; } /* * CCP has come up - inform the kernel driver and log a message. */ static void ccp_up(f) fsm *f; { ccp_options *go = &ccp_gotoptions[f->unit]; ccp_options *ho = &ccp_hisoptions[f->unit]; char method1[64]; ccp_flags_set(f->unit, 1, 1); if (ANY_COMPRESS(*go)) { if (ANY_COMPRESS(*ho)) { if (go->method == ho->method) { notice("%s compression enabled", method_name(go, ho)); } else { strlcpy(method1, method_name(go, NULL), sizeof(method1)); notice("%s / %s compression enabled", method1, method_name(ho, NULL)); } } else notice("%s receive compression enabled", method_name(go, NULL)); } else if (ANY_COMPRESS(*ho)) notice("%s transmit compression enabled", method_name(ho, NULL)); #ifdef MPPE if (go->mppe) { BZERO(mppe_recv_key, MPPE_MAX_KEY_LEN); BZERO(mppe_send_key, MPPE_MAX_KEY_LEN); continue_networks(f->unit); /* Bring up IP et al */ } #endif } /* * CCP has gone down - inform the kernel driver. */ static void ccp_down(f) fsm *f; { if (ccp_localstate[f->unit] & RACK_PENDING) UNTIMEOUT(ccp_rack_timeout, f); ccp_localstate[f->unit] = 0; ccp_flags_set(f->unit, 1, 0); #ifdef MPPE if (ccp_gotoptions[f->unit].mppe) { ccp_gotoptions[f->unit].mppe = 0; if (lcp_fsm[f->unit].state == OPENED) { /* If LCP is not already going down, make sure it does. */ error("MPPE disabled"); lcp_close(f->unit, "MPPE disabled"); } } #endif } #if PRINTPKT_SUPPORT /* * Print the contents of a CCP packet. */ static char *ccp_codenames[] = { "ConfReq", "ConfAck", "ConfNak", "ConfRej", "TermReq", "TermAck", "CodeRej", NULL, NULL, NULL, NULL, NULL, NULL, "ResetReq", "ResetAck", }; static int ccp_printpkt(p, plen, printer, arg) u_char *p; int plen; void (*printer) (void *, char *, ...); void *arg; { u_char *p0, *optend; int code, id, len; int optlen; p0 = p; if (plen < HEADERLEN) return 0; code = p[0]; id = p[1]; len = (p[2] << 8) + p[3]; if (len < HEADERLEN || len > plen) return 0; if (code >= 1 && code <= sizeof(ccp_codenames) / sizeof(char *) && ccp_codenames[code-1] != NULL) printer(arg, " %s", ccp_codenames[code-1]); else printer(arg, " code=0x%x", code); printer(arg, " id=0x%x", id); len -= HEADERLEN; p += HEADERLEN; switch (code) { case CONFREQ: case CONFACK: case CONFNAK: case CONFREJ: /* print list of possible compression methods */ while (len >= 2) { code = p[0]; optlen = p[1]; if (optlen < 2 || optlen > len) break; printer(arg, " <"); len -= optlen; optend = p + optlen; switch (code) { #ifdef MPPE case CI_MPPE: if (optlen >= CILEN_MPPE) { u_char mppe_opts; MPPE_CI_TO_OPTS(&p[2], mppe_opts); printer(arg, "mppe %s %s %s %s %s %s%s", (p[2] & MPPE_H_BIT)? "+H": "-H", (p[5] & MPPE_M_BIT)? "+M": "-M", (p[5] & MPPE_S_BIT)? "+S": "-S", (p[5] & MPPE_L_BIT)? "+L": "-L", (p[5] & MPPE_D_BIT)? "+D": "-D", (p[5] & MPPE_C_BIT)? "+C": "-C", (mppe_opts & MPPE_OPT_UNKNOWN)? " +U": ""); if (mppe_opts & MPPE_OPT_UNKNOWN) printer(arg, " (%.2x %.2x %.2x %.2x)", p[2], p[3], p[4], p[5]); p += CILEN_MPPE; } break; #endif case CI_DEFLATE: case CI_DEFLATE_DRAFT: if (optlen >= CILEN_DEFLATE) { printer(arg, "deflate%s %d", (code == CI_DEFLATE_DRAFT? "(old#)": ""), DEFLATE_SIZE(p[2])); if (DEFLATE_METHOD(p[2]) != DEFLATE_METHOD_VAL) printer(arg, " method %d", DEFLATE_METHOD(p[2])); if (p[3] != DEFLATE_CHK_SEQUENCE) printer(arg, " check %d", p[3]); p += CILEN_DEFLATE; } break; case CI_BSD_COMPRESS: if (optlen >= CILEN_BSD_COMPRESS) { printer(arg, "bsd v%d %d", BSD_VERSION(p[2]), BSD_NBITS(p[2])); p += CILEN_BSD_COMPRESS; } break; case CI_PREDICTOR_1: if (optlen >= CILEN_PREDICTOR_1) { printer(arg, "predictor 1"); p += CILEN_PREDICTOR_1; } break; case CI_PREDICTOR_2: if (optlen >= CILEN_PREDICTOR_2) { printer(arg, "predictor 2"); p += CILEN_PREDICTOR_2; } break; } while (p < optend) printer(arg, " %.2x", *p++); printer(arg, ">"); } break; case TERMACK: case TERMREQ: if (len > 0 && *p >= ' ' && *p < 0x7f) { print_string((char *)p, len, printer, arg); p += len; len = 0; } break; } /* dump out the rest of the packet in hex */ while (--len >= 0) printer(arg, " %.2x", *p++); return p - p0; } #endif /* PRINTPKT_SUPPORT */ /* * We have received a packet that the decompressor failed to * decompress. Here we would expect to issue a reset-request, but * Motorola has a patent on resetting the compressor as a result of * detecting an error in the decompressed data after decompression. * (See US patent 5,130,993; international patent publication number * WO 91/10289; Australian patent 73296/91.) * * So we ask the kernel whether the error was detected after * decompression; if it was, we take CCP down, thus disabling * compression :-(, otherwise we issue the reset-request. */ static void ccp_datainput(unit, pkt, len) int unit; u_char *pkt; int len; { fsm *f; f = &ccp_fsm[unit]; if (f->state == OPENED) { if (ccp_fatal_error(unit)) { /* * Disable compression by taking CCP down. */ error("Lost compression sync: disabling compression"); ccp_close(unit, "Lost compression sync"); #ifdef MPPE /* * If we were doing MPPE, we must also take the link down. */ if (ccp_gotoptions[unit].mppe) { error("Too many MPPE errors, closing LCP"); lcp_close(unit, "Too many MPPE errors"); } #endif } else { /* * Send a reset-request to reset the peer's compressor. * We don't do that if we are still waiting for an * acknowledgement to a previous reset-request. */ if (!(ccp_localstate[f->unit] & RACK_PENDING)) { fsm_sdata(f, CCP_RESETREQ, f->reqid = ++f->id, NULL, 0); TIMEOUT(ccp_rack_timeout, f, RACKTIMEOUT); ccp_localstate[f->unit] |= RACK_PENDING; } else ccp_localstate[f->unit] |= RREQ_REPEAT; } } } /* * Timeout waiting for reset-ack. */ static void ccp_rack_timeout(arg) void *arg; { fsm *f = arg; if (f->state == OPENED && ccp_localstate[f->unit] & RREQ_REPEAT) { fsm_sdata(f, CCP_RESETREQ, f->reqid, NULL, 0); TIMEOUT(ccp_rack_timeout, f, RACKTIMEOUT); ccp_localstate[f->unit] &= ~RREQ_REPEAT; } else ccp_localstate[f->unit] &= ~RACK_PENDING; } #endif /* PPP_SUPPORT && CCP_SUPPORT */ ocproxy-1.60/lwip/src/netif/ppp/chap-md5.c000066400000000000000000000071131303453231400203530ustar00rootroot00000000000000/* * chap-md5.c - New CHAP/MD5 implementation. * * Copyright (c) 2003 Paul Mackerras. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. The name(s) of the authors of this software must not be used to * endorse or promote products derived from this software without * prior written permission. * * 3. Redistributions of any form whatsoever must retain the following * acknowledgment: * "This product includes software developed by Paul Mackerras * ". * * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "lwip/opt.h" #if PPP_SUPPORT && CHAP_SUPPORT /* don't build if not configured for use in lwipopts.h */ #if 0 /* UNUSED */ #include #include #endif /* UNUSED */ #include "netif/ppp/ppp_impl.h" #include "netif/ppp/chap-new.h" #include "netif/ppp/chap-md5.h" #include "netif/ppp/magic.h" #if LWIP_INCLUDED_POLARSSL_MD5 #include "netif/ppp/polarssl/md5.h" #else #include "polarssl/md5.h" #endif #define MD5_HASH_SIZE 16 #define MD5_MIN_CHALLENGE 16 #define MD5_MAX_CHALLENGE 24 #if PPP_SERVER static void chap_md5_generate_challenge(unsigned char *cp) { int clen; clen = (int)(drand48() * (MD5_MAX_CHALLENGE - MD5_MIN_CHALLENGE)) + MD5_MIN_CHALLENGE; *cp++ = clen; random_bytes(cp, clen); } static int chap_md5_verify_response(int id, char *name, unsigned char *secret, int secret_len, unsigned char *challenge, unsigned char *response, char *message, int message_space) { md5_context ctx; unsigned char idbyte = id; unsigned char hash[MD5_HASH_SIZE]; int challenge_len, response_len; challenge_len = *challenge++; response_len = *response++; if (response_len == MD5_HASH_SIZE) { /* Generate hash of ID, secret, challenge */ md5_starts(&ctx); md5_update(&ctx, &idbyte, 1); md5_update(&ctx, secret, secret_len); md5_update(&ctx, challenge, challenge_len); md5_finish(&ctx, hash); /* Test if our hash matches the peer's response */ if (memcmp(hash, response, MD5_HASH_SIZE) == 0) { ppp_slprintf(message, message_space, "Access granted"); return 1; } } ppp_slprintf(message, message_space, "Access denied"); return 0; } #endif /* PPP_SERVER */ static void chap_md5_make_response(unsigned char *response, int id, char *our_name, unsigned char *challenge, char *secret, int secret_len, unsigned char *private) { md5_context ctx; unsigned char idbyte = id; int challenge_len = *challenge++; md5_starts(&ctx); md5_update(&ctx, &idbyte, 1); md5_update(&ctx, (u_char *)secret, secret_len); md5_update(&ctx, challenge, challenge_len); md5_finish(&ctx, &response[1]); response[0] = MD5_HASH_SIZE; } const struct chap_digest_type md5_digest = { CHAP_MD5, /* code */ #if PPP_SERVER chap_md5_generate_challenge, chap_md5_verify_response, #endif /* PPP_SERVER */ chap_md5_make_response, NULL, /* check_success */ NULL, /* handle_failure */ }; #endif /* PPP_SUPPORT && CHAP_SUPPORT */ ocproxy-1.60/lwip/src/netif/ppp/chap-new.c000066400000000000000000000441131303453231400204600ustar00rootroot00000000000000/* * chap-new.c - New CHAP implementation. * * Copyright (c) 2003 Paul Mackerras. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. The name(s) of the authors of this software must not be used to * endorse or promote products derived from this software without * prior written permission. * * 3. Redistributions of any form whatsoever must retain the following * acknowledgment: * "This product includes software developed by Paul Mackerras * ". * * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "lwip/opt.h" #if PPP_SUPPORT && CHAP_SUPPORT /* don't build if not configured for use in lwipopts.h */ #if 0 /* UNUSED */ #include #include #endif /* UNUSED */ #include "netif/ppp/ppp_impl.h" #if 0 /* UNUSED */ #include "session.h" #endif /* UNUSED */ #include "netif/ppp/chap-new.h" #include "netif/ppp/chap-md5.h" #if MSCHAP_SUPPORT #include "netif/ppp/chap_ms.h" #endif /* Hook for a plugin to validate CHAP challenge */ int (*chap_verify_hook)(char *name, char *ourname, int id, const struct chap_digest_type *digest, unsigned char *challenge, unsigned char *response, char *message, int message_space) = NULL; #if PPP_OPTIONS /* * Command-line options. */ static option_t chap_option_list[] = { { "chap-restart", o_int, &chap_timeout_time, "Set timeout for CHAP", OPT_PRIO }, { "chap-max-challenge", o_int, &pcb->settings.chap_max_transmits, "Set max #xmits for challenge", OPT_PRIO }, { "chap-interval", o_int, &pcb->settings.chap_rechallenge_time, "Set interval for rechallenge", OPT_PRIO }, { NULL } }; #endif /* PPP_OPTIONS */ /* Values for flags in chap_client_state and chap_server_state */ #define LOWERUP 1 #define AUTH_STARTED 2 #define AUTH_DONE 4 #define AUTH_FAILED 8 #define TIMEOUT_PENDING 0x10 #define CHALLENGE_VALID 0x20 /* * Prototypes. */ static void chap_init(ppp_pcb *pcb); static void chap_lowerup(ppp_pcb *pcb); static void chap_lowerdown(ppp_pcb *pcb); #if PPP_SERVER static void chap_timeout(void *arg); static void chap_generate_challenge(ppp_pcb *pcb); static void chap_handle_response(ppp_pcb *pcb, int code, unsigned char *pkt, int len); static int chap_verify_response(char *name, char *ourname, int id, const struct chap_digest_type *digest, unsigned char *challenge, unsigned char *response, char *message, int message_space); #endif /* PPP_SERVER */ static void chap_respond(ppp_pcb *pcb, int id, unsigned char *pkt, int len); static void chap_handle_status(ppp_pcb *pcb, int code, int id, unsigned char *pkt, int len); static void chap_protrej(ppp_pcb *pcb); static void chap_input(ppp_pcb *pcb, unsigned char *pkt, int pktlen); #if PRINTPKT_SUPPORT static int chap_print_pkt(unsigned char *p, int plen, void (*printer) (void *, char *, ...), void *arg); #endif /* PRINTPKT_SUPPORT */ /* List of digest types that we know about */ const static struct chap_digest_type* const chap_digests[] = { &md5_digest, #if MSCHAP_SUPPORT &chapms_digest, &chapms2_digest, #endif /* MSCHAP_SUPPORT */ NULL }; /* * chap_init - reset to initial state. */ static void chap_init(ppp_pcb *pcb) { memset(&pcb->chap_client, 0, sizeof(chap_client_state)); #if PPP_SERVER memset(&pcb->chap_server, 0, sizeof(chap_server_state)); #endif /* PPP_SERVER */ } /* * chap_lowerup - we can start doing stuff now. */ static void chap_lowerup(ppp_pcb *pcb) { pcb->chap_client.flags |= LOWERUP; #if PPP_SERVER pcb->chap_server.flags |= LOWERUP; if (pcb->chap_server.flags & AUTH_STARTED) chap_timeout(pcb); #endif /* PPP_SERVER */ } static void chap_lowerdown(ppp_pcb *pcb) { pcb->chap_client.flags = 0; #if PPP_SERVER if (pcb->chap_server.flags & TIMEOUT_PENDING) UNTIMEOUT(chap_timeout, pcb); pcb->chap_server.flags = 0; #endif /* PPP_SERVER */ } #if PPP_SERVER /* * chap_auth_peer - Start authenticating the peer. * If the lower layer is already up, we start sending challenges, * otherwise we wait for the lower layer to come up. */ void chap_auth_peer(ppp_pcb *pcb, char *our_name, int digest_code) { struct chap_server_state *ss = &pcb->chap_server; const struct chap_digest_type *dp; int i; if (pcb->chap_server.flags & AUTH_STARTED) { ppp_error("CHAP: peer authentication already started!"); return; } for (i = 0; (dp = chap_digests[i]) != NULL; ++i) if (dp->code == digest_code) break; if (dp == NULL) ppp_fatal("CHAP digest 0x%x requested but not available", digest_code); pcb->chap_server.digest = dp; pcb->chap_server.name = our_name; /* Start with a random ID value */ pcb->chap_server.id = (unsigned char)(drand48() * 256); pcb->chap_server.flags |= AUTH_STARTED; if (pcb->chap_server.flags & LOWERUP) chap_timeout(ss); } #endif /* PPP_SERVER */ /* * chap_auth_with_peer - Prepare to authenticate ourselves to the peer. * There isn't much to do until we receive a challenge. */ void chap_auth_with_peer(ppp_pcb *pcb, char *our_name, int digest_code) { const struct chap_digest_type *dp; int i; if(NULL == our_name) return; if (pcb->chap_client.flags & AUTH_STARTED) { ppp_error("CHAP: authentication with peer already started!"); return; } for (i = 0; (dp = chap_digests[i]) != NULL; ++i) if (dp->code == digest_code) break; if (dp == NULL) ppp_fatal("CHAP digest 0x%x requested but not available", digest_code); pcb->chap_client.digest = dp; pcb->chap_client.name = our_name; pcb->chap_client.flags |= AUTH_STARTED; } #if PPP_SERVER /* * chap_timeout - It's time to send another challenge to the peer. * This could be either a retransmission of a previous challenge, * or a new challenge to start re-authentication. */ static void chap_timeout(void *arg) { ppp_pcb *pcb = (ppp_pcb*)arg; struct pbuf *p; pcb->chap_server.flags &= ~TIMEOUT_PENDING; if ((pcb->chap_server.flags & CHALLENGE_VALID) == 0) { pcb->chap_server.challenge_xmits = 0; chap_generate_challenge(pcb); pcb->chap_server.flags |= CHALLENGE_VALID; } else if (pcb->chap_server.challenge_xmits >= pcb->settings.chap_max_transmits) { pcb->chap_server.flags &= ~CHALLENGE_VALID; pcb->chap_server.flags |= AUTH_DONE | AUTH_FAILED; auth_peer_fail(pcb, PPP_CHAP); return; } p = pbuf_alloc(PBUF_RAW, (u16_t)(pcb->chap_server.challenge_pktlen), PPP_CTRL_PBUF_TYPE); if(NULL == p) return; if(p->tot_len != p->len) { pbuf_free(p); return; } MEMCPY(p->payload, pcb->chap_server.challenge, pcb->chap_server.challenge_pktlen); ppp_write(pcb, p); ++pcb->chap_server.challenge_xmits; pcb->chap_server.flags |= TIMEOUT_PENDING; TIMEOUT(chap_timeout, arg, pcb->settings.chap_timeout_time); } /* * chap_generate_challenge - generate a challenge string and format * the challenge packet in pcb->chap_server.challenge_pkt. */ static void chap_generate_challenge(ppp_pcb *pcb) { int clen = 1, nlen, len; unsigned char *p; p = pcb->chap_server.challenge; MAKEHEADER(p, PPP_CHAP); p += CHAP_HDRLEN; pcb->chap_server.digest->generate_challenge(p); clen = *p; nlen = strlen(pcb->chap_server.name); memcpy(p + 1 + clen, pcb->chap_server.name, nlen); len = CHAP_HDRLEN + 1 + clen + nlen; pcb->chap_server.challenge_pktlen = PPP_HDRLEN + len; p = pcb->chap_server.challenge + PPP_HDRLEN; p[0] = CHAP_CHALLENGE; p[1] = ++pcb->chap_server.id; p[2] = len >> 8; p[3] = len; } /* * chap_handle_response - check the response to our challenge. */ static void chap_handle_response(ppp_pcb *pcb, int id, unsigned char *pkt, int len) { int response_len, ok, mlen; unsigned char *response, *outp; struct pbuf *p; char *name = NULL; /* initialized to shut gcc up */ int (*verifier)(char *, char *, int, const struct chap_digest_type *, unsigned char *, unsigned char *, char *, int); char rname[MAXNAMELEN+1]; if ((pcb->chap_server.flags & LOWERUP) == 0) return; if (id != pcb->chap_server.challenge[PPP_HDRLEN+1] || len < 2) return; if (pcb->chap_server.flags & CHALLENGE_VALID) { response = pkt; GETCHAR(response_len, pkt); len -= response_len + 1; /* length of name */ name = (char *)pkt + response_len; if (len < 0) return; if (pcb->chap_server.flags & TIMEOUT_PENDING) { pcb->chap_server.flags &= ~TIMEOUT_PENDING; UNTIMEOUT(chap_timeout, pcb); } #if PPP_REMOTENAME if (pcb->settings.explicit_remote) { name = pcb->remote_name; } else #endif /* PPP_REMOTENAME */ { /* Null terminate and clean remote name. */ ppp_slprintf(rname, sizeof(rname), "%.*v", len, name); name = rname; } if (chap_verify_hook) verifier = chap_verify_hook; else verifier = chap_verify_response; ok = (*verifier)(name, pcb->chap_server.name, id, pcb->chap_server.digest, pcb->chap_server.challenge + PPP_HDRLEN + CHAP_HDRLEN, response, pcb->chap_server.message, sizeof(pcb->chap_server.message)); #if 0 /* UNUSED */ if (!ok || !auth_number()) { #endif /* UNUSED */ if (!ok) { pcb->chap_server.flags |= AUTH_FAILED; ppp_warn("Peer %q failed CHAP authentication", name); } } else if ((pcb->chap_server.flags & AUTH_DONE) == 0) return; /* send the response */ mlen = strlen(pcb->chap_server.message); len = CHAP_HDRLEN + mlen; p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_HDRLEN +len), PPP_CTRL_PBUF_TYPE); if(NULL == p) return; if(p->tot_len != p->len) { pbuf_free(p); return; } outp = p->payload; MAKEHEADER(outp, PPP_CHAP); outp[0] = (pcb->chap_server.flags & AUTH_FAILED)? CHAP_FAILURE: CHAP_SUCCESS; outp[1] = id; outp[2] = len >> 8; outp[3] = len; if (mlen > 0) memcpy(outp + CHAP_HDRLEN, pcb->chap_server.message, mlen); ppp_write(pcb, p); if (pcb->chap_server.flags & CHALLENGE_VALID) { pcb->chap_server.flags &= ~CHALLENGE_VALID; if (!(pcb->chap_server.flags & AUTH_DONE) && !(pcb->chap_server.flags & AUTH_FAILED)) { #if 0 /* UNUSED */ /* * Auth is OK, so now we need to check session restrictions * to ensure everything is OK, but only if we used a * plugin, and only if we're configured to check. This * allows us to do PAM checks on PPP servers that * authenticate against ActiveDirectory, and use AD for * account info (like when using Winbind integrated with * PAM). */ if (session_mgmt && session_check(name, NULL, devnam, NULL) == 0) { pcb->chap_server.flags |= AUTH_FAILED; ppp_warn("Peer %q failed CHAP Session verification", name); } #endif /* UNUSED */ } if (pcb->chap_server.flags & AUTH_FAILED) { auth_peer_fail(pcb, PPP_CHAP); } else { if ((pcb->chap_server.flags & AUTH_DONE) == 0) auth_peer_success(pcb, PPP_CHAP, pcb->chap_server.digest->code, name, strlen(name)); if (pcb->settings.chap_rechallenge_time) { pcb->chap_server.flags |= TIMEOUT_PENDING; TIMEOUT(chap_timeout, pcb, pcb->settings.chap_rechallenge_time); } } pcb->chap_server.flags |= AUTH_DONE; } } /* * chap_verify_response - check whether the peer's response matches * what we think it should be. Returns 1 if it does (authentication * succeeded), or 0 if it doesn't. */ static int chap_verify_response(char *name, char *ourname, int id, const struct chap_digest_type *digest, unsigned char *challenge, unsigned char *response, char *message, int message_space) { int ok; unsigned char secret[MAXSECRETLEN]; int secret_len; /* FIXME: we need a way to check peer secret */ #if 0 /* Get the secret that the peer is supposed to know */ if (!get_secret(pcb, name, ourname, (char *)secret, &secret_len, 1)) { ppp_error("No CHAP secret found for authenticating %q", name); return 0; } #endif ok = digest->verify_response(id, name, secret, secret_len, challenge, response, message, message_space); memset(secret, 0, sizeof(secret)); return ok; } #endif /* PPP_SERVER */ /* * chap_respond - Generate and send a response to a challenge. */ static void chap_respond(ppp_pcb *pcb, int id, unsigned char *pkt, int len) { int clen, nlen; int secret_len; struct pbuf *p; u_char *outp; char rname[MAXNAMELEN+1]; char secret[MAXSECRETLEN+1]; p = pbuf_alloc(PBUF_RAW, (u16_t)(RESP_MAX_PKTLEN), PPP_CTRL_PBUF_TYPE); if(NULL == p) return; if(p->tot_len != p->len) { pbuf_free(p); return; } if ((pcb->chap_client.flags & (LOWERUP | AUTH_STARTED)) != (LOWERUP | AUTH_STARTED)) return; /* not ready */ if (len < 2 || len < pkt[0] + 1) return; /* too short */ clen = pkt[0]; nlen = len - (clen + 1); /* Null terminate and clean remote name. */ ppp_slprintf(rname, sizeof(rname), "%.*v", nlen, pkt + clen + 1); #if PPP_REMOTENAME /* Microsoft doesn't send their name back in the PPP packet */ if (pcb->settings.explicit_remote || (pcb->settings.remote_name[0] != 0 && rname[0] == 0)) strlcpy(rname, pcb->settings.remote_name, sizeof(rname)); #endif /* PPP_REMOTENAME */ /* get secret for authenticating ourselves with the specified host */ if (!get_secret(pcb, pcb->chap_client.name, rname, secret, &secret_len, 0)) { secret_len = 0; /* assume null secret if can't find one */ ppp_warn("No CHAP secret found for authenticating us to %q", rname); } outp = p->payload; MAKEHEADER(outp, PPP_CHAP); outp += CHAP_HDRLEN; pcb->chap_client.digest->make_response(outp, id, pcb->chap_client.name, pkt, secret, secret_len, pcb->chap_client.priv); memset(secret, 0, secret_len); clen = *outp; nlen = strlen(pcb->chap_client.name); memcpy(outp + clen + 1, pcb->chap_client.name, nlen); outp = (u_char*)p->payload + PPP_HDRLEN; len = CHAP_HDRLEN + clen + 1 + nlen; outp[0] = CHAP_RESPONSE; outp[1] = id; outp[2] = len >> 8; outp[3] = len; pbuf_realloc(p, PPP_HDRLEN + len); ppp_write(pcb, p); } static void chap_handle_status(ppp_pcb *pcb, int code, int id, unsigned char *pkt, int len) { const char *msg = NULL; if ((pcb->chap_client.flags & (AUTH_DONE|AUTH_STARTED|LOWERUP)) != (AUTH_STARTED|LOWERUP)) return; pcb->chap_client.flags |= AUTH_DONE; if (code == CHAP_SUCCESS) { /* used for MS-CHAP v2 mutual auth, yuck */ if (pcb->chap_client.digest->check_success != NULL) { if (!(*pcb->chap_client.digest->check_success)(pkt, len, pcb->chap_client.priv)) code = CHAP_FAILURE; } else msg = "CHAP authentication succeeded"; } else { if (pcb->chap_client.digest->handle_failure != NULL) (*pcb->chap_client.digest->handle_failure)(pkt, len); else msg = "CHAP authentication failed"; } if (msg) { if (len > 0) ppp_info("%s: %.*v", msg, len, pkt); else ppp_info("%s", msg); } if (code == CHAP_SUCCESS) auth_withpeer_success(pcb, PPP_CHAP, pcb->chap_client.digest->code); else { pcb->chap_client.flags |= AUTH_FAILED; ppp_error("CHAP authentication failed"); auth_withpeer_fail(pcb, PPP_CHAP); } } static void chap_input(ppp_pcb *pcb, unsigned char *pkt, int pktlen) { unsigned char code, id; int len; if (pktlen < CHAP_HDRLEN) return; GETCHAR(code, pkt); GETCHAR(id, pkt); GETSHORT(len, pkt); if (len < CHAP_HDRLEN || len > pktlen) return; len -= CHAP_HDRLEN; switch (code) { case CHAP_CHALLENGE: chap_respond(pcb, id, pkt, len); break; #if PPP_SERVER case CHAP_RESPONSE: chap_handle_response(pcb, id, pkt, len); break; #endif /* PPP_SERVER */ case CHAP_FAILURE: case CHAP_SUCCESS: chap_handle_status(pcb, code, id, pkt, len); break; } } static void chap_protrej(ppp_pcb *pcb) { #if PPP_SERVER if (pcb->chap_server.flags & TIMEOUT_PENDING) { pcb->chap_server.flags &= ~TIMEOUT_PENDING; UNTIMEOUT(chap_timeout, pcb); } if (pcb->chap_server.flags & AUTH_STARTED) { pcb->chap_server.flags = 0; auth_peer_fail(pcb, PPP_CHAP); } #endif /* PPP_SERVER */ if ((pcb->chap_client.flags & (AUTH_STARTED|AUTH_DONE)) == AUTH_STARTED) { pcb->chap_client.flags &= ~AUTH_STARTED; ppp_error("CHAP authentication failed due to protocol-reject"); auth_withpeer_fail(pcb, PPP_CHAP); } } #if PRINTPKT_SUPPORT /* * chap_print_pkt - print the contents of a CHAP packet. */ static char *chap_code_names[] = { "Challenge", "Response", "Success", "Failure" }; static int chap_print_pkt(unsigned char *p, int plen, void (*printer) (void *, char *, ...), void *arg) { int code, id, len; int clen, nlen; unsigned char x; if (plen < CHAP_HDRLEN) return 0; GETCHAR(code, p); GETCHAR(id, p); GETSHORT(len, p); if (len < CHAP_HDRLEN || len > plen) return 0; if (code >= 1 && code <= sizeof(chap_code_names) / sizeof(char *)) printer(arg, " %s", chap_code_names[code-1]); else printer(arg, " code=0x%x", code); printer(arg, " id=0x%x", id); len -= CHAP_HDRLEN; switch (code) { case CHAP_CHALLENGE: case CHAP_RESPONSE: if (len < 1) break; clen = p[0]; if (len < clen + 1) break; ++p; nlen = len - clen - 1; printer(arg, " <"); for (; clen > 0; --clen) { GETCHAR(x, p); printer(arg, "%.2x", x); } printer(arg, ">, name = "); ppp_print_string((char *)p, nlen, printer, arg); break; case CHAP_FAILURE: case CHAP_SUCCESS: printer(arg, " "); ppp_print_string((char *)p, len, printer, arg); break; default: for (clen = len; clen > 0; --clen) { GETCHAR(x, p); printer(arg, " %.2x", x); } /* no break */ } return len + CHAP_HDRLEN; } #endif /* PRINTPKT_SUPPORT */ const struct protent chap_protent = { PPP_CHAP, chap_init, chap_input, chap_protrej, chap_lowerup, chap_lowerdown, NULL, /* open */ NULL, /* close */ #if PRINTPKT_SUPPORT chap_print_pkt, #endif /* PRINTPKT_SUPPORT */ NULL, /* datainput */ 1, /* enabled_flag */ #if PRINTPKT_SUPPORT "CHAP", /* name */ NULL, /* data_name */ #endif /* PRINTPKT_SUPPORT */ #if PPP_OPTIONS chap_option_list, NULL, /* check_options */ #endif /* PPP_OPTIONS */ #if DEMAND_SUPPORT NULL, NULL #endif /* DEMAND_SUPPORT */ }; #endif /* PPP_SUPPORT && CHAP_SUPPORT */ ocproxy-1.60/lwip/src/netif/ppp/chap_ms.c000066400000000000000000000723461303453231400204010ustar00rootroot00000000000000/* * chap_ms.c - Microsoft MS-CHAP compatible implementation. * * Copyright (c) 1995 Eric Rosenquist. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The name(s) of the authors of this software must not be used to * endorse or promote products derived from this software without * prior written permission. * * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* * Modifications by Lauri Pesonen / lpesonen@clinet.fi, april 1997 * * Implemented LANManager type password response to MS-CHAP challenges. * Now pppd provides both NT style and LANMan style blocks, and the * prefered is set by option "ms-lanman". Default is to use NT. * The hash text (StdText) was taken from Win95 RASAPI32.DLL. * * You should also use DOMAIN\\USERNAME as described in README.MSCHAP80 */ /* * Modifications by Frank Cusack, frank@google.com, March 2002. * * Implemented MS-CHAPv2 functionality, heavily based on sample * implementation in RFC 2759. Implemented MPPE functionality, * heavily based on sample implementation in RFC 3079. * * Copyright (c) 2002 Google, Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The name(s) of the authors of this software must not be used to * endorse or promote products derived from this software without * prior written permission. * * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * */ #include "lwip/opt.h" #if PPP_SUPPORT && MSCHAP_SUPPORT /* don't build if not configured for use in lwipopts.h */ #if 0 /* UNUSED */ #include #include #include #include #include #include #include #endif /* UNUSED */ #include "netif/ppp/ppp_impl.h" #include "netif/ppp/chap-new.h" #include "netif/ppp/chap_ms.h" #include "netif/ppp/pppcrypt.h" #include "netif/ppp/magic.h" #if LWIP_INCLUDED_POLARSSL_MD4 #include "netif/ppp/polarssl/md4.h" #else #include "polarssl/md4.h" #endif #if LWIP_INCLUDED_POLARSSL_SHA1 #include "netif/ppp/polarssl/sha1.h" #else #include "polarssl/sha1.h" #endif #if LWIP_INCLUDED_POLARSSL_DES #include "netif/ppp/polarssl/des.h" #else #include "polarssl/des.h" #endif #define SHA1_SIGNATURE_SIZE 20 static void ascii2unicode (char[], int, u_char[]); static void NTPasswordHash (u_char *, int, u_char[MD4_SIGNATURE_SIZE]); static void ChallengeResponse (u_char *, u_char *, u_char[24]); static void ChapMS_NT (u_char *, char *, int, u_char[24]); static void ChapMS2_NT (u_char *, u_char[16], char *, char *, int, u_char[24]); static void GenerateAuthenticatorResponsePlain (char*, int, u_char[24], u_char[16], u_char *, char *, u_char[41]); #ifdef MSLANMAN static void ChapMS_LANMan (u_char *, char *, int, u_char *); #endif #ifdef MPPE static void Set_Start_Key (u_char *, char *, int); static void SetMasterKeys (char *, int, u_char[24], int); #endif #ifdef MSLANMAN bool ms_lanman = 0; /* Use LanMan password instead of NT */ /* Has meaning only with MS-CHAP challenges */ #endif #ifdef MPPE u_char mppe_send_key[MPPE_MAX_KEY_LEN]; u_char mppe_recv_key[MPPE_MAX_KEY_LEN]; int mppe_keys_set = 0; /* Have the MPPE keys been set? */ #ifdef DEBUGMPPEKEY /* For MPPE debug */ /* Use "[]|}{?/><,`!2&&(" (sans quotes) for RFC 3079 MS-CHAPv2 test value */ static char *mschap_challenge = NULL; /* Use "!@\#$%^&*()_+:3|~" (sans quotes, backslash is to escape #) for ... */ static char *mschap2_peer_challenge = NULL; #endif #include "netif/ppp/fsm.h" /* Need to poke MPPE options */ #include "netif/ppp/ccp.h" #include #endif #if PPP_OPTIONS /* * Command-line options. */ static option_t chapms_option_list[] = { #ifdef MSLANMAN { "ms-lanman", o_bool, &ms_lanman, "Use LanMan passwd when using MS-CHAP", 1 }, #endif #ifdef DEBUGMPPEKEY { "mschap-challenge", o_string, &mschap_challenge, "specify CHAP challenge" }, { "mschap2-peer-challenge", o_string, &mschap2_peer_challenge, "specify CHAP peer challenge" }, #endif { NULL } }; #endif /* PPP_OPTIONS */ #if PPP_SERVER /* * chapms_generate_challenge - generate a challenge for MS-CHAP. * For MS-CHAP the challenge length is fixed at 8 bytes. * The length goes in challenge[0] and the actual challenge starts * at challenge[1]. */ static void chapms_generate_challenge(unsigned char *challenge) { *challenge++ = 8; #ifdef DEBUGMPPEKEY if (mschap_challenge && strlen(mschap_challenge) == 8) memcpy(challenge, mschap_challenge, 8); else #endif random_bytes(challenge, 8); } static void chapms2_generate_challenge(unsigned char *challenge) { *challenge++ = 16; #ifdef DEBUGMPPEKEY if (mschap_challenge && strlen(mschap_challenge) == 16) memcpy(challenge, mschap_challenge, 16); else #endif random_bytes(challenge, 16); } static int chapms_verify_response(int id, char *name, unsigned char *secret, int secret_len, unsigned char *challenge, unsigned char *response, char *message, int message_space) { unsigned char md[MS_CHAP_RESPONSE_LEN]; int diff; int challenge_len, response_len; challenge_len = *challenge++; /* skip length, is 8 */ response_len = *response++; if (response_len != MS_CHAP_RESPONSE_LEN) goto bad; #ifndef MSLANMAN if (!response[MS_CHAP_USENT]) { /* Should really propagate this into the error packet. */ ppp_notice("Peer request for LANMAN auth not supported"); goto bad; } #endif /* Generate the expected response. */ ChapMS(challenge, (char *)secret, secret_len, md); #ifdef MSLANMAN /* Determine which part of response to verify against */ if (!response[MS_CHAP_USENT]) diff = memcmp(&response[MS_CHAP_LANMANRESP], &md[MS_CHAP_LANMANRESP], MS_CHAP_LANMANRESP_LEN); else #endif diff = memcmp(&response[MS_CHAP_NTRESP], &md[MS_CHAP_NTRESP], MS_CHAP_NTRESP_LEN); if (diff == 0) { ppp_slprintf(message, message_space, "Access granted"); return 1; } bad: /* See comments below for MS-CHAP V2 */ ppp_slprintf(message, message_space, "E=691 R=1 C=%0.*B V=0", challenge_len, challenge); return 0; } static int chapms2_verify_response(int id, char *name, unsigned char *secret, int secret_len, unsigned char *challenge, unsigned char *response, char *message, int message_space) { unsigned char md[MS_CHAP2_RESPONSE_LEN]; char saresponse[MS_AUTH_RESPONSE_LENGTH+1]; int challenge_len, response_len; challenge_len = *challenge++; /* skip length, is 16 */ response_len = *response++; if (response_len != MS_CHAP2_RESPONSE_LEN) goto bad; /* not even the right length */ /* Generate the expected response and our mutual auth. */ ChapMS2(challenge, &response[MS_CHAP2_PEER_CHALLENGE], name, (char *)secret, secret_len, md, (unsigned char *)saresponse, MS_CHAP2_AUTHENTICATOR); /* compare MDs and send the appropriate status */ /* * Per RFC 2759, success message must be formatted as * "S= M=" * where * is the Authenticator Response (mutual auth) * is a text message * * However, some versions of Windows (win98 tested) do not know * about the M= part (required per RFC 2759) and flag * it as an error (reported incorrectly as an encryption error * to the user). Since the RFC requires it, and it can be * useful information, we supply it if the peer is a conforming * system. Luckily (?), win98 sets the Flags field to 0x04 * (contrary to RFC requirements) so we can use that to * distinguish between conforming and non-conforming systems. * * Special thanks to Alex Swiridov for * help debugging this. */ if (memcmp(&md[MS_CHAP2_NTRESP], &response[MS_CHAP2_NTRESP], MS_CHAP2_NTRESP_LEN) == 0) { if (response[MS_CHAP2_FLAGS]) ppp_slprintf(message, message_space, "S=%s", saresponse); else ppp_slprintf(message, message_space, "S=%s M=%s", saresponse, "Access granted"); return 1; } bad: /* * Failure message must be formatted as * "E=e R=r C=c V=v M=m" * where * e = error code (we use 691, ERROR_AUTHENTICATION_FAILURE) * r = retry (we use 1, ok to retry) * c = challenge to use for next response, we reuse previous * v = Change Password version supported, we use 0 * m = text message * * The M=m part is only for MS-CHAPv2. Neither win2k nor * win98 (others untested) display the message to the user anyway. * They also both ignore the E=e code. * * Note that it's safe to reuse the same challenge as we don't * actually accept another response based on the error message * (and no clients try to resend a response anyway). * * Basically, this whole bit is useless code, even the small * implementation here is only because of overspecification. */ ppp_slprintf(message, message_space, "E=691 R=1 C=%0.*B V=0 M=%s", challenge_len, challenge, "Access denied"); return 0; } #endif /* PPP_SERVER */ static void chapms_make_response(unsigned char *response, int id, char *our_name, unsigned char *challenge, char *secret, int secret_len, unsigned char *private) { challenge++; /* skip length, should be 8 */ *response++ = MS_CHAP_RESPONSE_LEN; ChapMS(challenge, secret, secret_len, response); } static void chapms2_make_response(unsigned char *response, int id, char *our_name, unsigned char *challenge, char *secret, int secret_len, unsigned char *private) { challenge++; /* skip length, should be 16 */ *response++ = MS_CHAP2_RESPONSE_LEN; ChapMS2(challenge, #ifdef DEBUGMPPEKEY mschap2_peer_challenge, #else NULL, #endif our_name, secret, secret_len, response, private, MS_CHAP2_AUTHENTICATEE); } static int chapms2_check_success(unsigned char *msg, int len, unsigned char *private) { if ((len < MS_AUTH_RESPONSE_LENGTH + 2) || strncmp((char *)msg, "S=", 2) != 0) { /* Packet does not start with "S=" */ ppp_error("MS-CHAPv2 Success packet is badly formed."); return 0; } msg += 2; len -= 2; if (len < MS_AUTH_RESPONSE_LENGTH || memcmp(msg, private, MS_AUTH_RESPONSE_LENGTH)) { /* Authenticator Response did not match expected. */ ppp_error("MS-CHAPv2 mutual authentication failed."); return 0; } /* Authenticator Response matches. */ msg += MS_AUTH_RESPONSE_LENGTH; /* Eat it */ len -= MS_AUTH_RESPONSE_LENGTH; if ((len >= 3) && !strncmp((char *)msg, " M=", 3)) { msg += 3; /* Eat the delimiter */ } else if (len) { /* Packet has extra text which does not begin " M=" */ ppp_error("MS-CHAPv2 Success packet is badly formed."); return 0; } return 1; } static void chapms_handle_failure(unsigned char *inp, int len) { int err; char *p, msg[64]; /* We want a null-terminated string for strxxx(). */ len = LWIP_MIN(len, 63); MEMCPY(msg, inp, len); msg[len] = 0; p = msg; /* * Deal with MS-CHAP formatted failure messages; just print the * M= part (if any). For MS-CHAP we're not really supposed * to use M=, but it shouldn't hurt. See * chapms[2]_verify_response. */ if (!strncmp(p, "E=", 2)) err = strtol(p+2, NULL, 10); /* Remember the error code. */ else goto print_msg; /* Message is badly formatted. */ if (len && ((p = strstr(p, " M=")) != NULL)) { /* M= field found. */ p += 3; } else { /* No M=; use the error code. */ switch (err) { case MS_CHAP_ERROR_RESTRICTED_LOGON_HOURS: p = "E=646 Restricted logon hours"; break; case MS_CHAP_ERROR_ACCT_DISABLED: p = "E=647 Account disabled"; break; case MS_CHAP_ERROR_PASSWD_EXPIRED: p = "E=648 Password expired"; break; case MS_CHAP_ERROR_NO_DIALIN_PERMISSION: p = "E=649 No dialin permission"; break; case MS_CHAP_ERROR_AUTHENTICATION_FAILURE: p = "E=691 Authentication failure"; break; case MS_CHAP_ERROR_CHANGING_PASSWORD: /* Should never see this, we don't support Change Password. */ p = "E=709 Error changing password"; break; default: ppp_error("Unknown MS-CHAP authentication failure: %.*v", len, inp); return; } } print_msg: if (p != NULL) ppp_error("MS-CHAP authentication failed: %v", p); } static void ChallengeResponse(u_char *challenge, u_char PasswordHash[MD4_SIGNATURE_SIZE], u_char response[24]) { u_char ZPasswordHash[21]; des_context des; u_char des_key[8]; BZERO(ZPasswordHash, sizeof(ZPasswordHash)); MEMCPY(ZPasswordHash, PasswordHash, MD4_SIGNATURE_SIZE); #if 0 dbglog("ChallengeResponse - ZPasswordHash %.*B", sizeof(ZPasswordHash), ZPasswordHash); #endif pppcrypt_56_to_64_bit_key(ZPasswordHash + 0, des_key); des_setkey_enc(&des, des_key); des_crypt_ecb(&des, challenge, response +0); pppcrypt_56_to_64_bit_key(ZPasswordHash + 7, des_key); des_setkey_enc(&des, des_key); des_crypt_ecb(&des, challenge, response +8); pppcrypt_56_to_64_bit_key(ZPasswordHash + 14, des_key); des_setkey_enc(&des, des_key); des_crypt_ecb(&des, challenge, response +16); #if 0 dbglog("ChallengeResponse - response %.24B", response); #endif } void ChallengeHash(u_char PeerChallenge[16], u_char *rchallenge, char *username, u_char Challenge[8]) { sha1_context sha1Context; u_char sha1Hash[SHA1_SIGNATURE_SIZE]; char *user; /* remove domain from "domain\username" */ if ((user = strrchr(username, '\\')) != NULL) ++user; else user = username; sha1_starts(&sha1Context); sha1_update(&sha1Context, PeerChallenge, 16); sha1_update(&sha1Context, rchallenge, 16); sha1_update(&sha1Context, (unsigned char *)user, strlen(user)); sha1_finish(&sha1Context, sha1Hash); MEMCPY(Challenge, sha1Hash, 8); } /* * Convert the ASCII version of the password to Unicode. * This implicitly supports 8-bit ISO8859/1 characters. * This gives us the little-endian representation, which * is assumed by all M$ CHAP RFCs. (Unicode byte ordering * is machine-dependent.) */ static void ascii2unicode(char ascii[], int ascii_len, u_char unicode[]) { int i; BZERO(unicode, ascii_len * 2); for (i = 0; i < ascii_len; i++) unicode[i * 2] = (u_char) ascii[i]; } static void NTPasswordHash(u_char *secret, int secret_len, u_char hash[MD4_SIGNATURE_SIZE]) { md4_context md4Context; md4_starts(&md4Context); md4_update(&md4Context, secret, secret_len); md4_finish(&md4Context, hash); } static void ChapMS_NT(u_char *rchallenge, char *secret, int secret_len, u_char NTResponse[24]) { u_char unicodePassword[MAX_NT_PASSWORD * 2]; u_char PasswordHash[MD4_SIGNATURE_SIZE]; /* Hash the Unicode version of the secret (== password). */ ascii2unicode(secret, secret_len, unicodePassword); NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash); ChallengeResponse(rchallenge, PasswordHash, NTResponse); } static void ChapMS2_NT(u_char *rchallenge, u_char PeerChallenge[16], char *username, char *secret, int secret_len, u_char NTResponse[24]) { u_char unicodePassword[MAX_NT_PASSWORD * 2]; u_char PasswordHash[MD4_SIGNATURE_SIZE]; u_char Challenge[8]; ChallengeHash(PeerChallenge, rchallenge, username, Challenge); /* Hash the Unicode version of the secret (== password). */ ascii2unicode(secret, secret_len, unicodePassword); NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash); ChallengeResponse(Challenge, PasswordHash, NTResponse); } #ifdef MSLANMAN static u_char *StdText = (u_char *)"KGS!@#$%"; /* key from rasapi32.dll */ static void ChapMS_LANMan(u_char *rchallenge, char *secret, int secret_len, unsigned char *response) { int i; u_char UcasePassword[MAX_NT_PASSWORD]; /* max is actually 14 */ u_char PasswordHash[MD4_SIGNATURE_SIZE]; des_context des; u_char des_key[8]; /* LANMan password is case insensitive */ BZERO(UcasePassword, sizeof(UcasePassword)); for (i = 0; i < secret_len; i++) UcasePassword[i] = (u_char)toupper(secret[i]); pppcrypt_56_to_64_bit_key(UcasePassword +0, des_key); des_setkey_enc(&des, des_key); des_crypt_ecb(&des, StdText, PasswordHash +0); pppcrypt_56_to_64_bit_key(UcasePassword +7, des_key); des_setkey_enc(&des, des_key); des_crypt_ecb(&des, StdText, PasswordHash +8); ChallengeResponse(rchallenge, PasswordHash, &response[MS_CHAP_LANMANRESP]); } #endif void GenerateAuthenticatorResponse(u_char PasswordHashHash[MD4_SIGNATURE_SIZE], u_char NTResponse[24], u_char PeerChallenge[16], u_char *rchallenge, char *username, u_char authResponse[MS_AUTH_RESPONSE_LENGTH+1]) { /* * "Magic" constants used in response generation, from RFC 2759. */ u_char Magic1[39] = /* "Magic server to client signing constant" */ { 0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65, 0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67, 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74 }; u_char Magic2[41] = /* "Pad to make it do more than one iteration" */ { 0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B, 0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F, 0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E, 0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F, 0x6E }; int i; sha1_context sha1Context; u_char Digest[SHA1_SIGNATURE_SIZE]; u_char Challenge[8]; sha1_starts(&sha1Context); sha1_update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE); sha1_update(&sha1Context, NTResponse, 24); sha1_update(&sha1Context, Magic1, sizeof(Magic1)); sha1_finish(&sha1Context, Digest); ChallengeHash(PeerChallenge, rchallenge, username, Challenge); sha1_starts(&sha1Context); sha1_update(&sha1Context, Digest, sizeof(Digest)); sha1_update(&sha1Context, Challenge, sizeof(Challenge)); sha1_update(&sha1Context, Magic2, sizeof(Magic2)); sha1_finish(&sha1Context, Digest); /* Convert to ASCII hex string. */ for (i = 0; i < LWIP_MAX((MS_AUTH_RESPONSE_LENGTH / 2), sizeof(Digest)); i++) sprintf((char *)&authResponse[i * 2], "%02X", Digest[i]); } static void GenerateAuthenticatorResponsePlain (char *secret, int secret_len, u_char NTResponse[24], u_char PeerChallenge[16], u_char *rchallenge, char *username, u_char authResponse[MS_AUTH_RESPONSE_LENGTH+1]) { u_char unicodePassword[MAX_NT_PASSWORD * 2]; u_char PasswordHash[MD4_SIGNATURE_SIZE]; u_char PasswordHashHash[MD4_SIGNATURE_SIZE]; /* Hash (x2) the Unicode version of the secret (== password). */ ascii2unicode(secret, secret_len, unicodePassword); NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash); NTPasswordHash(PasswordHash, sizeof(PasswordHash), PasswordHashHash); GenerateAuthenticatorResponse(PasswordHashHash, NTResponse, PeerChallenge, rchallenge, username, authResponse); } #ifdef MPPE /* * Set mppe_xxxx_key from the NTPasswordHashHash. * RFC 2548 (RADIUS support) requires us to export this function (ugh). */ void mppe_set_keys(u_char *rchallenge, u_char PasswordHashHash[MD4_SIGNATURE_SIZE]) { sha1_context sha1Context; u_char Digest[SHA1_SIGNATURE_SIZE]; /* >= MPPE_MAX_KEY_LEN */ sha1_starts(&sha1Context); sha1_update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE); sha1_update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE); sha1_update(&sha1Context, rchallenge, 8); sha1_finish(&sha1Context, Digest); /* Same key in both directions. */ MEMCPY(mppe_send_key, Digest, sizeof(mppe_send_key)); MEMCPY(mppe_recv_key, Digest, sizeof(mppe_recv_key)); mppe_keys_set = 1; } /* * Set mppe_xxxx_key from MS-CHAP credentials. (see RFC 3079) */ static void Set_Start_Key(u_char *rchallenge, char *secret, int secret_len) { u_char unicodePassword[MAX_NT_PASSWORD * 2]; u_char PasswordHash[MD4_SIGNATURE_SIZE]; u_char PasswordHashHash[MD4_SIGNATURE_SIZE]; /* Hash (x2) the Unicode version of the secret (== password). */ ascii2unicode(secret, secret_len, unicodePassword); NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash); NTPasswordHash(PasswordHash, sizeof(PasswordHash), PasswordHashHash); mppe_set_keys(rchallenge, PasswordHashHash); } /* * Set mppe_xxxx_key from MS-CHAPv2 credentials. (see RFC 3079) * * This helper function used in the Winbind module, which gets the * NTHashHash from the server. */ void mppe_set_keys2(u_char PasswordHashHash[MD4_SIGNATURE_SIZE], u_char NTResponse[24], int IsServer) { sha1_context sha1Context; u_char MasterKey[SHA1_SIGNATURE_SIZE]; /* >= MPPE_MAX_KEY_LEN */ u_char Digest[SHA1_SIGNATURE_SIZE]; /* >= MPPE_MAX_KEY_LEN */ u_char SHApad1[40] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; u_char SHApad2[40] = { 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2 }; /* "This is the MPPE Master Key" */ u_char Magic1[27] = { 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x4d, 0x50, 0x50, 0x45, 0x20, 0x4d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x4b, 0x65, 0x79 }; /* "On the client side, this is the send key; " "on the server side, it is the receive key." */ u_char Magic2[84] = { 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79, 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20, 0x6b, 0x65, 0x79, 0x2e }; /* "On the client side, this is the receive key; " "on the server side, it is the send key." */ u_char Magic3[84] = { 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20, 0x6b, 0x65, 0x79, 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79, 0x2e }; u_char *s; sha1_starts(&sha1Context); sha1_update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE); sha1_update(&sha1Context, NTResponse, 24); sha1_update(&sha1Context, Magic1, sizeof(Magic1)); sha1_finish(&sha1Context, MasterKey); /* * generate send key */ if (IsServer) s = Magic3; else s = Magic2; sha1_starts(&sha1Context); sha1_update(&sha1Context, MasterKey, 16); sha1_update(&sha1Context, SHApad1, sizeof(SHApad1)); sha1_update(&sha1Context, s, 84); sha1_update(&sha1Context, SHApad2, sizeof(SHApad2)); sha1_finish(&sha1Context, Digest); MEMCPY(mppe_send_key, Digest, sizeof(mppe_send_key)); /* * generate recv key */ if (IsServer) s = Magic2; else s = Magic3; sha1_starts(&sha1Context); sha1_update(&sha1Context, MasterKey, 16); sha1_update(&sha1Context, SHApad1, sizeof(SHApad1)); sha1_update(&sha1Context, s, 84); sha1_update(&sha1Context, SHApad2, sizeof(SHApad2)); sha1_finish(&sha1Context, Digest); MEMCPY(mppe_recv_key, Digest, sizeof(mppe_recv_key)); mppe_keys_set = 1; } /* * Set mppe_xxxx_key from MS-CHAPv2 credentials. (see RFC 3079) */ static void SetMasterKeys(char *secret, int secret_len, u_char NTResponse[24], int IsServer) { u_char unicodePassword[MAX_NT_PASSWORD * 2]; u_char PasswordHash[MD4_SIGNATURE_SIZE]; u_char PasswordHashHash[MD4_SIGNATURE_SIZE]; /* Hash (x2) the Unicode version of the secret (== password). */ ascii2unicode(secret, secret_len, unicodePassword); NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash); NTPasswordHash(PasswordHash, sizeof(PasswordHash), PasswordHashHash); mppe_set_keys2(PasswordHashHash, NTResponse, IsServer); } #endif /* MPPE */ void ChapMS(u_char *rchallenge, char *secret, int secret_len, unsigned char *response) { BZERO(response, MS_CHAP_RESPONSE_LEN); ChapMS_NT(rchallenge, secret, secret_len, &response[MS_CHAP_NTRESP]); #ifdef MSLANMAN ChapMS_LANMan(rchallenge, secret, secret_len, &response[MS_CHAP_LANMANRESP]); /* preferred method is set by option */ response[MS_CHAP_USENT] = !ms_lanman; #else response[MS_CHAP_USENT] = 1; #endif #ifdef MPPE Set_Start_Key(rchallenge, secret, secret_len); #endif } /* * If PeerChallenge is NULL, one is generated and the PeerChallenge * field of response is filled in. Call this way when generating a response. * If PeerChallenge is supplied, it is copied into the PeerChallenge field. * Call this way when verifying a response (or debugging). * Do not call with PeerChallenge = response. * * The PeerChallenge field of response is then used for calculation of the * Authenticator Response. */ void ChapMS2(u_char *rchallenge, u_char *PeerChallenge, char *user, char *secret, int secret_len, unsigned char *response, u_char authResponse[], int authenticator) { /* ARGSUSED */ u_char *p = &response[MS_CHAP2_PEER_CHALLENGE]; int i; BZERO(response, MS_CHAP2_RESPONSE_LEN); /* Generate the Peer-Challenge if requested, or copy it if supplied. */ if (!PeerChallenge) for (i = 0; i < MS_CHAP2_PEER_CHAL_LEN; i++) *p++ = (u_char) (drand48() * 0xff); else MEMCPY(&response[MS_CHAP2_PEER_CHALLENGE], PeerChallenge, MS_CHAP2_PEER_CHAL_LEN); /* Generate the NT-Response */ ChapMS2_NT(rchallenge, &response[MS_CHAP2_PEER_CHALLENGE], user, secret, secret_len, &response[MS_CHAP2_NTRESP]); /* Generate the Authenticator Response. */ GenerateAuthenticatorResponsePlain(secret, secret_len, &response[MS_CHAP2_NTRESP], &response[MS_CHAP2_PEER_CHALLENGE], rchallenge, user, authResponse); #ifdef MPPE SetMasterKeys(secret, secret_len, &response[MS_CHAP2_NTRESP], authenticator); #endif } #ifdef MPPE /* * Set MPPE options from plugins. */ void set_mppe_enc_types(int policy, int types) { /* Early exit for unknown policies. */ if (policy != MPPE_ENC_POL_ENC_ALLOWED || policy != MPPE_ENC_POL_ENC_REQUIRED) return; /* Don't modify MPPE if it's optional and wasn't already configured. */ if (policy == MPPE_ENC_POL_ENC_ALLOWED && !ccp_wantoptions[0].mppe) return; /* * Disable undesirable encryption types. Note that we don't ENABLE * any encryption types, to avoid overriding manual configuration. */ switch(types) { case MPPE_ENC_TYPES_RC4_40: ccp_wantoptions[0].mppe &= ~MPPE_OPT_128; /* disable 128-bit */ break; case MPPE_ENC_TYPES_RC4_128: ccp_wantoptions[0].mppe &= ~MPPE_OPT_40; /* disable 40-bit */ break; default: break; } } #endif /* MPPE */ const struct chap_digest_type chapms_digest = { CHAP_MICROSOFT, /* code */ #if PPP_SERVER chapms_generate_challenge, chapms_verify_response, #endif /* PPP_SERVER */ chapms_make_response, NULL, /* check_success */ chapms_handle_failure, }; const struct chap_digest_type chapms2_digest = { CHAP_MICROSOFT_V2, /* code */ #if PPP_SERVER chapms2_generate_challenge, chapms2_verify_response, #endif /* PPP_SERVER */ chapms2_make_response, chapms2_check_success, chapms_handle_failure, }; #endif /* PPP_SUPPORT && MSCHAP_SUPPORT */ ocproxy-1.60/lwip/src/netif/ppp/demand.c000066400000000000000000000317431303453231400202130ustar00rootroot00000000000000/* * demand.c - Support routines for demand-dialling. * * Copyright (c) 1996-2002 Paul Mackerras. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. The name(s) of the authors of this software must not be used to * endorse or promote products derived from this software without * prior written permission. * * 3. Redistributions of any form whatsoever must retain the following * acknowledgment: * "This product includes software developed by Paul Mackerras * ". * * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "lwip/opt.h" #if PPP_SUPPORT && DEMAND_SUPPORT /* don't build if not configured for use in lwipopts.h */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef PPP_FILTER #include #endif #include "netif/ppp/ppp_impl.h" #include "netif/ppp/fsm.h" #include "netif/ppp/ipcp.h" #include "netif/ppp/lcp.h" char *frame; int framelen; int framemax; int escape_flag; int flush_flag; int fcs; struct packet { int length; struct packet *next; unsigned char data[1]; }; struct packet *pend_q; struct packet *pend_qtail; static int active_packet (unsigned char *, int); /* * demand_conf - configure the interface for doing dial-on-demand. */ void demand_conf() { int i; const struct protent *protp; /* framemax = lcp_allowoptions[0].mru; if (framemax < PPP_MRU) */ framemax = PPP_MRU; framemax += PPP_HDRLEN + PPP_FCSLEN; frame = malloc(framemax); if (frame == NULL) novm("demand frame"); framelen = 0; pend_q = NULL; escape_flag = 0; flush_flag = 0; fcs = PPP_INITFCS; netif_set_mtu(pcb, LWIP_MIN(lcp_allowoptions[0].mru, PPP_MRU)); if (ppp_send_config(pcb, PPP_MRU, (u32_t) 0, 0, 0) < 0 || ppp_recv_config(pcb, PPP_MRU, (u32_t) 0, 0, 0) < 0) fatal("Couldn't set up demand-dialled PPP interface: %m"); #ifdef PPP_FILTER set_filters(&pass_filter, &active_filter); #endif /* * Call the demand_conf procedure for each protocol that's got one. */ for (i = 0; (protp = protocols[i]) != NULL; ++i) if (protp->enabled_flag && protp->demand_conf != NULL) ((*protp->demand_conf)(pcb)); /* FIXME: find a way to die() here */ #if 0 if (!((*protp->demand_conf)(pcb))) die(1); #endif } /* * demand_block - set each network protocol to block further packets. */ void demand_block() { int i; const struct protent *protp; for (i = 0; (protp = protocols[i]) != NULL; ++i) if (protp->enabled_flag && protp->demand_conf != NULL) sifnpmode(pcb, protp->protocol & ~0x8000, NPMODE_QUEUE); get_loop_output(); } /* * demand_discard - set each network protocol to discard packets * with an error. */ void demand_discard() { struct packet *pkt, *nextpkt; int i; const struct protent *protp; for (i = 0; (protp = protocols[i]) != NULL; ++i) if (protp->enabled_flag && protp->demand_conf != NULL) sifnpmode(pcb, protp->protocol & ~0x8000, NPMODE_ERROR); get_loop_output(); /* discard all saved packets */ for (pkt = pend_q; pkt != NULL; pkt = nextpkt) { nextpkt = pkt->next; free(pkt); } pend_q = NULL; framelen = 0; flush_flag = 0; escape_flag = 0; fcs = PPP_INITFCS; } /* * demand_unblock - set each enabled network protocol to pass packets. */ void demand_unblock() { int i; const struct protent *protp; for (i = 0; (protp = protocols[i]) != NULL; ++i) if (protp->enabled_flag && protp->demand_conf != NULL) sifnpmode(pcb, protp->protocol & ~0x8000, NPMODE_PASS); } /* * FCS lookup table as calculated by genfcstab. */ static u_short fcstab[256] = { 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7, 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e, 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876, 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c, 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974, 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb, 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3, 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a, 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72, 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9, 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1, 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70, 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7, 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff, 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036, 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e, 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5, 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd, 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134, 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3, 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb, 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232, 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a, 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1, 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9, 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78 }; /* * loop_chars - process characters received from the loopback. * Calls loop_frame when a complete frame has been accumulated. * Return value is 1 if we need to bring up the link, 0 otherwise. */ int loop_chars(p, n) unsigned char *p; int n; { int c, rv; rv = 0; /* check for synchronous connection... */ if ( (p[0] == 0xFF) && (p[1] == 0x03) ) { rv = loop_frame(p,n); return rv; } for (; n > 0; --n) { c = *p++; if (c == PPP_FLAG) { if (!escape_flag && !flush_flag && framelen > 2 && fcs == PPP_GOODFCS) { framelen -= 2; if (loop_frame((unsigned char *)frame, framelen)) rv = 1; } framelen = 0; flush_flag = 0; escape_flag = 0; fcs = PPP_INITFCS; continue; } if (flush_flag) continue; if (escape_flag) { c ^= PPP_TRANS; escape_flag = 0; } else if (c == PPP_ESCAPE) { escape_flag = 1; continue; } if (framelen >= framemax) { flush_flag = 1; continue; } frame[framelen++] = c; fcs = PPP_FCS(fcs, c); } return rv; } /* * loop_frame - given a frame obtained from the loopback, * decide whether to bring up the link or not, and, if we want * to transmit this frame later, put it on the pending queue. * Return value is 1 if we need to bring up the link, 0 otherwise. * We assume that the kernel driver has already applied the * pass_filter, so we won't get packets it rejected. * We apply the active_filter to see if we want this packet to * bring up the link. */ int loop_frame(frame, len) unsigned char *frame; int len; { struct packet *pkt; /* dbglog("from loop: %P", frame, len); */ if (len < PPP_HDRLEN) return 0; if ((PPP_PROTOCOL(frame) & 0x8000) != 0) return 0; /* shouldn't get any of these anyway */ if (!active_packet(frame, len)) return 0; pkt = (struct packet *) malloc(sizeof(struct packet) + len); if (pkt != NULL) { pkt->length = len; pkt->next = NULL; memcpy(pkt->data, frame, len); if (pend_q == NULL) pend_q = pkt; else pend_qtail->next = pkt; pend_qtail = pkt; } return 1; } /* * demand_rexmit - Resend all those frames which we got via the * loopback, now that the real serial link is up. */ void demand_rexmit(proto, newip) int proto; u32_t newip; { struct packet *pkt, *prev, *nextpkt; unsigned short checksum; unsigned short pkt_checksum = 0; unsigned iphdr; struct timeval tv; char cv = 0; char ipstr[16]; prev = NULL; pkt = pend_q; pend_q = NULL; tv.tv_sec = 1; tv.tv_usec = 0; select(0,NULL,NULL,NULL,&tv); /* Sleep for 1 Seconds */ for (; pkt != NULL; pkt = nextpkt) { nextpkt = pkt->next; if (PPP_PROTOCOL(pkt->data) == proto) { if ( (proto == PPP_IP) && newip ) { /* Get old checksum */ iphdr = (pkt->data[4] & 15) << 2; checksum = *((unsigned short *) (pkt->data+14)); if (checksum == 0xFFFF) { checksum = 0; } if (pkt->data[13] == 17) { pkt_checksum = *((unsigned short *) (pkt->data+10+iphdr)); if (pkt_checksum) { cv = 1; if (pkt_checksum == 0xFFFF) { pkt_checksum = 0; } } else { cv = 0; } } if (pkt->data[13] == 6) { pkt_checksum = *((unsigned short *) (pkt->data+20+iphdr)); cv = 1; if (pkt_checksum == 0xFFFF) { pkt_checksum = 0; } } /* Delete old Source-IP-Address */ checksum -= *((unsigned short *) (pkt->data+16)) ^ 0xFFFF; checksum -= *((unsigned short *) (pkt->data+18)) ^ 0xFFFF; pkt_checksum -= *((unsigned short *) (pkt->data+16)) ^ 0xFFFF; pkt_checksum -= *((unsigned short *) (pkt->data+18)) ^ 0xFFFF; /* Change Source-IP-Address */ * ((u32_t *) (pkt->data + 16)) = newip; /* Add new Source-IP-Address */ checksum += *((unsigned short *) (pkt->data+16)) ^ 0xFFFF; checksum += *((unsigned short *) (pkt->data+18)) ^ 0xFFFF; pkt_checksum += *((unsigned short *) (pkt->data+16)) ^ 0xFFFF; pkt_checksum += *((unsigned short *) (pkt->data+18)) ^ 0xFFFF; /* Write new checksum */ if (!checksum) { checksum = 0xFFFF; } *((unsigned short *) (pkt->data+14)) = checksum; if (pkt->data[13] == 6) { *((unsigned short *) (pkt->data+20+iphdr)) = pkt_checksum; } if (cv && (pkt->data[13] == 17) ) { *((unsigned short *) (pkt->data+10+iphdr)) = pkt_checksum; } /* Log Packet */ strcpy(ipstr,inet_ntoa(*( (struct in_addr *) (pkt->data+16)))); if (pkt->data[13] == 1) { syslog(LOG_INFO,"Open ICMP %s -> %s\n", ipstr, inet_ntoa(*( (struct in_addr *) (pkt->data+20)))); } else { syslog(LOG_INFO,"Open %s %s:%d -> %s:%d\n", pkt->data[13] == 6 ? "TCP" : "UDP", ipstr, ntohs(*( (short *) (pkt->data+iphdr+4))), inet_ntoa(*( (struct in_addr *) (pkt->data+20))), ntohs(*( (short *) (pkt->data+iphdr+6)))); } } output(pcb, pkt->data, pkt->length); free(pkt); } else { if (prev == NULL) pend_q = pkt; else prev->next = pkt; prev = pkt; } } pend_qtail = prev; if (prev != NULL) prev->next = NULL; } /* * Scan a packet to decide whether it is an "active" packet, * that is, whether it is worth bringing up the link for. */ static int active_packet(p, len) unsigned char *p; int len; { int proto, i; const struct protent *protp; if (len < PPP_HDRLEN) return 0; proto = PPP_PROTOCOL(p); #ifdef PPP_FILTER p[0] = 1; /* outbound packet indicator */ if ((pass_filter.bf_len != 0 && bpf_filter(pass_filter.bf_insns, p, len, len) == 0) || (active_filter.bf_len != 0 && bpf_filter(active_filter.bf_insns, p, len, len) == 0)) { p[0] = 0xff; return 0; } p[0] = 0xff; #endif for (i = 0; (protp = protocols[i]) != NULL; ++i) { if (protp->protocol < 0xC000 && (protp->protocol & ~0x8000) == proto) { if (!protp->enabled_flag) return 0; if (protp->active_pkt == NULL) return 1; return (*protp->active_pkt)(p, len); } } return 0; /* not a supported protocol !!?? */ } #endif /* PPP_SUPPORT && DEMAND_SUPPORT */ ocproxy-1.60/lwip/src/netif/ppp/eap.c000066400000000000000000001721301303453231400175240ustar00rootroot00000000000000/* * eap.c - Extensible Authentication Protocol for PPP (RFC 2284) * * Copyright (c) 2001 by Sun Microsystems, Inc. * All rights reserved. * * Non-exclusive rights to redistribute, modify, translate, and use * this software in source and binary forms, in whole or in part, is * hereby granted, provided that the above copyright notice is * duplicated in any source form, and that neither the name of the * copyright holder nor the author is used to endorse or promote * products derived from this software. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. * * Original version by James Carlson * * This implementation of EAP supports MD5-Challenge and SRP-SHA1 * authentication styles. Note that support of MD5-Challenge is a * requirement of RFC 2284, and that it's essentially just a * reimplementation of regular RFC 1994 CHAP using EAP messages. * * As an authenticator ("server"), there are multiple phases for each * style. In the first phase of each style, the unauthenticated peer * name is queried using the EAP Identity request type. If the * "remotename" option is used, then this phase is skipped, because * the peer's name is presumed to be known. * * For MD5-Challenge, there are two phases, and the second phase * consists of sending the challenge itself and handling the * associated response. * * For SRP-SHA1, there are four phases. The second sends 's', 'N', * and 'g'. The reply contains 'A'. The third sends 'B', and the * reply contains 'M1'. The forth sends the 'M2' value. * * As an authenticatee ("client"), there's just a single phase -- * responding to the queries generated by the peer. EAP is an * authenticator-driven protocol. * * Based on draft-ietf-pppext-eap-srp-03.txt. */ #include "lwip/opt.h" #if PPP_SUPPORT && EAP_SUPPORT /* don't build if not configured for use in lwipopts.h */ #include "netif/ppp/ppp_impl.h" #if LWIP_INCLUDED_POLARSSL_MD5 #include "netif/ppp/polarssl/md5.h" #else #include "polarssl/md5.h" #endif #include "netif/ppp/eap.h" #ifdef USE_SRP #include #include #include #include "netif/ppp/pppcrypt.h" #endif /* USE_SRP */ #ifndef SHA_DIGESTSIZE #define SHA_DIGESTSIZE 20 #endif #ifdef USE_SRP static char *pn_secret = NULL; /* Pseudonym generating secret */ #endif #if PPP_OPTIONS /* * Command-line options. */ static option_t eap_option_list[] = { { "eap-restart", o_int, &eap_states[0].es_server.ea_timeout, "Set retransmit timeout for EAP Requests (server)" }, { "eap-max-sreq", o_int, &eap_states[0].es_server.ea_maxrequests, "Set max number of EAP Requests sent (server)" }, { "eap-timeout", o_int, &eap_states[0].es_client.ea_timeout, "Set time limit for peer EAP authentication" }, { "eap-max-rreq", o_int, &eap_states[0].es_client.ea_maxrequests, "Set max number of EAP Requests allows (client)" }, { "eap-interval", o_int, &eap_states[0].es_rechallenge, "Set interval for EAP rechallenge" }, #ifdef USE_SRP { "srp-interval", o_int, &eap_states[0].es_lwrechallenge, "Set interval for SRP lightweight rechallenge" }, { "srp-pn-secret", o_string, &pn_secret, "Long term pseudonym generation secret" }, { "srp-use-pseudonym", o_bool, &eap_states[0].es_usepseudo, "Use pseudonym if offered one by server", 1 }, #endif { NULL } }; #endif /* PPP_OPTIONS */ /* * Protocol entry points. */ static void eap_init(ppp_pcb *pcb); static void eap_input(ppp_pcb *pcb, u_char *inp, int inlen); static void eap_protrej(ppp_pcb *pcb); static void eap_lowerup(ppp_pcb *pcb); static void eap_lowerdown(ppp_pcb *pcb); #if PRINTPKT_SUPPORT static int eap_printpkt(u_char *inp, int inlen, void (*)(void *arg, char *fmt, ...), void *arg); #endif /* PRINTPKT_SUPPORT */ const struct protent eap_protent = { PPP_EAP, /* protocol number */ eap_init, /* initialization procedure */ eap_input, /* process a received packet */ eap_protrej, /* process a received protocol-reject */ eap_lowerup, /* lower layer has gone up */ eap_lowerdown, /* lower layer has gone down */ NULL, /* open the protocol */ NULL, /* close the protocol */ #if PRINTPKT_SUPPORT eap_printpkt, /* print a packet in readable form */ #endif /* PRINTPKT_SUPPORT */ NULL, /* process a received data packet */ 1, /* protocol enabled */ #if PRINTPKT_SUPPORT "EAP", /* text name of protocol */ NULL, /* text name of corresponding data protocol */ #endif /* PRINTPKT_SUPPORT */ #if PPP_OPTIONS eap_option_list, /* list of command-line options */ NULL, /* check requested options; assign defaults */ #endif /* PPP_OPTIONS */ #if DEMAND_SUPPORT NULL, /* configure interface for demand-dial */ NULL /* say whether to bring up link for this pkt */ #endif /* DEMAND_SUPPORT */ }; #ifdef USE_SRP /* * A well-known 2048 bit modulus. */ static const u_char wkmodulus[] = { 0xAC, 0x6B, 0xDB, 0x41, 0x32, 0x4A, 0x9A, 0x9B, 0xF1, 0x66, 0xDE, 0x5E, 0x13, 0x89, 0x58, 0x2F, 0xAF, 0x72, 0xB6, 0x65, 0x19, 0x87, 0xEE, 0x07, 0xFC, 0x31, 0x92, 0x94, 0x3D, 0xB5, 0x60, 0x50, 0xA3, 0x73, 0x29, 0xCB, 0xB4, 0xA0, 0x99, 0xED, 0x81, 0x93, 0xE0, 0x75, 0x77, 0x67, 0xA1, 0x3D, 0xD5, 0x23, 0x12, 0xAB, 0x4B, 0x03, 0x31, 0x0D, 0xCD, 0x7F, 0x48, 0xA9, 0xDA, 0x04, 0xFD, 0x50, 0xE8, 0x08, 0x39, 0x69, 0xED, 0xB7, 0x67, 0xB0, 0xCF, 0x60, 0x95, 0x17, 0x9A, 0x16, 0x3A, 0xB3, 0x66, 0x1A, 0x05, 0xFB, 0xD5, 0xFA, 0xAA, 0xE8, 0x29, 0x18, 0xA9, 0x96, 0x2F, 0x0B, 0x93, 0xB8, 0x55, 0xF9, 0x79, 0x93, 0xEC, 0x97, 0x5E, 0xEA, 0xA8, 0x0D, 0x74, 0x0A, 0xDB, 0xF4, 0xFF, 0x74, 0x73, 0x59, 0xD0, 0x41, 0xD5, 0xC3, 0x3E, 0xA7, 0x1D, 0x28, 0x1E, 0x44, 0x6B, 0x14, 0x77, 0x3B, 0xCA, 0x97, 0xB4, 0x3A, 0x23, 0xFB, 0x80, 0x16, 0x76, 0xBD, 0x20, 0x7A, 0x43, 0x6C, 0x64, 0x81, 0xF1, 0xD2, 0xB9, 0x07, 0x87, 0x17, 0x46, 0x1A, 0x5B, 0x9D, 0x32, 0xE6, 0x88, 0xF8, 0x77, 0x48, 0x54, 0x45, 0x23, 0xB5, 0x24, 0xB0, 0xD5, 0x7D, 0x5E, 0xA7, 0x7A, 0x27, 0x75, 0xD2, 0xEC, 0xFA, 0x03, 0x2C, 0xFB, 0xDB, 0xF5, 0x2F, 0xB3, 0x78, 0x61, 0x60, 0x27, 0x90, 0x04, 0xE5, 0x7A, 0xE6, 0xAF, 0x87, 0x4E, 0x73, 0x03, 0xCE, 0x53, 0x29, 0x9C, 0xCC, 0x04, 0x1C, 0x7B, 0xC3, 0x08, 0xD8, 0x2A, 0x56, 0x98, 0xF3, 0xA8, 0xD0, 0xC3, 0x82, 0x71, 0xAE, 0x35, 0xF8, 0xE9, 0xDB, 0xFB, 0xB6, 0x94, 0xB5, 0xC8, 0x03, 0xD8, 0x9F, 0x7A, 0xE4, 0x35, 0xDE, 0x23, 0x6D, 0x52, 0x5F, 0x54, 0x75, 0x9B, 0x65, 0xE3, 0x72, 0xFC, 0xD6, 0x8E, 0xF2, 0x0F, 0xA7, 0x11, 0x1F, 0x9E, 0x4A, 0xFF, 0x73 }; #endif #if PPP_SERVER /* Local forward declarations. */ static void eap_server_timeout(void *arg); #endif /* PPP_SERVER */ /* * Convert EAP state code to printable string for debug. */ static const char * eap_state_name(esc) enum eap_state_code esc; { static const char *state_names[] = { EAP_STATES }; return (state_names[(int)esc]); } /* * eap_init - Initialize state for an EAP user. This is currently * called once by main() during start-up. */ static void eap_init(ppp_pcb *pcb) { BZERO(&pcb->eap, sizeof(eap_state)); #if PPP_SERVER pcb->eap.es_server.ea_id = (u_char)(drand48() * 0x100); /* FIXME: use magic.c random function */ #endif /* PPP_SERVER */ } /* * eap_client_timeout - Give up waiting for the peer to send any * Request messages. */ static void eap_client_timeout(void *arg) { ppp_pcb *pcb = (ppp_pcb*)arg; if (!eap_client_active(pcb)) return; ppp_error("EAP: timeout waiting for Request from peer"); auth_withpeer_fail(pcb, PPP_EAP); pcb->eap.es_client.ea_state = eapBadAuth; } /* * eap_authwithpeer - Authenticate to our peer (behave as client). * * Start client state and wait for requests. This is called only * after eap_lowerup. */ void eap_authwithpeer(ppp_pcb *pcb, char *localname) { if(NULL == localname) return; /* Save the peer name we're given */ pcb->eap.es_client.ea_name = localname; pcb->eap.es_client.ea_namelen = strlen(localname); pcb->eap.es_client.ea_state = eapListen; /* * Start a timer so that if the other end just goes * silent, we don't sit here waiting forever. */ if (pcb->settings.eap_req_time > 0) TIMEOUT(eap_client_timeout, pcb, pcb->settings.eap_req_time); } #if PPP_SERVER /* * Format a standard EAP Failure message and send it to the peer. * (Server operation) */ static void eap_send_failure(ppp_pcb *pcb) { struct pbuf *p; u_char *outp; p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_HDRLEN + EAP_HEADERLEN), PPP_CTRL_PBUF_TYPE); if(NULL == p) return; if(p->tot_len != p->len) { pbuf_free(p); return; } outp = p->payload; MAKEHEADER(outp, PPP_EAP); PUTCHAR(EAP_FAILURE, outp); pcb->eap.es_server.ea_id++; PUTCHAR(pcb->eap.es_server.ea_id, outp); PUTSHORT(EAP_HEADERLEN, outp); ppp_write(pcb, p); pcb->eap.es_server.ea_state = eapBadAuth; auth_peer_fail(pcb, PPP_EAP); } /* * Format a standard EAP Success message and send it to the peer. * (Server operation) */ static void eap_send_success(ppp_pcb *pcb) { struct pbuf *p; u_char *outp; p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_HDRLEN + EAP_HEADERLEN), PPP_CTRL_PBUF_TYPE); if(NULL == p) return; if(p->tot_len != p->len) { pbuf_free(p); return; } outp = p->payload; MAKEHEADER(outp, PPP_EAP); PUTCHAR(EAP_SUCCESS, outp); pcb->eap.es_server.ea_id++; PUTCHAR(pcb->eap.es_server.ea_id, outp); PUTSHORT(EAP_HEADERLEN, outp); ppp_write(pcb, p); auth_peer_success(pcb, PPP_EAP, 0, pcb->eap.es_server.ea_peer, pcb->eap.es_server.ea_peerlen); } #endif /* PPP_SERVER */ #ifdef USE_SRP /* * Set DES key according to pseudonym-generating secret and current * date. */ static bool pncrypt_setkey(int timeoffs) { struct tm *tp; char tbuf[9]; SHA1_CTX ctxt; u_char dig[SHA_DIGESTSIZE]; time_t reftime; if (pn_secret == NULL) return (0); reftime = time(NULL) + timeoffs; tp = localtime(&reftime); SHA1Init(&ctxt); SHA1Update(&ctxt, pn_secret, strlen(pn_secret)); strftime(tbuf, sizeof (tbuf), "%Y%m%d", tp); SHA1Update(&ctxt, tbuf, strlen(tbuf)); SHA1Final(dig, &ctxt); /* FIXME: if we want to do SRP, we need to find a way to pass the PolarSSL des_context instead of using static memory */ return (DesSetkey(dig)); } static char base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; struct b64state { u32_t bs_bits; int bs_offs; }; static int b64enc(bs, inp, inlen, outp) struct b64state *bs; u_char *inp; int inlen; u_char *outp; { int outlen = 0; while (inlen > 0) { bs->bs_bits = (bs->bs_bits << 8) | *inp++; inlen--; bs->bs_offs += 8; if (bs->bs_offs >= 24) { *outp++ = base64[(bs->bs_bits >> 18) & 0x3F]; *outp++ = base64[(bs->bs_bits >> 12) & 0x3F]; *outp++ = base64[(bs->bs_bits >> 6) & 0x3F]; *outp++ = base64[bs->bs_bits & 0x3F]; outlen += 4; bs->bs_offs = 0; bs->bs_bits = 0; } } return (outlen); } static int b64flush(bs, outp) struct b64state *bs; u_char *outp; { int outlen = 0; if (bs->bs_offs == 8) { *outp++ = base64[(bs->bs_bits >> 2) & 0x3F]; *outp++ = base64[(bs->bs_bits << 4) & 0x3F]; outlen = 2; } else if (bs->bs_offs == 16) { *outp++ = base64[(bs->bs_bits >> 10) & 0x3F]; *outp++ = base64[(bs->bs_bits >> 4) & 0x3F]; *outp++ = base64[(bs->bs_bits << 2) & 0x3F]; outlen = 3; } bs->bs_offs = 0; bs->bs_bits = 0; return (outlen); } static int b64dec(bs, inp, inlen, outp) struct b64state *bs; u_char *inp; int inlen; u_char *outp; { int outlen = 0; char *cp; while (inlen > 0) { if ((cp = strchr(base64, *inp++)) == NULL) break; bs->bs_bits = (bs->bs_bits << 6) | (cp - base64); inlen--; bs->bs_offs += 6; if (bs->bs_offs >= 8) { *outp++ = bs->bs_bits >> (bs->bs_offs - 8); outlen++; bs->bs_offs -= 8; } } return (outlen); } #endif /* USE_SRP */ #if PPP_SERVER /* * Assume that current waiting server state is complete and figure * next state to use based on available authentication data. 'status' * indicates if there was an error in handling the last query. It is * 0 for success and non-zero for failure. */ static void eap_figure_next_state(ppp_pcb *pcb, int status) { #ifdef USE_SRP unsigned char secbuf[MAXWORDLEN], clear[8], *sp, *dp; struct t_pw tpw; struct t_confent *tce, mytce; char *cp, *cp2; struct t_server *ts; int id, i, plen, toffs; u_char vals[2]; struct b64state bs; #endif /* USE_SRP */ pcb->settings.eap_timeout_time = pcb->eap.es_savedtime; switch (pcb->eap.es_server.ea_state) { case eapBadAuth: return; case eapIdentify: #ifdef USE_SRP /* Discard any previous session. */ ts = (struct t_server *)pcb->eap.es_server.ea_session; if (ts != NULL) { t_serverclose(ts); pcb->eap.es_server.ea_session = NULL; pcb->eap.es_server.ea_skey = NULL; } #endif /* USE_SRP */ if (status != 0) { pcb->eap.es_server.ea_state = eapBadAuth; break; } #ifdef USE_SRP /* If we've got a pseudonym, try to decode to real name. */ if (pcb->eap.es_server.ea_peerlen > SRP_PSEUDO_LEN && strncmp(pcb->eap.es_server.ea_peer, SRP_PSEUDO_ID, SRP_PSEUDO_LEN) == 0 && (pcb->eap.es_server.ea_peerlen - SRP_PSEUDO_LEN) * 3 / 4 < sizeof (secbuf)) { BZERO(&bs, sizeof (bs)); plen = b64dec(&bs, pcb->eap.es_server.ea_peer + SRP_PSEUDO_LEN, pcb->eap.es_server.ea_peerlen - SRP_PSEUDO_LEN, secbuf); toffs = 0; for (i = 0; i < 5; i++) { pncrypt_setkey(toffs); toffs -= 86400; /* FIXME: if we want to do SRP, we need to find a way to pass the PolarSSL des_context instead of using static memory */ if (!DesDecrypt(secbuf, clear)) { ppp_dbglog("no DES here; cannot decode " "pseudonym"); return; } id = *(unsigned char *)clear; if (id + 1 <= plen && id + 9 > plen) break; } if (plen % 8 == 0 && i < 5) { /* * Note that this is always shorter than the * original stored string, so there's no need * to realloc. */ if ((i = plen = *(unsigned char *)clear) > 7) i = 7; pcb->eap.es_server.ea_peerlen = plen; dp = (unsigned char *)pcb->eap.es_server.ea_peer; MEMCPY(dp, clear + 1, i); plen -= i; dp += i; sp = secbuf + 8; while (plen > 0) { /* FIXME: if we want to do SRP, we need to find a way to pass the PolarSSL des_context instead of using static memory */ (void) DesDecrypt(sp, dp); sp += 8; dp += 8; plen -= 8; } pcb->eap.es_server.ea_peer[ pcb->eap.es_server.ea_peerlen] = '\0'; ppp_dbglog("decoded pseudonym to \"%.*q\"", pcb->eap.es_server.ea_peerlen, pcb->eap.es_server.ea_peer); } else { ppp_dbglog("failed to decode real name"); /* Stay in eapIdentfy state; requery */ break; } } /* Look up user in secrets database. */ if (get_srp_secret(pcb->eap.es_unit, pcb->eap.es_server.ea_peer, pcb->eap.es_server.ea_name, (char *)secbuf, 1) != 0) { /* Set up default in case SRP entry is bad */ pcb->eap.es_server.ea_state = eapMD5Chall; /* Get t_confent based on index in srp-secrets */ id = strtol((char *)secbuf, &cp, 10); if (*cp++ != ':' || id < 0) break; if (id == 0) { mytce.index = 0; mytce.modulus.data = (u_char *)wkmodulus; mytce.modulus.len = sizeof (wkmodulus); mytce.generator.data = (u_char *)"\002"; mytce.generator.len = 1; tce = &mytce; } else if ((tce = gettcid(id)) != NULL) { /* * Client will have to verify this modulus/ * generator combination, and that will take * a while. Lengthen the timeout here. */ if (pcb->settings.eap_timeout_time > 0 && pcb->settings.eap_timeout_time < 30) pcb->settings.eap_timeout_time = 30; } else { break; } if ((cp2 = strchr(cp, ':')) == NULL) break; *cp2++ = '\0'; tpw.pebuf.name = pcb->eap.es_server.ea_peer; tpw.pebuf.password.len = t_fromb64((char *)tpw.pwbuf, cp); tpw.pebuf.password.data = tpw.pwbuf; tpw.pebuf.salt.len = t_fromb64((char *)tpw.saltbuf, cp2); tpw.pebuf.salt.data = tpw.saltbuf; if ((ts = t_serveropenraw(&tpw.pebuf, tce)) == NULL) break; pcb->eap.es_server.ea_session = (void *)ts; pcb->eap.es_server.ea_state = eapSRP1; vals[0] = pcb->eap.es_server.ea_id + 1; vals[1] = EAPT_SRP; t_serveraddexdata(ts, vals, 2); /* Generate B; must call before t_servergetkey() */ t_servergenexp(ts); break; } #endif /* USE_SRP */ pcb->eap.es_server.ea_state = eapMD5Chall; break; case eapSRP1: #ifdef USE_SRP ts = (struct t_server *)pcb->eap.es_server.ea_session; if (ts != NULL && status != 0) { t_serverclose(ts); pcb->eap.es_server.ea_session = NULL; pcb->eap.es_server.ea_skey = NULL; } #endif /* USE_SRP */ if (status == 1) { pcb->eap.es_server.ea_state = eapMD5Chall; } else if (status != 0 || pcb->eap.es_server.ea_session == NULL) { pcb->eap.es_server.ea_state = eapBadAuth; } else { pcb->eap.es_server.ea_state = eapSRP2; } break; case eapSRP2: #ifdef USE_SRP ts = (struct t_server *)pcb->eap.es_server.ea_session; if (ts != NULL && status != 0) { t_serverclose(ts); pcb->eap.es_server.ea_session = NULL; pcb->eap.es_server.ea_skey = NULL; } #endif /* USE_SRP */ if (status != 0 || pcb->eap.es_server.ea_session == NULL) { pcb->eap.es_server.ea_state = eapBadAuth; } else { pcb->eap.es_server.ea_state = eapSRP3; } break; case eapSRP3: case eapSRP4: #ifdef USE_SRP ts = (struct t_server *)pcb->eap.es_server.ea_session; if (ts != NULL && status != 0) { t_serverclose(ts); pcb->eap.es_server.ea_session = NULL; pcb->eap.es_server.ea_skey = NULL; } #endif /* USE_SRP */ if (status != 0 || pcb->eap.es_server.ea_session == NULL) { pcb->eap.es_server.ea_state = eapBadAuth; } else { pcb->eap.es_server.ea_state = eapOpen; } break; case eapMD5Chall: if (status != 0) { pcb->eap.es_server.ea_state = eapBadAuth; } else { pcb->eap.es_server.ea_state = eapOpen; } break; default: pcb->eap.es_server.ea_state = eapBadAuth; break; } if (pcb->eap.es_server.ea_state == eapBadAuth) eap_send_failure(pcb); } /* * Format an EAP Request message and send it to the peer. Message * type depends on current state. (Server operation) */ static void eap_send_request(ppp_pcb *pcb) { struct pbuf *p; u_char *outp; u_char *lenloc; u_char *ptr; int outlen; int challen; char *str; #ifdef USE_SRP struct t_server *ts; u_char clear[8], cipher[8], dig[SHA_DIGESTSIZE], *optr, *cp; int i, j; struct b64state b64; SHA1_CTX ctxt; #endif /* USE_SRP */ /* Handle both initial auth and restart */ if (pcb->eap.es_server.ea_state < eapIdentify && pcb->eap.es_server.ea_state != eapInitial) { pcb->eap.es_server.ea_state = eapIdentify; #if PPP_REMOTENAME if (pcb->settings.explicit_remote) { /* * If we already know the peer's * unauthenticated name, then there's no * reason to ask. Go to next state instead. */ pcb->eap.es_server.ea_peer = pcb->remote_name; pcb->eap.es_server.ea_peerlen = strlen(pcb->remote_name); eap_figure_next_state(pcb, 0); } #endif /* PPP_REMOTENAME */ } if (pcb->settings.eap_max_transmits > 0 && pcb->eap.es_server.ea_requests >= pcb->settings.eap_max_transmits) { if (pcb->eap.es_server.ea_responses > 0) ppp_error("EAP: too many Requests sent"); else ppp_error("EAP: no response to Requests"); eap_send_failure(pcb); return; } p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_CTRL_PBUF_MAX_SIZE), PPP_CTRL_PBUF_TYPE); if(NULL == p) return; if(p->tot_len != p->len) { pbuf_free(p); return; } outp = p->payload; MAKEHEADER(outp, PPP_EAP); PUTCHAR(EAP_REQUEST, outp); PUTCHAR(pcb->eap.es_server.ea_id, outp); lenloc = outp; INCPTR(2, outp); switch (pcb->eap.es_server.ea_state) { case eapIdentify: PUTCHAR(EAPT_IDENTITY, outp); str = "Name"; challen = strlen(str); MEMCPY(outp, str, challen); INCPTR(challen, outp); break; case eapMD5Chall: PUTCHAR(EAPT_MD5CHAP, outp); /* * pick a random challenge length between * EAP_MIN_CHALLENGE_LENGTH and EAP_MAX_CHALLENGE_LENGTH */ challen = (drand48() * (EAP_MAX_CHALLENGE_LENGTH - EAP_MIN_CHALLENGE_LENGTH)) + EAP_MIN_CHALLENGE_LENGTH; PUTCHAR(challen, outp); pcb->eap.es_challen = challen; ptr = pcb->eap.es_challenge; while (--challen >= 0) *ptr++ = (u_char) (drand48() * 0x100); MEMCPY(outp, pcb->eap.es_challenge, pcb->eap.es_challen); INCPTR(pcb->eap.es_challen, outp); MEMCPY(outp, pcb->eap.es_server.ea_name, pcb->eap.es_server.ea_namelen); INCPTR(pcb->eap.es_server.ea_namelen, outp); break; #ifdef USE_SRP case eapSRP1: PUTCHAR(EAPT_SRP, outp); PUTCHAR(EAPSRP_CHALLENGE, outp); PUTCHAR(pcb->eap.es_server.ea_namelen, outp); MEMCPY(outp, pcb->eap.es_server.ea_name, pcb->eap.es_server.ea_namelen); INCPTR(pcb->eap.es_server.ea_namelen, outp); ts = (struct t_server *)pcb->eap.es_server.ea_session; assert(ts != NULL); PUTCHAR(ts->s.len, outp); MEMCPY(outp, ts->s.data, ts->s.len); INCPTR(ts->s.len, outp); if (ts->g.len == 1 && ts->g.data[0] == 2) { PUTCHAR(0, outp); } else { PUTCHAR(ts->g.len, outp); MEMCPY(outp, ts->g.data, ts->g.len); INCPTR(ts->g.len, outp); } if (ts->n.len != sizeof (wkmodulus) || BCMP(ts->n.data, wkmodulus, sizeof (wkmodulus)) != 0) { MEMCPY(outp, ts->n.data, ts->n.len); INCPTR(ts->n.len, outp); } break; case eapSRP2: PUTCHAR(EAPT_SRP, outp); PUTCHAR(EAPSRP_SKEY, outp); ts = (struct t_server *)pcb->eap.es_server.ea_session; assert(ts != NULL); MEMCPY(outp, ts->B.data, ts->B.len); INCPTR(ts->B.len, outp); break; case eapSRP3: PUTCHAR(EAPT_SRP, outp); PUTCHAR(EAPSRP_SVALIDATOR, outp); PUTLONG(SRPVAL_EBIT, outp); ts = (struct t_server *)pcb->eap.es_server.ea_session; assert(ts != NULL); MEMCPY(outp, t_serverresponse(ts), SHA_DIGESTSIZE); INCPTR(SHA_DIGESTSIZE, outp); if (pncrypt_setkey(0)) { /* Generate pseudonym */ optr = outp; cp = (unsigned char *)pcb->eap.es_server.ea_peer; if ((j = i = pcb->eap.es_server.ea_peerlen) > 7) j = 7; clear[0] = i; MEMCPY(clear + 1, cp, j); i -= j; cp += j; /* FIXME: if we want to do SRP, we need to find a way to pass the PolarSSL des_context instead of using static memory */ if (!DesEncrypt(clear, cipher)) { ppp_dbglog("no DES here; not generating pseudonym"); break; } BZERO(&b64, sizeof (b64)); outp++; /* space for pseudonym length */ outp += b64enc(&b64, cipher, 8, outp); while (i >= 8) { /* FIXME: if we want to do SRP, we need to find a way to pass the PolarSSL des_context instead of using static memory */ (void) DesEncrypt(cp, cipher); outp += b64enc(&b64, cipher, 8, outp); cp += 8; i -= 8; } if (i > 0) { MEMCPY(clear, cp, i); cp += i; while (i < 8) { *cp++ = drand48() * 0x100; i++; } /* FIXME: if we want to do SRP, we need to find a way to pass the PolarSSL des_context instead of using static memory */ (void) DesEncrypt(clear, cipher); outp += b64enc(&b64, cipher, 8, outp); } outp += b64flush(&b64, outp); /* Set length and pad out to next 20 octet boundary */ i = outp - optr - 1; *optr = i; i %= SHA_DIGESTSIZE; if (i != 0) { while (i < SHA_DIGESTSIZE) { *outp++ = drand48() * 0x100; i++; } } /* Obscure the pseudonym with SHA1 hash */ SHA1Init(&ctxt); SHA1Update(&ctxt, &pcb->eap.es_server.ea_id, 1); SHA1Update(&ctxt, pcb->eap.es_server.ea_skey, SESSION_KEY_LEN); SHA1Update(&ctxt, pcb->eap.es_server.ea_peer, pcb->eap.es_server.ea_peerlen); while (optr < outp) { SHA1Final(dig, &ctxt); cp = dig; while (cp < dig + SHA_DIGESTSIZE) *optr++ ^= *cp++; SHA1Init(&ctxt); SHA1Update(&ctxt, &pcb->eap.es_server.ea_id, 1); SHA1Update(&ctxt, pcb->eap.es_server.ea_skey, SESSION_KEY_LEN); SHA1Update(&ctxt, optr - SHA_DIGESTSIZE, SHA_DIGESTSIZE); } } break; case eapSRP4: PUTCHAR(EAPT_SRP, outp); PUTCHAR(EAPSRP_LWRECHALLENGE, outp); challen = EAP_MIN_CHALLENGE_LENGTH + ((EAP_MAX_CHALLENGE_LENGTH - EAP_MIN_CHALLENGE_LENGTH) * drand48()); pcb->eap.es_challen = challen; ptr = pcb->eap.es_challenge; while (--challen >= 0) *ptr++ = drand48() * 0x100; MEMCPY(outp, pcb->eap.es_challenge, pcb->eap.es_challen); INCPTR(pcb->eap.es_challen, outp); break; #endif /* USE_SRP */ default: return; } outlen = (outp - (unsigned char*)p->payload) - PPP_HDRLEN; PUTSHORT(outlen, lenloc); pbuf_realloc(p, outlen + PPP_HDRLEN); ppp_write(pcb, p); pcb->eap.es_server.ea_requests++; if (pcb->settings.eap_timeout_time > 0) TIMEOUT(eap_server_timeout, pcb, pcb->settings.eap_timeout_time); } /* * eap_authpeer - Authenticate our peer (behave as server). * * Start server state and send first request. This is called only * after eap_lowerup. */ void eap_authpeer(ppp_pcb *pcb, char *localname) { /* Save the name we're given. */ pcb->eap.es_server.ea_name = localname; pcb->eap.es_server.ea_namelen = strlen(localname); pcb->eap.es_savedtime = pcb->settings.eap_timeout_time; /* Lower layer up yet? */ if (pcb->eap.es_server.ea_state == eapInitial || pcb->eap.es_server.ea_state == eapPending) { pcb->eap.es_server.ea_state = eapPending; return; } pcb->eap.es_server.ea_state = eapPending; /* ID number not updated here intentionally; hashed into M1 */ eap_send_request(pcb); } /* * eap_server_timeout - Retransmission timer for sending Requests * expired. */ static void eap_server_timeout(void *arg) { ppp_pcb *pcb = (ppp_pcb*)arg; if (!eap_server_active(pcb)) return; /* EAP ID number must not change on timeout. */ eap_send_request(pcb); } /* * When it's time to send rechallenge the peer, this timeout is * called. Once the rechallenge is successful, the response handler * will restart the timer. If it fails, then the link is dropped. */ static void eap_rechallenge(void *arg) { ppp_pcb *pcb = (ppp_pcb*)arg; if (pcb->eap.es_server.ea_state != eapOpen && pcb->eap.es_server.ea_state != eapSRP4) return; pcb->eap.es_server.ea_requests = 0; pcb->eap.es_server.ea_state = eapIdentify; eap_figure_next_state(pcb, 0); pcb->eap.es_server.ea_id++; eap_send_request(pcb); } static void srp_lwrechallenge(void *arg) { ppp_pcb *pcb = (ppp_pcb*)arg; if (pcb->eap.es_server.ea_state != eapOpen || pcb->eap.es_server.ea_type != EAPT_SRP) return; pcb->eap.es_server.ea_requests = 0; pcb->eap.es_server.ea_state = eapSRP4; pcb->eap.es_server.ea_id++; eap_send_request(pcb); } #endif /* PPP_SERVER */ /* * eap_lowerup - The lower layer is now up. * * This is called before either eap_authpeer or eap_authwithpeer. See * link_established() in auth.c. All that's necessary here is to * return to closed state so that those two routines will do the right * thing. */ static void eap_lowerup(ppp_pcb *pcb) { /* Discard any (possibly authenticated) peer name. */ #if PPP_SERVER if (pcb->eap.es_server.ea_peer != NULL #if PPP_REMOTENAME && pcb->eap.es_server.ea_peer != pcb->remote_name #endif /* PPP_REMOTENAME */ ) free(pcb->eap.es_server.ea_peer); pcb->eap.es_server.ea_peer = NULL; #endif /* PPP_SERVER */ if (pcb->eap.es_client.ea_peer != NULL) free(pcb->eap.es_client.ea_peer); pcb->eap.es_client.ea_peer = NULL; pcb->eap.es_client.ea_state = eapClosed; #if PPP_SERVER pcb->eap.es_server.ea_state = eapClosed; #endif /* PPP_SERVER */ } /* * eap_lowerdown - The lower layer is now down. * * Cancel all timeouts and return to initial state. */ static void eap_lowerdown(ppp_pcb *pcb) { if (eap_client_active(pcb) && pcb->settings.eap_req_time > 0) { UNTIMEOUT(eap_client_timeout, pcb); } #if PPP_SERVER if (eap_server_active(pcb)) { if (pcb->settings.eap_timeout_time > 0) { UNTIMEOUT(eap_server_timeout, pcb); } } else { if ((pcb->eap.es_server.ea_state == eapOpen || pcb->eap.es_server.ea_state == eapSRP4) && pcb->eap.es_rechallenge > 0) { UNTIMEOUT(eap_rechallenge, (void *)pcb); } if (pcb->eap.es_server.ea_state == eapOpen && pcb->eap.es_lwrechallenge > 0) { UNTIMEOUT(srp_lwrechallenge, (void *)pcb); } } pcb->eap.es_client.ea_state = pcb->eap.es_server.ea_state = eapInitial; pcb->eap.es_client.ea_requests = pcb->eap.es_server.ea_requests = 0; #endif /* PPP_SERVER */ } /* * eap_protrej - Peer doesn't speak this protocol. * * This shouldn't happen. If it does, it represents authentication * failure. */ static void eap_protrej(ppp_pcb *pcb) { if (eap_client_active(pcb)) { ppp_error("EAP authentication failed due to Protocol-Reject"); auth_withpeer_fail(pcb, PPP_EAP); } #if PPP_SERVER if (eap_server_active(pcb)) { ppp_error("EAP authentication of peer failed on Protocol-Reject"); auth_peer_fail(pcb, PPP_EAP); } #endif /* PPP_SERVER */ eap_lowerdown(pcb); } /* * Format and send a regular EAP Response message. */ static void eap_send_response(ppp_pcb *pcb, u_char id, u_char typenum, u_char *str, int lenstr) { struct pbuf *p; u_char *outp; int msglen; msglen = EAP_HEADERLEN + sizeof (u_char) + lenstr; p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_HDRLEN + msglen), PPP_CTRL_PBUF_TYPE); if(NULL == p) return; if(p->tot_len != p->len) { pbuf_free(p); return; } outp = p->payload; MAKEHEADER(outp, PPP_EAP); PUTCHAR(EAP_RESPONSE, outp); PUTCHAR(id, outp); pcb->eap.es_client.ea_id = id; PUTSHORT(msglen, outp); PUTCHAR(typenum, outp); if (lenstr > 0) { MEMCPY(outp, str, lenstr); } ppp_write(pcb, p); } /* * Format and send an MD5-Challenge EAP Response message. */ static void eap_chap_response(ppp_pcb *pcb, u_char id, u_char *hash, char *name, int namelen) { struct pbuf *p; u_char *outp; int msglen; msglen = EAP_HEADERLEN + 2 * sizeof (u_char) + MD5_SIGNATURE_SIZE + namelen; p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_HDRLEN + msglen), PPP_CTRL_PBUF_TYPE); if(NULL == p) return; if(p->tot_len != p->len) { pbuf_free(p); return; } outp = p->payload; MAKEHEADER(outp, PPP_EAP); PUTCHAR(EAP_RESPONSE, outp); PUTCHAR(id, outp); pcb->eap.es_client.ea_id = id; PUTSHORT(msglen, outp); PUTCHAR(EAPT_MD5CHAP, outp); PUTCHAR(MD5_SIGNATURE_SIZE, outp); MEMCPY(outp, hash, MD5_SIGNATURE_SIZE); INCPTR(MD5_SIGNATURE_SIZE, outp); if (namelen > 0) { MEMCPY(outp, name, namelen); } ppp_write(pcb, p); } #ifdef USE_SRP /* * Format and send a SRP EAP Response message. */ static void eap_srp_response(esp, id, subtypenum, str, lenstr) eap_state *esp; u_char id; u_char subtypenum; u_char *str; int lenstr; { ppp_pcb *pcb = &ppp_pcb_list[pcb->eap.es_unit]; struct pbuf *p; u_char *outp; int msglen; msglen = EAP_HEADERLEN + 2 * sizeof (u_char) + lenstr; p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_HDRLEN + msglen), PPP_CTRL_PBUF_TYPE); if(NULL == p) return; if(p->tot_len != p->len) { pbuf_free(p); return; } outp = p->payload; MAKEHEADER(outp, PPP_EAP); PUTCHAR(EAP_RESPONSE, outp); PUTCHAR(id, outp); pcb->eap.es_client.ea_id = id; PUTSHORT(msglen, outp); PUTCHAR(EAPT_SRP, outp); PUTCHAR(subtypenum, outp); if (lenstr > 0) { MEMCPY(outp, str, lenstr); } ppp_write(pcb, p); } /* * Format and send a SRP EAP Client Validator Response message. */ static void eap_srpval_response(esp, id, flags, str) eap_state *esp; u_char id; u32_t flags; u_char *str; { ppp_pcb *pcb = &ppp_pcb_list[pcb->eap.es_unit]; struct pbuf *p; u_char *outp; int msglen; msglen = EAP_HEADERLEN + 2 * sizeof (u_char) + sizeof (u32_t) + SHA_DIGESTSIZE; p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_HDRLEN + msglen), PPP_CTRL_PBUF_TYPE); if(NULL == p) return; if(p->tot_len != p->len) { pbuf_free(p); return; } outp = p->payload; MAKEHEADER(outp, PPP_EAP); PUTCHAR(EAP_RESPONSE, outp); PUTCHAR(id, outp); pcb->eap.es_client.ea_id = id; PUTSHORT(msglen, outp); PUTCHAR(EAPT_SRP, outp); PUTCHAR(EAPSRP_CVALIDATOR, outp); PUTLONG(flags, outp); MEMCPY(outp, str, SHA_DIGESTSIZE); ppp_write(pcb, p); } #endif /* USE_SRP */ static void eap_send_nak(ppp_pcb *pcb, u_char id, u_char type) { struct pbuf *p; u_char *outp; int msglen; msglen = EAP_HEADERLEN + 2 * sizeof (u_char); p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_HDRLEN + msglen), PPP_CTRL_PBUF_TYPE); if(NULL == p) return; if(p->tot_len != p->len) { pbuf_free(p); return; } outp = p->payload; MAKEHEADER(outp, PPP_EAP); PUTCHAR(EAP_RESPONSE, outp); PUTCHAR(id, outp); pcb->eap.es_client.ea_id = id; PUTSHORT(msglen, outp); PUTCHAR(EAPT_NAK, outp); PUTCHAR(type, outp); ppp_write(pcb, p); } #ifdef USE_SRP static char * name_of_pn_file() { char *user, *path, *file; struct passwd *pw; size_t pl; static bool pnlogged = 0; pw = getpwuid(getuid()); if (pw == NULL || (user = pw->pw_dir) == NULL || user[0] == 0) { errno = EINVAL; return (NULL); } file = _PATH_PSEUDONYM; pl = strlen(user) + strlen(file) + 2; path = malloc(pl); if (path == NULL) return (NULL); (void) slprintf(path, pl, "%s/%s", user, file); if (!pnlogged) { ppp_dbglog("pseudonym file: %s", path); pnlogged = 1; } return (path); } static int open_pn_file(modebits) mode_t modebits; { char *path; int fd, err; if ((path = name_of_pn_file()) == NULL) return (-1); fd = open(path, modebits, S_IRUSR | S_IWUSR); err = errno; free(path); errno = err; return (fd); } static void remove_pn_file() { char *path; if ((path = name_of_pn_file()) != NULL) { (void) unlink(path); (void) free(path); } } static void write_pseudonym(esp, inp, len, id) eap_state *esp; u_char *inp; int len, id; { u_char val; u_char *datp, *digp; SHA1_CTX ctxt; u_char dig[SHA_DIGESTSIZE]; int dsize, fd, olen = len; /* * Do the decoding by working backwards. This eliminates the need * to save the decoded output in a separate buffer. */ val = id; while (len > 0) { if ((dsize = len % SHA_DIGESTSIZE) == 0) dsize = SHA_DIGESTSIZE; len -= dsize; datp = inp + len; SHA1Init(&ctxt); SHA1Update(&ctxt, &val, 1); SHA1Update(&ctxt, pcb->eap.es_client.ea_skey, SESSION_KEY_LEN); if (len > 0) { SHA1Update(&ctxt, datp, SHA_DIGESTSIZE); } else { SHA1Update(&ctxt, pcb->eap.es_client.ea_name, pcb->eap.es_client.ea_namelen); } SHA1Final(dig, &ctxt); for (digp = dig; digp < dig + SHA_DIGESTSIZE; digp++) *datp++ ^= *digp; } /* Now check that the result is sane */ if (olen <= 0 || *inp + 1 > olen) { ppp_dbglog("EAP: decoded pseudonym is unusable <%.*B>", olen, inp); return; } /* Save it away */ fd = open_pn_file(O_WRONLY | O_CREAT | O_TRUNC); if (fd < 0) { ppp_dbglog("EAP: error saving pseudonym: %m"); return; } len = write(fd, inp + 1, *inp); if (close(fd) != -1 && len == *inp) { ppp_dbglog("EAP: saved pseudonym"); pcb->eap.es_usedpseudo = 0; } else { ppp_dbglog("EAP: failed to save pseudonym"); remove_pn_file(); } } #endif /* USE_SRP */ /* * eap_request - Receive EAP Request message (client mode). */ static void eap_request(ppp_pcb *pcb, u_char *inp, int id, int len) { u_char typenum; u_char vallen; int secret_len; char secret[MAXWORDLEN]; char rhostname[256]; md5_context mdContext; u_char hash[MD5_SIGNATURE_SIZE]; #ifdef USE_SRP struct t_client *tc; struct t_num sval, gval, Nval, *Ap, Bval; u_char vals[2]; SHA1_CTX ctxt; u_char dig[SHA_DIGESTSIZE]; int fd; #endif /* USE_SRP */ /* * Note: we update es_client.ea_id *only if* a Response * message is being generated. Otherwise, we leave it the * same for duplicate detection purposes. */ pcb->eap.es_client.ea_requests++; if (pcb->settings.eap_allow_req != 0 && pcb->eap.es_client.ea_requests > pcb->settings.eap_allow_req) { ppp_info("EAP: received too many Request messages"); if (pcb->settings.eap_req_time > 0) { UNTIMEOUT(eap_client_timeout, pcb); } auth_withpeer_fail(pcb, PPP_EAP); return; } if (len <= 0) { ppp_error("EAP: empty Request message discarded"); return; } GETCHAR(typenum, inp); len--; switch (typenum) { case EAPT_IDENTITY: if (len > 0) ppp_info("EAP: Identity prompt \"%.*q\"", len, inp); #ifdef USE_SRP if (pcb->eap.es_usepseudo && (pcb->eap.es_usedpseudo == 0 || (pcb->eap.es_usedpseudo == 1 && id == pcb->eap.es_client.ea_id))) { pcb->eap.es_usedpseudo = 1; /* Try to get a pseudonym */ if ((fd = open_pn_file(O_RDONLY)) >= 0) { strcpy(rhostname, SRP_PSEUDO_ID); len = read(fd, rhostname + SRP_PSEUDO_LEN, sizeof (rhostname) - SRP_PSEUDO_LEN); /* XXX NAI unsupported */ if (len > 0) { eap_send_response(pcb, id, typenum, rhostname, len + SRP_PSEUDO_LEN); } (void) close(fd); if (len > 0) break; } } /* Stop using pseudonym now. */ if (pcb->eap.es_usepseudo && pcb->eap.es_usedpseudo != 2) { remove_pn_file(); pcb->eap.es_usedpseudo = 2; } #endif /* USE_SRP */ eap_send_response(pcb, id, typenum, (u_char*)pcb->eap.es_client.ea_name, pcb->eap.es_client.ea_namelen); break; case EAPT_NOTIFICATION: if (len > 0) ppp_info("EAP: Notification \"%.*q\"", len, inp); eap_send_response(pcb, id, typenum, NULL, 0); break; case EAPT_NAK: /* * Avoid the temptation to send Response Nak in reply * to Request Nak here. It can only lead to trouble. */ ppp_warn("EAP: unexpected Nak in Request; ignored"); /* Return because we're waiting for something real. */ return; case EAPT_MD5CHAP: if (len < 1) { ppp_error("EAP: received MD5-Challenge with no data"); /* Bogus request; wait for something real. */ return; } GETCHAR(vallen, inp); len--; if (vallen < 8 || vallen > len) { ppp_error("EAP: MD5-Challenge with bad length %d (8..%d)", vallen, len); /* Try something better. */ eap_send_nak(pcb, id, EAPT_SRP); break; } /* Not so likely to happen. */ if (vallen >= len + sizeof (rhostname)) { ppp_dbglog("EAP: trimming really long peer name down"); MEMCPY(rhostname, inp + vallen, sizeof (rhostname) - 1); rhostname[sizeof (rhostname) - 1] = '\0'; } else { MEMCPY(rhostname, inp + vallen, len - vallen); rhostname[len - vallen] = '\0'; } #if PPP_REMOTENAME /* In case the remote doesn't give us his name. */ if (pcb->settings.explicit_remote || (pcb->settings.remote_name[0] != '\0' && vallen == len)) strlcpy(rhostname, pcb->settings.remote_name, sizeof (rhostname)); #endif /* PPP_REMOTENAME */ /* * Get the secret for authenticating ourselves with * the specified host. */ if (!get_secret(pcb, pcb->eap.es_client.ea_name, rhostname, secret, &secret_len, 0)) { ppp_dbglog("EAP: no MD5 secret for auth to %q", rhostname); eap_send_nak(pcb, id, EAPT_SRP); break; } md5_starts(&mdContext); typenum = id; md5_update(&mdContext, &typenum, 1); md5_update(&mdContext, (u_char *)secret, secret_len); BZERO(secret, sizeof (secret)); md5_update(&mdContext, inp, vallen); md5_finish(&mdContext, hash); eap_chap_response(pcb, id, hash, pcb->eap.es_client.ea_name, pcb->eap.es_client.ea_namelen); break; #ifdef USE_SRP case EAPT_SRP: if (len < 1) { ppp_error("EAP: received empty SRP Request"); /* Bogus request; wait for something real. */ return; } /* Get subtype */ GETCHAR(vallen, inp); len--; switch (vallen) { case EAPSRP_CHALLENGE: tc = NULL; if (pcb->eap.es_client.ea_session != NULL) { tc = (struct t_client *)pcb->eap.es_client. ea_session; /* * If this is a new challenge, then start * over with a new client session context. * Otherwise, just resend last response. */ if (id != pcb->eap.es_client.ea_id) { t_clientclose(tc); pcb->eap.es_client.ea_session = NULL; tc = NULL; } } /* No session key just yet */ pcb->eap.es_client.ea_skey = NULL; if (tc == NULL) { GETCHAR(vallen, inp); len--; if (vallen >= len) { ppp_error("EAP: badly-formed SRP Challenge" " (name)"); /* Ignore badly-formed messages */ return; } MEMCPY(rhostname, inp, vallen); rhostname[vallen] = '\0'; INCPTR(vallen, inp); len -= vallen; /* * In case the remote doesn't give us his name, * use configured name. */ if (explicit_remote || (remote_name[0] != '\0' && vallen == 0)) { strlcpy(rhostname, remote_name, sizeof (rhostname)); } if (pcb->eap.es_client.ea_peer != NULL) free(pcb->eap.es_client.ea_peer); pcb->eap.es_client.ea_peer = strdup(rhostname); pcb->eap.es_client.ea_peerlen = strlen(rhostname); GETCHAR(vallen, inp); len--; if (vallen >= len) { ppp_error("EAP: badly-formed SRP Challenge" " (s)"); /* Ignore badly-formed messages */ return; } sval.data = inp; sval.len = vallen; INCPTR(vallen, inp); len -= vallen; GETCHAR(vallen, inp); len--; if (vallen > len) { ppp_error("EAP: badly-formed SRP Challenge" " (g)"); /* Ignore badly-formed messages */ return; } /* If no generator present, then use value 2 */ if (vallen == 0) { gval.data = (u_char *)"\002"; gval.len = 1; } else { gval.data = inp; gval.len = vallen; } INCPTR(vallen, inp); len -= vallen; /* * If no modulus present, then use well-known * value. */ if (len == 0) { Nval.data = (u_char *)wkmodulus; Nval.len = sizeof (wkmodulus); } else { Nval.data = inp; Nval.len = len; } tc = t_clientopen(pcb->eap.es_client.ea_name, &Nval, &gval, &sval); if (tc == NULL) { eap_send_nak(pcb, id, EAPT_MD5CHAP); break; } pcb->eap.es_client.ea_session = (void *)tc; /* Add Challenge ID & type to verifier */ vals[0] = id; vals[1] = EAPT_SRP; t_clientaddexdata(tc, vals, 2); } Ap = t_clientgenexp(tc); eap_srp_response(esp, id, EAPSRP_CKEY, Ap->data, Ap->len); break; case EAPSRP_SKEY: tc = (struct t_client *)pcb->eap.es_client.ea_session; if (tc == NULL) { ppp_warn("EAP: peer sent Subtype 2 without 1"); eap_send_nak(pcb, id, EAPT_MD5CHAP); break; } if (pcb->eap.es_client.ea_skey != NULL) { /* * ID number should not change here. Warn * if it does (but otherwise ignore). */ if (id != pcb->eap.es_client.ea_id) { ppp_warn("EAP: ID changed from %d to %d " "in SRP Subtype 2 rexmit", pcb->eap.es_client.ea_id, id); } } else { if (get_srp_secret(pcb->eap.es_unit, pcb->eap.es_client.ea_name, pcb->eap.es_client.ea_peer, secret, 0) == 0) { /* * Can't work with this peer because * the secret is missing. Just give * up. */ eap_send_nak(pcb, id, EAPT_MD5CHAP); break; } Bval.data = inp; Bval.len = len; t_clientpasswd(tc, secret); BZERO(secret, sizeof (secret)); pcb->eap.es_client.ea_skey = t_clientgetkey(tc, &Bval); if (pcb->eap.es_client.ea_skey == NULL) { /* Server is rogue; stop now */ ppp_error("EAP: SRP server is rogue"); goto client_failure; } } eap_srpval_response(esp, id, SRPVAL_EBIT, t_clientresponse(tc)); break; case EAPSRP_SVALIDATOR: tc = (struct t_client *)pcb->eap.es_client.ea_session; if (tc == NULL || pcb->eap.es_client.ea_skey == NULL) { ppp_warn("EAP: peer sent Subtype 3 without 1/2"); eap_send_nak(pcb, id, EAPT_MD5CHAP); break; } /* * If we're already open, then this ought to be a * duplicate. Otherwise, check that the server is * who we think it is. */ if (pcb->eap.es_client.ea_state == eapOpen) { if (id != pcb->eap.es_client.ea_id) { ppp_warn("EAP: ID changed from %d to %d " "in SRP Subtype 3 rexmit", pcb->eap.es_client.ea_id, id); } } else { len -= sizeof (u32_t) + SHA_DIGESTSIZE; if (len < 0 || t_clientverify(tc, inp + sizeof (u32_t)) != 0) { ppp_error("EAP: SRP server verification " "failed"); goto client_failure; } GETLONG(pcb->eap.es_client.ea_keyflags, inp); /* Save pseudonym if user wants it. */ if (len > 0 && pcb->eap.es_usepseudo) { INCPTR(SHA_DIGESTSIZE, inp); write_pseudonym(esp, inp, len, id); } } /* * We've verified our peer. We're now mostly done, * except for waiting on the regular EAP Success * message. */ eap_srp_response(esp, id, EAPSRP_ACK, NULL, 0); break; case EAPSRP_LWRECHALLENGE: if (len < 4) { ppp_warn("EAP: malformed Lightweight rechallenge"); return; } SHA1Init(&ctxt); vals[0] = id; SHA1Update(&ctxt, vals, 1); SHA1Update(&ctxt, pcb->eap.es_client.ea_skey, SESSION_KEY_LEN); SHA1Update(&ctxt, inp, len); SHA1Update(&ctxt, pcb->eap.es_client.ea_name, pcb->eap.es_client.ea_namelen); SHA1Final(dig, &ctxt); eap_srp_response(esp, id, EAPSRP_LWRECHALLENGE, dig, SHA_DIGESTSIZE); break; default: ppp_error("EAP: unknown SRP Subtype %d", vallen); eap_send_nak(pcb, id, EAPT_MD5CHAP); break; } break; #endif /* USE_SRP */ default: ppp_info("EAP: unknown authentication type %d; Naking", typenum); eap_send_nak(pcb, id, EAPT_SRP); break; } if (pcb->settings.eap_req_time > 0) { UNTIMEOUT(eap_client_timeout, pcb); TIMEOUT(eap_client_timeout, pcb, pcb->settings.eap_req_time); } return; #ifdef USE_SRP client_failure: pcb->eap.es_client.ea_state = eapBadAuth; if (pcb->settings.eap_req_time > 0) { UNTIMEOUT(eap_client_timeout, (void *)esp); } pcb->eap.es_client.ea_session = NULL; t_clientclose(tc); auth_withpeer_fail(pcb, PPP_EAP); #endif /* USE_SRP */ } #if PPP_SERVER /* FIXME: remove malloc() and free() */ /* * eap_response - Receive EAP Response message (server mode). */ static void eap_response(ppp_pcb *pcb, u_char *inp, int id, int len) { u_char typenum; u_char vallen; int secret_len; char secret[MAXSECRETLEN]; char rhostname[256]; md5_context mdContext; u_char hash[MD5_SIGNATURE_SIZE]; #ifdef USE_SRP struct t_server *ts; struct t_num A; SHA1_CTX ctxt; u_char dig[SHA_DIGESTSIZE]; #endif /* USE_SRP */ if (pcb->eap.es_server.ea_id != id) { ppp_dbglog("EAP: discarding Response %d; expected ID %d", id, pcb->eap.es_server.ea_id); return; } pcb->eap.es_server.ea_responses++; if (len <= 0) { ppp_error("EAP: empty Response message discarded"); return; } GETCHAR(typenum, inp); len--; switch (typenum) { case EAPT_IDENTITY: if (pcb->eap.es_server.ea_state != eapIdentify) { ppp_dbglog("EAP discarding unwanted Identify \"%.q\"", len, inp); break; } ppp_info("EAP: unauthenticated peer name \"%.*q\"", len, inp); if (pcb->eap.es_server.ea_peer != NULL #if PPP_REMOTENAME && pcb->eap.es_server.ea_peer != pcb->remote_name #endif /* PPP_REMOTENAME */ ) free(pcb->eap.es_server.ea_peer); pcb->eap.es_server.ea_peer = malloc(len + 1); if (pcb->eap.es_server.ea_peer == NULL) { pcb->eap.es_server.ea_peerlen = 0; eap_figure_next_state(pcb, 1); break; } MEMCPY(pcb->eap.es_server.ea_peer, inp, len); pcb->eap.es_server.ea_peer[len] = '\0'; pcb->eap.es_server.ea_peerlen = len; eap_figure_next_state(pcb, 0); break; case EAPT_NOTIFICATION: ppp_dbglog("EAP unexpected Notification; response discarded"); break; case EAPT_NAK: if (len < 1) { ppp_info("EAP: Nak Response with no suggested protocol"); eap_figure_next_state(pcb, 1); break; } GETCHAR(vallen, inp); len--; if ( #if PPP_REMOTENAME !pcb->explicit_remote && #endif /* PPP_REMOTENAME */ pcb->eap.es_server.ea_state == eapIdentify){ /* Peer cannot Nak Identify Request */ eap_figure_next_state(pcb, 1); break; } switch (vallen) { case EAPT_SRP: /* Run through SRP validator selection again. */ pcb->eap.es_server.ea_state = eapIdentify; eap_figure_next_state(pcb, 0); break; case EAPT_MD5CHAP: pcb->eap.es_server.ea_state = eapMD5Chall; break; default: ppp_dbglog("EAP: peer requesting unknown Type %d", vallen); switch (pcb->eap.es_server.ea_state) { case eapSRP1: case eapSRP2: case eapSRP3: pcb->eap.es_server.ea_state = eapMD5Chall; break; case eapMD5Chall: case eapSRP4: pcb->eap.es_server.ea_state = eapIdentify; eap_figure_next_state(pcb, 0); break; default: break; } break; } break; case EAPT_MD5CHAP: if (pcb->eap.es_server.ea_state != eapMD5Chall) { ppp_error("EAP: unexpected MD5-Response"); eap_figure_next_state(pcb, 1); break; } if (len < 1) { ppp_error("EAP: received MD5-Response with no data"); eap_figure_next_state(pcb, 1); break; } GETCHAR(vallen, inp); len--; if (vallen != 16 || vallen > len) { ppp_error("EAP: MD5-Response with bad length %d", vallen); eap_figure_next_state(pcb, 1); break; } /* Not so likely to happen. */ if (vallen >= len + sizeof (rhostname)) { ppp_dbglog("EAP: trimming really long peer name down"); MEMCPY(rhostname, inp + vallen, sizeof (rhostname) - 1); rhostname[sizeof (rhostname) - 1] = '\0'; } else { MEMCPY(rhostname, inp + vallen, len - vallen); rhostname[len - vallen] = '\0'; } #if PPP_REMOTENAME /* In case the remote doesn't give us his name. */ if (explicit_remote || (remote_name[0] != '\0' && vallen == len)) strlcpy(rhostname, remote_name, sizeof (rhostname)); #endif /* PPP_REMOTENAME */ /* * Get the secret for authenticating the specified * host. */ if (!get_secret(pcb, rhostname, pcb->eap.es_server.ea_name, secret, &secret_len, 1)) { ppp_dbglog("EAP: no MD5 secret for auth of %q", rhostname); eap_send_failure(pcb); break; } md5_starts(&mdContext); md5_update(&mdContext, &pcb->eap.es_server.ea_id, 1); md5_update(&mdContext, (u_char *)secret, secret_len); BZERO(secret, sizeof (secret)); md5_update(&mdContext, pcb->eap.es_challenge, pcb->eap.es_challen); md5_finish(&mdContext, hash); if (BCMP(hash, inp, MD5_SIGNATURE_SIZE) != 0) { eap_send_failure(pcb); break; } pcb->eap.es_server.ea_type = EAPT_MD5CHAP; eap_send_success(pcb); eap_figure_next_state(pcb, 0); if (pcb->eap.es_rechallenge != 0) TIMEOUT(eap_rechallenge, pcb, pcb->eap.es_rechallenge); break; #ifdef USE_SRP case EAPT_SRP: if (len < 1) { ppp_error("EAP: empty SRP Response"); eap_figure_next_state(pcb, 1); break; } GETCHAR(typenum, inp); len--; switch (typenum) { case EAPSRP_CKEY: if (pcb->eap.es_server.ea_state != eapSRP1) { ppp_error("EAP: unexpected SRP Subtype 1 Response"); eap_figure_next_state(pcb, 1); break; } A.data = inp; A.len = len; ts = (struct t_server *)pcb->eap.es_server.ea_session; assert(ts != NULL); pcb->eap.es_server.ea_skey = t_servergetkey(ts, &A); if (pcb->eap.es_server.ea_skey == NULL) { /* Client's A value is bogus; terminate now */ ppp_error("EAP: bogus A value from client"); eap_send_failure(pcb); } else { eap_figure_next_state(pcb, 0); } break; case EAPSRP_CVALIDATOR: if (pcb->eap.es_server.ea_state != eapSRP2) { ppp_error("EAP: unexpected SRP Subtype 2 Response"); eap_figure_next_state(pcb, 1); break; } if (len < sizeof (u32_t) + SHA_DIGESTSIZE) { ppp_error("EAP: M1 length %d < %d", len, sizeof (u32_t) + SHA_DIGESTSIZE); eap_figure_next_state(pcb, 1); break; } GETLONG(pcb->eap.es_server.ea_keyflags, inp); ts = (struct t_server *)pcb->eap.es_server.ea_session; assert(ts != NULL); if (t_serververify(ts, inp)) { ppp_info("EAP: unable to validate client identity"); eap_send_failure(pcb); break; } eap_figure_next_state(pcb, 0); break; case EAPSRP_ACK: if (pcb->eap.es_server.ea_state != eapSRP3) { ppp_error("EAP: unexpected SRP Subtype 3 Response"); eap_send_failure(esp); break; } pcb->eap.es_server.ea_type = EAPT_SRP; eap_send_success(pcb, esp); eap_figure_next_state(pcb, 0); if (pcb->eap.es_rechallenge != 0) TIMEOUT(eap_rechallenge, pcb, pcb->eap.es_rechallenge); if (pcb->eap.es_lwrechallenge != 0) TIMEOUT(srp_lwrechallenge, pcb, pcb->eap.es_lwrechallenge); break; case EAPSRP_LWRECHALLENGE: if (pcb->eap.es_server.ea_state != eapSRP4) { ppp_info("EAP: unexpected SRP Subtype 4 Response"); return; } if (len != SHA_DIGESTSIZE) { ppp_error("EAP: bad Lightweight rechallenge " "response"); return; } SHA1Init(&ctxt); vallen = id; SHA1Update(&ctxt, &vallen, 1); SHA1Update(&ctxt, pcb->eap.es_server.ea_skey, SESSION_KEY_LEN); SHA1Update(&ctxt, pcb->eap.es_challenge, pcb->eap.es_challen); SHA1Update(&ctxt, pcb->eap.es_server.ea_peer, pcb->eap.es_server.ea_peerlen); SHA1Final(dig, &ctxt); if (BCMP(dig, inp, SHA_DIGESTSIZE) != 0) { ppp_error("EAP: failed Lightweight rechallenge"); eap_send_failure(pcb); break; } pcb->eap.es_server.ea_state = eapOpen; if (pcb->eap.es_lwrechallenge != 0) TIMEOUT(srp_lwrechallenge, esp, pcb->eap.es_lwrechallenge); break; } break; #endif /* USE_SRP */ default: /* This can't happen. */ ppp_error("EAP: unknown Response type %d; ignored", typenum); return; } if (pcb->settings.eap_timeout_time > 0) { UNTIMEOUT(eap_server_timeout, pcb); } if (pcb->eap.es_server.ea_state != eapBadAuth && pcb->eap.es_server.ea_state != eapOpen) { pcb->eap.es_server.ea_id++; eap_send_request(pcb); } } #endif /* PPP_SERVER */ /* * eap_success - Receive EAP Success message (client mode). */ static void eap_success(ppp_pcb *pcb, u_char *inp, int id, int len) { if (pcb->eap.es_client.ea_state != eapOpen && !eap_client_active(pcb)) { ppp_dbglog("EAP unexpected success message in state %s (%d)", eap_state_name(pcb->eap.es_client.ea_state), pcb->eap.es_client.ea_state); return; } if (pcb->settings.eap_req_time > 0) { UNTIMEOUT(eap_client_timeout, pcb); } if (len > 0) { /* This is odd. The spec doesn't allow for this. */ PRINTMSG(inp, len); } pcb->eap.es_client.ea_state = eapOpen; auth_withpeer_success(pcb, PPP_EAP, 0); } /* * eap_failure - Receive EAP Failure message (client mode). */ static void eap_failure(ppp_pcb *pcb, u_char *inp, int id, int len) { if (!eap_client_active(pcb)) { ppp_dbglog("EAP unexpected failure message in state %s (%d)", eap_state_name(pcb->eap.es_client.ea_state), pcb->eap.es_client.ea_state); } if (pcb->settings.eap_req_time > 0) { UNTIMEOUT(eap_client_timeout, pcb); } if (len > 0) { /* This is odd. The spec doesn't allow for this. */ PRINTMSG(inp, len); } pcb->eap.es_client.ea_state = eapBadAuth; ppp_error("EAP: peer reports authentication failure"); auth_withpeer_fail(pcb, PPP_EAP); } /* * eap_input - Handle received EAP message. */ static void eap_input(ppp_pcb *pcb, u_char *inp, int inlen) { u_char code, id; int len; /* * Parse header (code, id and length). If packet too short, * drop it. */ if (inlen < EAP_HEADERLEN) { ppp_error("EAP: packet too short: %d < %d", inlen, EAP_HEADERLEN); return; } GETCHAR(code, inp); GETCHAR(id, inp); GETSHORT(len, inp); if (len < EAP_HEADERLEN || len > inlen) { ppp_error("EAP: packet has illegal length field %d (%d..%d)", len, EAP_HEADERLEN, inlen); return; } len -= EAP_HEADERLEN; /* Dispatch based on message code */ switch (code) { case EAP_REQUEST: eap_request(pcb, inp, id, len); break; #if PPP_SERVER case EAP_RESPONSE: eap_response(pcb, inp, id, len); break; #endif /* PPP_SERVER */ case EAP_SUCCESS: eap_success(pcb, inp, id, len); break; case EAP_FAILURE: eap_failure(pcb, inp, id, len); break; default: /* XXX Need code reject */ /* Note: it's not legal to send EAP Nak here. */ ppp_warn("EAP: unknown code %d received", code); break; } } #if PRINTPKT_SUPPORT /* * eap_printpkt - print the contents of an EAP packet. */ static char *eap_codenames[] = { "Request", "Response", "Success", "Failure" }; static char *eap_typenames[] = { "Identity", "Notification", "Nak", "MD5-Challenge", "OTP", "Generic-Token", NULL, NULL, "RSA", "DSS", "KEA", "KEA-Validate", "TLS", "Defender", "Windows 2000", "Arcot", "Cisco", "Nokia", "SRP" }; static int eap_printpkt(u_char *inp, int inlen, void (*printer) (void *, char *, ...), void *arg) { int code, id, len, rtype, vallen; u_char *pstart; u32_t uval; if (inlen < EAP_HEADERLEN) return (0); pstart = inp; GETCHAR(code, inp); GETCHAR(id, inp); GETSHORT(len, inp); if (len < EAP_HEADERLEN || len > inlen) return (0); if (code >= 1 && code <= sizeof(eap_codenames) / sizeof(char *)) printer(arg, " %s", eap_codenames[code-1]); else printer(arg, " code=0x%x", code); printer(arg, " id=0x%x", id); len -= EAP_HEADERLEN; switch (code) { case EAP_REQUEST: if (len < 1) { printer(arg, " "); break; } GETCHAR(rtype, inp); len--; if (rtype >= 1 && rtype <= sizeof (eap_typenames) / sizeof (char *)) printer(arg, " %s", eap_typenames[rtype-1]); else printer(arg, " type=0x%x", rtype); switch (rtype) { case EAPT_IDENTITY: case EAPT_NOTIFICATION: if (len > 0) { printer(arg, " "); INCPTR(len, inp); len = 0; } else { printer(arg, " "); } break; case EAPT_MD5CHAP: if (len <= 0) break; GETCHAR(vallen, inp); len--; if (vallen > len) goto truncated; printer(arg, " ", vallen, inp); INCPTR(vallen, inp); len -= vallen; if (len > 0) { printer(arg, " "); INCPTR(len, inp); len = 0; } else { printer(arg, " "); } break; case EAPT_SRP: if (len < 3) goto truncated; GETCHAR(vallen, inp); len--; printer(arg, "-%d", vallen); switch (vallen) { case EAPSRP_CHALLENGE: GETCHAR(vallen, inp); len--; if (vallen >= len) goto truncated; if (vallen > 0) { printer(arg, " "); } else { printer(arg, " "); } INCPTR(vallen, inp); len -= vallen; GETCHAR(vallen, inp); len--; if (vallen >= len) goto truncated; printer(arg, " ", vallen, inp); INCPTR(vallen, inp); len -= vallen; GETCHAR(vallen, inp); len--; if (vallen > len) goto truncated; if (vallen == 0) { printer(arg, " "); } else { printer(arg, " ", vallen, inp); } INCPTR(vallen, inp); len -= vallen; if (len == 0) { printer(arg, " "); } else { printer(arg, " ", len, inp); INCPTR(len, inp); len = 0; } break; case EAPSRP_SKEY: printer(arg, " ", len, inp); INCPTR(len, inp); len = 0; break; case EAPSRP_SVALIDATOR: if (len < sizeof (u32_t)) break; GETLONG(uval, inp); len -= sizeof (u32_t); if (uval & SRPVAL_EBIT) { printer(arg, " E"); uval &= ~SRPVAL_EBIT; } if (uval != 0) { printer(arg, " f<%X>", uval); } if ((vallen = len) > SHA_DIGESTSIZE) vallen = SHA_DIGESTSIZE; printer(arg, " ", len, inp, len < SHA_DIGESTSIZE ? "?" : ""); INCPTR(vallen, inp); len -= vallen; if (len > 0) { printer(arg, " ", len, inp); INCPTR(len, inp); len = 0; } break; case EAPSRP_LWRECHALLENGE: printer(arg, " ", len, inp); INCPTR(len, inp); len = 0; break; } break; } break; case EAP_RESPONSE: if (len < 1) break; GETCHAR(rtype, inp); len--; if (rtype >= 1 && rtype <= sizeof (eap_typenames) / sizeof (char *)) printer(arg, " %s", eap_typenames[rtype-1]); else printer(arg, " type=0x%x", rtype); switch (rtype) { case EAPT_IDENTITY: if (len > 0) { printer(arg, " "); INCPTR(len, inp); len = 0; } break; case EAPT_NAK: if (len <= 0) { printer(arg, " "); break; } GETCHAR(rtype, inp); len--; printer(arg, " = 1 && rtype < sizeof (eap_typenames) / sizeof (char *)) printer(arg, " (%s)", eap_typenames[rtype-1]); printer(arg, ">"); break; case EAPT_MD5CHAP: if (len <= 0) { printer(arg, " "); break; } GETCHAR(vallen, inp); len--; if (vallen > len) goto truncated; printer(arg, " ", vallen, inp); INCPTR(vallen, inp); len -= vallen; if (len > 0) { printer(arg, " "); INCPTR(len, inp); len = 0; } else { printer(arg, " "); } break; case EAPT_SRP: if (len < 1) goto truncated; GETCHAR(vallen, inp); len--; printer(arg, "-%d", vallen); switch (vallen) { case EAPSRP_CKEY: printer(arg, " ", len, inp); INCPTR(len, inp); len = 0; break; case EAPSRP_CVALIDATOR: if (len < sizeof (u32_t)) break; GETLONG(uval, inp); len -= sizeof (u32_t); if (uval & SRPVAL_EBIT) { printer(arg, " E"); uval &= ~SRPVAL_EBIT; } if (uval != 0) { printer(arg, " f<%X>", uval); } printer(arg, " ", len, inp, len == SHA_DIGESTSIZE ? "" : "?"); INCPTR(len, inp); len = 0; break; case EAPSRP_ACK: break; case EAPSRP_LWRECHALLENGE: printer(arg, " ", len, inp, len == SHA_DIGESTSIZE ? "" : "?"); if ((vallen = len) > SHA_DIGESTSIZE) vallen = SHA_DIGESTSIZE; INCPTR(vallen, inp); len -= vallen; break; } break; } break; case EAP_SUCCESS: /* No payload expected for these! */ case EAP_FAILURE: break; truncated: printer(arg, " "); break; } if (len > 8) printer(arg, "%8B...", inp); else if (len > 0) printer(arg, "%.*B", len, inp); INCPTR(len, inp); return (inp - pstart); } #endif /* PRINTPKT_SUPPORT */ #endif /* PPP_SUPPORT && EAP_SUPPORT */ ocproxy-1.60/lwip/src/netif/ppp/ecp.c000066400000000000000000000126341303453231400175300ustar00rootroot00000000000000/* * ecp.c - PPP Encryption Control Protocol. * * Copyright (c) 2002 Google, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The name(s) of the authors of this software must not be used to * endorse or promote products derived from this software without * prior written permission. * * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Derived from ccp.c, which is: * * Copyright (c) 1994-2002 Paul Mackerras. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. The name(s) of the authors of this software must not be used to * endorse or promote products derived from this software without * prior written permission. * * 3. Redistributions of any form whatsoever must retain the following * acknowledgment: * "This product includes software developed by Paul Mackerras * ". * * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "lwip/opt.h" #if PPP_SUPPORT && ECP_SUPPORT /* don't build if not configured for use in lwipopts.h */ #include #include "netif/ppp/ppp_impl.h" #include "netif/ppp/fsm.h" #include "netif/ppp/ecp.h" #if PPP_OPTIONS static option_t ecp_option_list[] = { { "noecp", o_bool, &ecp_protent.enabled_flag, "Disable ECP negotiation" }, { "-ecp", o_bool, &ecp_protent.enabled_flag, "Disable ECP negotiation", OPT_ALIAS }, { NULL } }; #endif /* PPP_OPTIONS */ /* * Protocol entry points from main code. */ static void ecp_init (int unit); /* static void ecp_open (int unit); static void ecp_close (int unit, char *); static void ecp_lowerup (int unit); static void ecp_lowerdown (int); static void ecp_input (int unit, u_char *pkt, int len); static void ecp_protrej (int unit); */ #if PRINTPKT_SUPPORT static int ecp_printpkt (u_char *pkt, int len, void (*printer) (void *, char *, ...), void *arg); #endif /* PRINTPKT_SUPPORT */ /* static void ecp_datainput (int unit, u_char *pkt, int len); */ const struct protent ecp_protent = { PPP_ECP, ecp_init, NULL, /* ecp_input, */ NULL, /* ecp_protrej, */ NULL, /* ecp_lowerup, */ NULL, /* ecp_lowerdown, */ NULL, /* ecp_open, */ NULL, /* ecp_close, */ #if PRINTPKT_SUPPORT ecp_printpkt, #endif /* PRINTPKT_SUPPORT */ NULL, /* ecp_datainput, */ 0, #if PRINTPKT_SUPPORT "ECP", "Encrypted", #endif /* PRINTPKT_SUPPORT */ #if PPP_OPTIONS ecp_option_list, NULL, #endif /* PPP_OPTIONS */ #if DEMAND_SUPPORT NULL, NULL #endif /* DEMAND_SUPPORT */ }; fsm ecp_fsm[NUM_PPP]; ecp_options ecp_wantoptions[NUM_PPP]; /* what to request the peer to use */ ecp_options ecp_gotoptions[NUM_PPP]; /* what the peer agreed to do */ ecp_options ecp_allowoptions[NUM_PPP]; /* what we'll agree to do */ ecp_options ecp_hisoptions[NUM_PPP]; /* what we agreed to do */ static const fsm_callbacks ecp_callbacks = { NULL, /* ecp_resetci, */ NULL, /* ecp_cilen, */ NULL, /* ecp_addci, */ NULL, /* ecp_ackci, */ NULL, /* ecp_nakci, */ NULL, /* ecp_rejci, */ NULL, /* ecp_reqci, */ NULL, /* ecp_up, */ NULL, /* ecp_down, */ NULL, NULL, NULL, NULL, NULL, /* ecp_extcode, */ "ECP" }; /* * ecp_init - initialize ECP. */ static void ecp_init(unit) int unit; { fsm *f = &ecp_fsm[unit]; f->unit = unit; f->protocol = PPP_ECP; f->callbacks = &ecp_callbacks; fsm_init(f); memset(&ecp_wantoptions[unit], 0, sizeof(ecp_options)); memset(&ecp_gotoptions[unit], 0, sizeof(ecp_options)); memset(&ecp_allowoptions[unit], 0, sizeof(ecp_options)); memset(&ecp_hisoptions[unit], 0, sizeof(ecp_options)); } #if PRINTPKT_SUPPORT static int ecp_printpkt(p, plen, printer, arg) u_char *p; int plen; void (*printer) (void *, char *, ...); void *arg; { return 0; } #endif /* PRINTPKT_SUPPORT */ #endif /* PPP_SUPPORT && ECP_SUPPORT */ ocproxy-1.60/lwip/src/netif/ppp/eui64.c000066400000000000000000000040361303453231400177120ustar00rootroot00000000000000/* * eui64.c - EUI64 routines for IPv6CP. * * Copyright (c) 1999 Tommi Komulainen. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The name(s) of the authors of this software must not be used to * endorse or promote products derived from this software without * prior written permission. * * 4. Redistributions of any form whatsoever must retain the following * acknowledgment: * "This product includes software developed by Tommi Komulainen * ". * * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * $Id: eui64.c,v 1.6 2002/12/04 23:03:32 paulus Exp $ */ #include "lwip/opt.h" #if PPP_SUPPORT && PPP_IPV6_SUPPORT /* don't build if not configured for use in lwipopts.h */ #include "netif/ppp/ppp_impl.h" #include "netif/ppp/eui64.h" /* * eui64_ntoa - Make an ascii representation of an interface identifier */ char *eui64_ntoa(eui64_t e) { static char buf[32]; snprintf(buf, 32, "%02x%02x:%02x%02x:%02x%02x:%02x%02x", e.e8[0], e.e8[1], e.e8[2], e.e8[3], e.e8[4], e.e8[5], e.e8[6], e.e8[7]); return buf; } #endif /* PPP_SUPPORT && PPP_IPV6_SUPPORT */ ocproxy-1.60/lwip/src/netif/ppp/fsm.c000066400000000000000000000462541303453231400175530ustar00rootroot00000000000000/* * fsm.c - {Link, IP} Control Protocol Finite State Machine. * * Copyright (c) 1984-2000 Carnegie Mellon University. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The name "Carnegie Mellon University" must not be used to * endorse or promote products derived from this software without * prior written permission. For permission or any legal * details, please contact * Office of Technology Transfer * Carnegie Mellon University * 5000 Forbes Avenue * Pittsburgh, PA 15213-3890 * (412) 268-4387, fax: (412) 268-7395 * tech-transfer@andrew.cmu.edu * * 4. Redistributions of any form whatsoever must retain the following * acknowledgment: * "This product includes software developed by Computing Services * at Carnegie Mellon University (http://www.cmu.edu/computing/)." * * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "lwip/opt.h" #if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */ /* * TODO: * Randomize fsm id on link/init. * Deal with variable outgoing MTU. */ #if 0 /* UNUSED */ #include #include #include #endif /* UNUSED */ #include "netif/ppp/ppp_impl.h" #include "netif/ppp/fsm.h" static void fsm_timeout (void *); static void fsm_rconfreq(fsm *f, u_char id, u_char *inp, int len); static void fsm_rconfack(fsm *f, int id, u_char *inp, int len); static void fsm_rconfnakrej(fsm *f, int code, int id, u_char *inp, int len); static void fsm_rtermreq(fsm *f, int id, u_char *p, int len); static void fsm_rtermack(fsm *f); static void fsm_rcoderej(fsm *f, u_char *inp, int len); static void fsm_sconfreq(fsm *f, int retransmit); #define PROTO_NAME(f) ((f)->callbacks->proto_name) /* * fsm_init - Initialize fsm. * * Initialize fsm state. */ void fsm_init(fsm *f) { ppp_pcb *pcb = f->pcb; f->state = PPP_FSM_INITIAL; f->flags = 0; f->id = 0; /* XXX Start with random id? */ f->maxnakloops = pcb->settings.fsm_max_nak_loops; f->term_reason_len = 0; } /* * fsm_lowerup - The lower layer is up. */ void fsm_lowerup(fsm *f) { switch( f->state ){ case PPP_FSM_INITIAL: f->state = PPP_FSM_CLOSED; break; case PPP_FSM_STARTING: if( f->flags & OPT_SILENT ) f->state = PPP_FSM_STOPPED; else { /* Send an initial configure-request */ fsm_sconfreq(f, 0); f->state = PPP_FSM_REQSENT; } break; default: FSMDEBUG(("%s: Up event in state %d!", PROTO_NAME(f), f->state)); /* no break */ } } /* * fsm_lowerdown - The lower layer is down. * * Cancel all timeouts and inform upper layers. */ void fsm_lowerdown(fsm *f) { switch( f->state ){ case PPP_FSM_CLOSED: f->state = PPP_FSM_INITIAL; break; case PPP_FSM_STOPPED: f->state = PPP_FSM_STARTING; if( f->callbacks->starting ) (*f->callbacks->starting)(f); break; case PPP_FSM_CLOSING: f->state = PPP_FSM_INITIAL; UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ break; case PPP_FSM_STOPPING: case PPP_FSM_REQSENT: case PPP_FSM_ACKRCVD: case PPP_FSM_ACKSENT: f->state = PPP_FSM_STARTING; UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ break; case PPP_FSM_OPENED: if( f->callbacks->down ) (*f->callbacks->down)(f); f->state = PPP_FSM_STARTING; break; default: FSMDEBUG(("%s: Down event in state %d!", PROTO_NAME(f), f->state)); /* no break */ } } /* * fsm_open - Link is allowed to come up. */ void fsm_open(fsm *f) { switch( f->state ){ case PPP_FSM_INITIAL: f->state = PPP_FSM_STARTING; if( f->callbacks->starting ) (*f->callbacks->starting)(f); break; case PPP_FSM_CLOSED: if( f->flags & OPT_SILENT ) f->state = PPP_FSM_STOPPED; else { /* Send an initial configure-request */ fsm_sconfreq(f, 0); f->state = PPP_FSM_REQSENT; } break; case PPP_FSM_CLOSING: f->state = PPP_FSM_STOPPING; /* fall through */ /* no break */ case PPP_FSM_STOPPED: case PPP_FSM_OPENED: if( f->flags & OPT_RESTART ){ fsm_lowerdown(f); fsm_lowerup(f); } break; } } /* * terminate_layer - Start process of shutting down the FSM * * Cancel any timeout running, notify upper layers we're done, and * send a terminate-request message as configured. */ static void terminate_layer(fsm *f, int nextstate) { ppp_pcb *pcb = f->pcb; if( f->state != PPP_FSM_OPENED ) UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ else if( f->callbacks->down ) (*f->callbacks->down)(f); /* Inform upper layers we're down */ /* Init restart counter and send Terminate-Request */ f->retransmits = pcb->settings.fsm_max_term_transmits; fsm_sdata(f, TERMREQ, f->reqid = ++f->id, (u_char *) f->term_reason, f->term_reason_len); if (f->retransmits == 0) { /* * User asked for no terminate requests at all; just close it. * We've already fired off one Terminate-Request just to be nice * to the peer, but we're not going to wait for a reply. */ f->state = nextstate == PPP_FSM_CLOSING ? PPP_FSM_CLOSED : PPP_FSM_STOPPED; if( f->callbacks->finished ) (*f->callbacks->finished)(f); return; } TIMEOUT(fsm_timeout, f, pcb->settings.fsm_timeout_time); --f->retransmits; f->state = nextstate; } /* * fsm_close - Start closing connection. * * Cancel timeouts and either initiate close or possibly go directly to * the PPP_FSM_CLOSED state. */ void fsm_close(fsm *f, char *reason) { f->term_reason = reason; f->term_reason_len = (reason == NULL? 0: LWIP_MIN(strlen(reason), 0xFF) ); switch( f->state ){ case PPP_FSM_STARTING: f->state = PPP_FSM_INITIAL; break; case PPP_FSM_STOPPED: f->state = PPP_FSM_CLOSED; break; case PPP_FSM_STOPPING: f->state = PPP_FSM_CLOSING; break; case PPP_FSM_REQSENT: case PPP_FSM_ACKRCVD: case PPP_FSM_ACKSENT: case PPP_FSM_OPENED: terminate_layer(f, PPP_FSM_CLOSING); break; } } /* * fsm_timeout - Timeout expired. */ static void fsm_timeout(void *arg) { fsm *f = (fsm *) arg; ppp_pcb *pcb = f->pcb; switch (f->state) { case PPP_FSM_CLOSING: case PPP_FSM_STOPPING: if( f->retransmits <= 0 ){ /* * We've waited for an ack long enough. Peer probably heard us. */ f->state = (f->state == PPP_FSM_CLOSING)? PPP_FSM_CLOSED: PPP_FSM_STOPPED; if( f->callbacks->finished ) (*f->callbacks->finished)(f); } else { /* Send Terminate-Request */ fsm_sdata(f, TERMREQ, f->reqid = ++f->id, (u_char *) f->term_reason, f->term_reason_len); TIMEOUT(fsm_timeout, f, pcb->settings.fsm_timeout_time); --f->retransmits; } break; case PPP_FSM_REQSENT: case PPP_FSM_ACKRCVD: case PPP_FSM_ACKSENT: if (f->retransmits <= 0) { ppp_warn("%s: timeout sending Config-Requests\n", PROTO_NAME(f)); f->state = PPP_FSM_STOPPED; if( (f->flags & OPT_PASSIVE) == 0 && f->callbacks->finished ) (*f->callbacks->finished)(f); } else { /* Retransmit the configure-request */ if (f->callbacks->retransmit) (*f->callbacks->retransmit)(f); fsm_sconfreq(f, 1); /* Re-send Configure-Request */ if( f->state == PPP_FSM_ACKRCVD ) f->state = PPP_FSM_REQSENT; } break; default: FSMDEBUG(("%s: Timeout event in state %d!", PROTO_NAME(f), f->state)); /* no break */ } } /* * fsm_input - Input packet. */ void fsm_input(fsm *f, u_char *inpacket, int l) { u_char *inp; u_char code, id; int len; /* * Parse header (code, id and length). * If packet too short, drop it. */ inp = inpacket; if (l < HEADERLEN) { FSMDEBUG(("fsm_input(%x): Rcvd short header.", f->protocol)); return; } GETCHAR(code, inp); GETCHAR(id, inp); GETSHORT(len, inp); if (len < HEADERLEN) { FSMDEBUG(("fsm_input(%x): Rcvd illegal length.", f->protocol)); return; } if (len > l) { FSMDEBUG(("fsm_input(%x): Rcvd short packet.", f->protocol)); return; } len -= HEADERLEN; /* subtract header length */ if( f->state == PPP_FSM_INITIAL || f->state == PPP_FSM_STARTING ){ FSMDEBUG(("fsm_input(%x): Rcvd packet in state %d.", f->protocol, f->state)); return; } /* * Action depends on code. */ switch (code) { case CONFREQ: fsm_rconfreq(f, id, inp, len); break; case CONFACK: fsm_rconfack(f, id, inp, len); break; case CONFNAK: case CONFREJ: fsm_rconfnakrej(f, code, id, inp, len); break; case TERMREQ: fsm_rtermreq(f, id, inp, len); break; case TERMACK: fsm_rtermack(f); break; case CODEREJ: fsm_rcoderej(f, inp, len); break; default: if( !f->callbacks->extcode || !(*f->callbacks->extcode)(f, code, id, inp, len) ) fsm_sdata(f, CODEREJ, ++f->id, inpacket, len + HEADERLEN); break; } } /* * fsm_rconfreq - Receive Configure-Request. */ static void fsm_rconfreq(fsm *f, u_char id, u_char *inp, int len) { int code, reject_if_disagree; switch( f->state ){ case PPP_FSM_CLOSED: /* Go away, we're closed */ fsm_sdata(f, TERMACK, id, NULL, 0); return; case PPP_FSM_CLOSING: case PPP_FSM_STOPPING: return; case PPP_FSM_OPENED: /* Go down and restart negotiation */ if( f->callbacks->down ) (*f->callbacks->down)(f); /* Inform upper layers */ fsm_sconfreq(f, 0); /* Send initial Configure-Request */ f->state = PPP_FSM_REQSENT; break; case PPP_FSM_STOPPED: /* Negotiation started by our peer */ fsm_sconfreq(f, 0); /* Send initial Configure-Request */ f->state = PPP_FSM_REQSENT; break; } /* * Pass the requested configuration options * to protocol-specific code for checking. */ if (f->callbacks->reqci){ /* Check CI */ reject_if_disagree = (f->nakloops >= f->maxnakloops); code = (*f->callbacks->reqci)(f, inp, &len, reject_if_disagree); } else if (len) code = CONFREJ; /* Reject all CI */ else code = CONFACK; /* send the Ack, Nak or Rej to the peer */ fsm_sdata(f, code, id, inp, len); if (code == CONFACK) { if (f->state == PPP_FSM_ACKRCVD) { UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ f->state = PPP_FSM_OPENED; if (f->callbacks->up) (*f->callbacks->up)(f); /* Inform upper layers */ } else f->state = PPP_FSM_ACKSENT; f->nakloops = 0; } else { /* we sent CONFACK or CONFREJ */ if (f->state != PPP_FSM_ACKRCVD) f->state = PPP_FSM_REQSENT; if( code == CONFNAK ) ++f->nakloops; } } /* * fsm_rconfack - Receive Configure-Ack. */ static void fsm_rconfack(fsm *f, int id, u_char *inp, int len) { ppp_pcb *pcb = f->pcb; if (id != f->reqid || f->seen_ack) /* Expected id? */ return; /* Nope, toss... */ if( !(f->callbacks->ackci? (*f->callbacks->ackci)(f, inp, len): (len == 0)) ){ /* Ack is bad - ignore it */ ppp_error("Received bad configure-ack: %P", inp, len); return; } f->seen_ack = 1; f->rnakloops = 0; switch (f->state) { case PPP_FSM_CLOSED: case PPP_FSM_STOPPED: fsm_sdata(f, TERMACK, id, NULL, 0); break; case PPP_FSM_REQSENT: f->state = PPP_FSM_ACKRCVD; f->retransmits = pcb->settings.fsm_max_conf_req_transmits; break; case PPP_FSM_ACKRCVD: /* Huh? an extra valid Ack? oh well... */ UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ fsm_sconfreq(f, 0); f->state = PPP_FSM_REQSENT; break; case PPP_FSM_ACKSENT: UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ f->state = PPP_FSM_OPENED; f->retransmits = pcb->settings.fsm_max_conf_req_transmits; if (f->callbacks->up) (*f->callbacks->up)(f); /* Inform upper layers */ break; case PPP_FSM_OPENED: /* Go down and restart negotiation */ if (f->callbacks->down) (*f->callbacks->down)(f); /* Inform upper layers */ fsm_sconfreq(f, 0); /* Send initial Configure-Request */ f->state = PPP_FSM_REQSENT; break; } } /* * fsm_rconfnakrej - Receive Configure-Nak or Configure-Reject. */ static void fsm_rconfnakrej(fsm *f, int code, int id, u_char *inp, int len) { int ret; int treat_as_reject; if (id != f->reqid || f->seen_ack) /* Expected id? */ return; /* Nope, toss... */ if (code == CONFNAK) { ++f->rnakloops; treat_as_reject = (f->rnakloops >= f->maxnakloops); if (f->callbacks->nakci == NULL || !(ret = f->callbacks->nakci(f, inp, len, treat_as_reject))) { ppp_error("Received bad configure-nak: %P", inp, len); return; } } else { f->rnakloops = 0; if (f->callbacks->rejci == NULL || !(ret = f->callbacks->rejci(f, inp, len))) { ppp_error("Received bad configure-rej: %P", inp, len); return; } } f->seen_ack = 1; switch (f->state) { case PPP_FSM_CLOSED: case PPP_FSM_STOPPED: fsm_sdata(f, TERMACK, id, NULL, 0); break; case PPP_FSM_REQSENT: case PPP_FSM_ACKSENT: /* They didn't agree to what we wanted - try another request */ UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ if (ret < 0) f->state = PPP_FSM_STOPPED; /* kludge for stopping CCP */ else fsm_sconfreq(f, 0); /* Send Configure-Request */ break; case PPP_FSM_ACKRCVD: /* Got a Nak/reject when we had already had an Ack?? oh well... */ UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ fsm_sconfreq(f, 0); f->state = PPP_FSM_REQSENT; break; case PPP_FSM_OPENED: /* Go down and restart negotiation */ if (f->callbacks->down) (*f->callbacks->down)(f); /* Inform upper layers */ fsm_sconfreq(f, 0); /* Send initial Configure-Request */ f->state = PPP_FSM_REQSENT; break; } } /* * fsm_rtermreq - Receive Terminate-Req. */ static void fsm_rtermreq(fsm *f, int id, u_char *p, int len) { ppp_pcb *pcb = f->pcb; switch (f->state) { case PPP_FSM_ACKRCVD: case PPP_FSM_ACKSENT: f->state = PPP_FSM_REQSENT; /* Start over but keep trying */ break; case PPP_FSM_OPENED: if (len > 0) { ppp_info("%s terminated by peer (%0.*v)", PROTO_NAME(f), len, p); } else ppp_info("%s terminated by peer", PROTO_NAME(f)); f->retransmits = 0; f->state = PPP_FSM_STOPPING; if (f->callbacks->down) (*f->callbacks->down)(f); /* Inform upper layers */ TIMEOUT(fsm_timeout, f, pcb->settings.fsm_timeout_time); break; } fsm_sdata(f, TERMACK, id, NULL, 0); } /* * fsm_rtermack - Receive Terminate-Ack. */ static void fsm_rtermack(fsm *f) { switch (f->state) { case PPP_FSM_CLOSING: UNTIMEOUT(fsm_timeout, f); f->state = PPP_FSM_CLOSED; if( f->callbacks->finished ) (*f->callbacks->finished)(f); break; case PPP_FSM_STOPPING: UNTIMEOUT(fsm_timeout, f); f->state = PPP_FSM_STOPPED; if( f->callbacks->finished ) (*f->callbacks->finished)(f); break; case PPP_FSM_ACKRCVD: f->state = PPP_FSM_REQSENT; break; case PPP_FSM_OPENED: if (f->callbacks->down) (*f->callbacks->down)(f); /* Inform upper layers */ fsm_sconfreq(f, 0); f->state = PPP_FSM_REQSENT; break; } } /* * fsm_rcoderej - Receive an Code-Reject. */ static void fsm_rcoderej(fsm *f, u_char *inp, int len) { u_char code, id; if (len < HEADERLEN) { FSMDEBUG(("fsm_rcoderej: Rcvd short Code-Reject packet!")); return; } GETCHAR(code, inp); GETCHAR(id, inp); ppp_warn("%s: Rcvd Code-Reject for code %d, id %d", PROTO_NAME(f), code, id); if( f->state == PPP_FSM_ACKRCVD ) f->state = PPP_FSM_REQSENT; } /* * fsm_protreject - Peer doesn't speak this protocol. * * Treat this as a catastrophic error (RXJ-). */ void fsm_protreject(fsm *f) { switch( f->state ){ case PPP_FSM_CLOSING: UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ /* fall through */ /* no break */ case PPP_FSM_CLOSED: f->state = PPP_FSM_CLOSED; if( f->callbacks->finished ) (*f->callbacks->finished)(f); break; case PPP_FSM_STOPPING: case PPP_FSM_REQSENT: case PPP_FSM_ACKRCVD: case PPP_FSM_ACKSENT: UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ /* fall through */ /* no break */ case PPP_FSM_STOPPED: f->state = PPP_FSM_STOPPED; if( f->callbacks->finished ) (*f->callbacks->finished)(f); break; case PPP_FSM_OPENED: terminate_layer(f, PPP_FSM_STOPPING); break; default: FSMDEBUG(("%s: Protocol-reject event in state %d!", PROTO_NAME(f), f->state)); /* no break */ } } /* * fsm_sconfreq - Send a Configure-Request. */ static void fsm_sconfreq(fsm *f, int retransmit) { ppp_pcb *pcb = f->pcb; struct pbuf *p; u_char *outp; int cilen; if( f->state != PPP_FSM_REQSENT && f->state != PPP_FSM_ACKRCVD && f->state != PPP_FSM_ACKSENT ){ /* Not currently negotiating - reset options */ if( f->callbacks->resetci ) (*f->callbacks->resetci)(f); f->nakloops = 0; f->rnakloops = 0; } if( !retransmit ){ /* New request - reset retransmission counter, use new ID */ f->retransmits = pcb->settings.fsm_max_conf_req_transmits; f->reqid = ++f->id; } f->seen_ack = 0; /* * Make up the request packet */ if( f->callbacks->cilen && f->callbacks->addci ){ cilen = (*f->callbacks->cilen)(f); if( cilen > pcb->peer_mru - HEADERLEN ) cilen = pcb->peer_mru - HEADERLEN; } else cilen = 0; p = pbuf_alloc(PBUF_RAW, (u16_t)(cilen + HEADERLEN + PPP_HDRLEN), PPP_CTRL_PBUF_TYPE); if(NULL == p) return; if(p->tot_len != p->len) { pbuf_free(p); return; } /* send the request to our peer */ outp = p->payload; MAKEHEADER(outp, f->protocol); PUTCHAR(CONFREQ, outp); PUTCHAR(f->reqid, outp); PUTSHORT(cilen + HEADERLEN, outp); if (cilen != 0) { (*f->callbacks->addci)(f, outp, &cilen); } ppp_write(pcb, p); /* start the retransmit timer */ --f->retransmits; TIMEOUT(fsm_timeout, f, pcb->settings.fsm_timeout_time); } /* * fsm_sdata - Send some data. * * Used for all packets sent to our peer by this module. */ void fsm_sdata(fsm *f, u_char code, u_char id, u_char *data, int datalen) { ppp_pcb *pcb = f->pcb; struct pbuf *p; u_char *outp; int outlen; /* Adjust length to be smaller than MTU */ if (datalen > pcb->peer_mru - HEADERLEN) datalen = pcb->peer_mru - HEADERLEN; outlen = datalen + HEADERLEN; p = pbuf_alloc(PBUF_RAW, (u16_t)(outlen + PPP_HDRLEN), PPP_CTRL_PBUF_TYPE); if(NULL == p) return; if(p->tot_len != p->len) { pbuf_free(p); return; } outp = p->payload; /* if (datalen && data != outp + PPP_HDRLEN + HEADERLEN) -- was only for fsm_sconfreq() */ MEMCPY(outp + PPP_HDRLEN + HEADERLEN, data, datalen); MAKEHEADER(outp, f->protocol); PUTCHAR(code, outp); PUTCHAR(id, outp); PUTSHORT(outlen, outp); ppp_write(pcb, p); } #endif /* PPP_SUPPORT */ ocproxy-1.60/lwip/src/netif/ppp/ipcp.c000066400000000000000000001644161303453231400177220ustar00rootroot00000000000000/* * ipcp.c - PPP IP Control Protocol. * * Copyright (c) 1984-2000 Carnegie Mellon University. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The name "Carnegie Mellon University" must not be used to * endorse or promote products derived from this software without * prior written permission. For permission or any legal * details, please contact * Office of Technology Transfer * Carnegie Mellon University * 5000 Forbes Avenue * Pittsburgh, PA 15213-3890 * (412) 268-4387, fax: (412) 268-7395 * tech-transfer@andrew.cmu.edu * * 4. Redistributions of any form whatsoever must retain the following * acknowledgment: * "This product includes software developed by Computing Services * at Carnegie Mellon University (http://www.cmu.edu/computing/)." * * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "lwip/opt.h" #if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */ /* * TODO: */ #if 0 /* UNUSED */ #include #include #include #include #include #include #include #include #include #endif /* UNUSED */ #include "netif/ppp/ppp_impl.h" #include "netif/ppp/fsm.h" #include "netif/ppp/ipcp.h" #if 0 /* UNUSED */ /* global vars */ u32_t netmask = 0; /* IP netmask to set on interface */ #endif /* UNUSED */ #if 0 /* UNUSED */ bool disable_defaultip = 0; /* Don't use hostname for default IP adrs */ #endif /* UNUSED */ #if 0 /* moved to ppp_settings */ bool noremoteip = 0; /* Let him have no IP address */ #endif /* moved to ppp_setting */ #if 0 /* UNUSED */ /* Hook for a plugin to know when IP protocol has come up */ void (*ip_up_hook) (void) = NULL; /* Hook for a plugin to know when IP protocol has come down */ void (*ip_down_hook) (void) = NULL; /* Hook for a plugin to choose the remote IP address */ void (*ip_choose_hook) (u32_t *) = NULL; #endif /* UNUSED */ #if PPP_NOTIFY /* Notifiers for when IPCP goes up and down */ struct notifier *ip_up_notifier = NULL; struct notifier *ip_down_notifier = NULL; #endif /* PPP_NOTIFY */ /* local vars */ #if 0 /* moved to ppp_pcb */ static int default_route_set[NUM_PPP]; /* Have set up a default route */ static int proxy_arp_set[NUM_PPP]; /* Have created proxy arp entry */ static int ipcp_is_up; /* have called np_up() */ static int ipcp_is_open; /* haven't called np_finished() */ static bool ask_for_local; /* request our address from peer */ #endif /* moved to ppp_pcb */ #if 0 /* UNUSED */ static char vj_value[8]; /* string form of vj option value */ static char netmask_str[20]; /* string form of netmask value */ #endif /* UNUSED */ /* * Callbacks for fsm code. (CI = Configuration Information) */ static void ipcp_resetci(fsm *f); /* Reset our CI */ static int ipcp_cilen(fsm *f); /* Return length of our CI */ static void ipcp_addci(fsm *f, u_char *ucp, int *lenp); /* Add our CI */ static int ipcp_ackci(fsm *f, u_char *p, int len); /* Peer ack'd our CI */ static int ipcp_nakci(fsm *f, u_char *p, int len, int treat_as_reject);/* Peer nak'd our CI */ static int ipcp_rejci(fsm *f, u_char *p, int len); /* Peer rej'd our CI */ static int ipcp_reqci(fsm *f, u_char *inp, int *len, int reject_if_disagree); /* Rcv CI */ static void ipcp_up(fsm *f); /* We're UP */ static void ipcp_down(fsm *f); /* We're DOWN */ static void ipcp_finished(fsm *f); /* Don't need lower layer */ static const fsm_callbacks ipcp_callbacks = { /* IPCP callback routines */ ipcp_resetci, /* Reset our Configuration Information */ ipcp_cilen, /* Length of our Configuration Information */ ipcp_addci, /* Add our Configuration Information */ ipcp_ackci, /* ACK our Configuration Information */ ipcp_nakci, /* NAK our Configuration Information */ ipcp_rejci, /* Reject our Configuration Information */ ipcp_reqci, /* Request peer's Configuration Information */ ipcp_up, /* Called when fsm reaches OPENED state */ ipcp_down, /* Called when fsm leaves OPENED state */ NULL, /* Called when we want the lower layer up */ ipcp_finished, /* Called when we want the lower layer down */ NULL, /* Called when Protocol-Reject received */ NULL, /* Retransmission is necessary */ NULL, /* Called to handle protocol-specific codes */ "IPCP" /* String name of protocol */ }; /* * Command-line options. */ #if PPP_OPTIONS static int setvjslots (char **); static int setdnsaddr (char **); static int setwinsaddr (char **); static int setnetmask (char **); int setipaddr (char *, char **, int); static void printipaddr (option_t *, void (*)(void *, char *,...),void *); static option_t ipcp_option_list[] = { { "noip", o_bool, &ipcp_protent.enabled_flag, "Disable IP and IPCP" }, { "-ip", o_bool, &ipcp_protent.enabled_flag, "Disable IP and IPCP", OPT_ALIAS }, { "novj", o_bool, &ipcp_wantoptions[0].neg_vj, "Disable VJ compression", OPT_A2CLR, &ipcp_allowoptions[0].neg_vj }, { "-vj", o_bool, &ipcp_wantoptions[0].neg_vj, "Disable VJ compression", OPT_ALIAS | OPT_A2CLR, &ipcp_allowoptions[0].neg_vj }, { "novjccomp", o_bool, &ipcp_wantoptions[0].cflag, "Disable VJ connection-ID compression", OPT_A2CLR, &ipcp_allowoptions[0].cflag }, { "-vjccomp", o_bool, &ipcp_wantoptions[0].cflag, "Disable VJ connection-ID compression", OPT_ALIAS | OPT_A2CLR, &ipcp_allowoptions[0].cflag }, { "vj-max-slots", o_special, (void *)setvjslots, "Set maximum VJ header slots", OPT_PRIO | OPT_A2STRVAL | OPT_STATIC, vj_value }, { "ipcp-accept-local", o_bool, &ipcp_wantoptions[0].accept_local, "Accept peer's address for us", 1 }, { "ipcp-accept-remote", o_bool, &ipcp_wantoptions[0].accept_remote, "Accept peer's address for it", 1 }, { "ipparam", o_string, &ipparam, "Set ip script parameter", OPT_PRIO }, { "noipdefault", o_bool, &disable_defaultip, "Don't use name for default IP adrs", 1 }, { "ms-dns", 1, (void *)setdnsaddr, "DNS address for the peer's use" }, { "ms-wins", 1, (void *)setwinsaddr, "Nameserver for SMB over TCP/IP for peer" }, { "ipcp-restart", o_int, &ipcp_fsm[0].timeouttime, "Set timeout for IPCP", OPT_PRIO }, { "ipcp-max-terminate", o_int, &ipcp_fsm[0].maxtermtransmits, "Set max #xmits for term-reqs", OPT_PRIO }, { "ipcp-max-configure", o_int, &ipcp_fsm[0].maxconfreqtransmits, "Set max #xmits for conf-reqs", OPT_PRIO }, { "ipcp-max-failure", o_int, &ipcp_fsm[0].maxnakloops, "Set max #conf-naks for IPCP", OPT_PRIO }, { "defaultroute", o_bool, &ipcp_wantoptions[0].default_route, "Add default route", OPT_ENABLE|1, &ipcp_allowoptions[0].default_route }, { "nodefaultroute", o_bool, &ipcp_allowoptions[0].default_route, "disable defaultroute option", OPT_A2CLR, &ipcp_wantoptions[0].default_route }, { "-defaultroute", o_bool, &ipcp_allowoptions[0].default_route, "disable defaultroute option", OPT_ALIAS | OPT_A2CLR, &ipcp_wantoptions[0].default_route }, { "replacedefaultroute", o_bool, &ipcp_wantoptions[0].replace_default_route, "Replace default route", 1 }, { "noreplacedefaultroute", o_bool, &ipcp_allowoptions[0].replace_default_route, "Never replace default route", OPT_A2COPY, &ipcp_wantoptions[0].replace_default_route }, { "proxyarp", o_bool, &ipcp_wantoptions[0].proxy_arp, "Add proxy ARP entry", OPT_ENABLE|1, &ipcp_allowoptions[0].proxy_arp }, { "noproxyarp", o_bool, &ipcp_allowoptions[0].proxy_arp, "disable proxyarp option", OPT_A2CLR, &ipcp_wantoptions[0].proxy_arp }, { "-proxyarp", o_bool, &ipcp_allowoptions[0].proxy_arp, "disable proxyarp option", OPT_ALIAS | OPT_A2CLR, &ipcp_wantoptions[0].proxy_arp }, { "usepeerdns", o_bool, &usepeerdns, "Ask peer for DNS address(es)", 1 }, { "netmask", o_special, (void *)setnetmask, "set netmask", OPT_PRIO | OPT_A2STRVAL | OPT_STATIC, netmask_str }, { "ipcp-no-addresses", o_bool, &ipcp_wantoptions[0].old_addrs, "Disable old-style IP-Addresses usage", OPT_A2CLR, &ipcp_allowoptions[0].old_addrs }, { "ipcp-no-address", o_bool, &ipcp_wantoptions[0].neg_addr, "Disable IP-Address usage", OPT_A2CLR, &ipcp_allowoptions[0].neg_addr }, #ifdef __linux__ { "noremoteip", o_bool, &noremoteip, "Allow peer to have no IP address", 1 }, #endif { "nosendip", o_bool, &ipcp_wantoptions[0].neg_addr, "Don't send our IP address to peer", OPT_A2CLR, &ipcp_wantoptions[0].old_addrs}, { "IP addresses", o_wild, (void *) &setipaddr, "set local and remote IP addresses", OPT_NOARG | OPT_A2PRINTER, (void *) &printipaddr }, { NULL } }; #endif /* PPP_OPTIONS */ /* * Protocol entry points from main code. */ static void ipcp_init(ppp_pcb *pcb); static void ipcp_open(ppp_pcb *pcb); static void ipcp_close(ppp_pcb *pcb, char *reason); static void ipcp_lowerup(ppp_pcb *pcb); static void ipcp_lowerdown(ppp_pcb *pcb); static void ipcp_input(ppp_pcb *pcb, u_char *p, int len); static void ipcp_protrej(ppp_pcb *pcb); #if PRINTPKT_SUPPORT static int ipcp_printpkt(u_char *p, int plen, void (*printer) (void *, char *, ...), void *arg); #endif /* PRINTPKT_SUPPORT */ #if PPP_OPTIONS static void ip_check_options (void); #endif /* PPP_OPTIONS */ #if DEMAND_SUPPORT static int ip_demand_conf (int); static int ip_active_pkt (u_char *, int); #endif /* DEMAND_SUPPORT */ #if 0 /* UNUSED */ static void create_resolv (u32_t, u32_t); #endif /* UNUSED */ const struct protent ipcp_protent = { PPP_IPCP, ipcp_init, ipcp_input, ipcp_protrej, ipcp_lowerup, ipcp_lowerdown, ipcp_open, ipcp_close, #if PRINTPKT_SUPPORT ipcp_printpkt, #endif /* PRINTPKT_SUPPORT */ NULL, 1, #if PRINTPKT_SUPPORT "IPCP", "IP", #endif /* PRINTPKT_SUPPORT */ #if PPP_OPTIONS ipcp_option_list, ip_check_options, #endif /* PPP_OPTIONS */ #if DEMAND_SUPPORT ip_demand_conf, ip_active_pkt #endif /* DEMAND_SUPPORT */ }; static void ipcp_clear_addrs(ppp_pcb *pcb, u32_t ouraddr, u32_t hisaddr, u8_t replacedefaultroute); /* * Lengths of configuration options. */ #define CILEN_VOID 2 #define CILEN_COMPRESS 4 /* min length for compression protocol opt. */ #define CILEN_VJ 6 /* length for RFC1332 Van-Jacobson opt. */ #define CILEN_ADDR 6 /* new-style single address option */ #define CILEN_ADDRS 10 /* old-style dual address option */ #define CODENAME(x) ((x) == CONFACK ? "ACK" : \ (x) == CONFNAK ? "NAK" : "REJ") #if 0 /* UNUSED, already defined by lwIP */ /* * Make a string representation of a network IP address. */ char * ip_ntoa(ipaddr) u32_t ipaddr; { static char b[64]; slprintf(b, sizeof(b), "%I", ipaddr); return b; } #endif /* UNUSED, already defined by lwIP */ /* * Option parsing. */ #if PPP_OPTIONS /* * setvjslots - set maximum number of connection slots for VJ compression */ static int setvjslots(argv) char **argv; { int value; /* FIXME: found what int_option() did */ #if PPP_OPTIONS if (!int_option(*argv, &value)) return 0; #endif /* PPP_OPTIONS */ if (value < 2 || value > 16) { option_error("vj-max-slots value must be between 2 and 16"); return 0; } ipcp_wantoptions [0].maxslotindex = ipcp_allowoptions[0].maxslotindex = value - 1; slprintf(vj_value, sizeof(vj_value), "%d", value); return 1; } /* * setdnsaddr - set the dns address(es) */ static int setdnsaddr(argv) char **argv; { u32_t dns; struct hostent *hp; dns = inet_addr(*argv); if (dns == (u32_t) -1) { if ((hp = gethostbyname(*argv)) == NULL) { option_error("invalid address parameter '%s' for ms-dns option", *argv); return 0; } dns = *(u32_t *)hp->h_addr; } /* We take the last 2 values given, the 2nd-last as the primary and the last as the secondary. If only one is given it becomes both primary and secondary. */ if (ipcp_allowoptions[0].dnsaddr[1] == 0) ipcp_allowoptions[0].dnsaddr[0] = dns; else ipcp_allowoptions[0].dnsaddr[0] = ipcp_allowoptions[0].dnsaddr[1]; /* always set the secondary address value. */ ipcp_allowoptions[0].dnsaddr[1] = dns; return (1); } /* * setwinsaddr - set the wins address(es) * This is primrarly used with the Samba package under UNIX or for pointing * the caller to the existing WINS server on a Windows NT platform. */ static int setwinsaddr(argv) char **argv; { u32_t wins; struct hostent *hp; wins = inet_addr(*argv); if (wins == (u32_t) -1) { if ((hp = gethostbyname(*argv)) == NULL) { option_error("invalid address parameter '%s' for ms-wins option", *argv); return 0; } wins = *(u32_t *)hp->h_addr; } /* We take the last 2 values given, the 2nd-last as the primary and the last as the secondary. If only one is given it becomes both primary and secondary. */ if (ipcp_allowoptions[0].winsaddr[1] == 0) ipcp_allowoptions[0].winsaddr[0] = wins; else ipcp_allowoptions[0].winsaddr[0] = ipcp_allowoptions[0].winsaddr[1]; /* always set the secondary address value. */ ipcp_allowoptions[0].winsaddr[1] = wins; return (1); } /* * setipaddr - Set the IP address * If doit is 0, the call is to check whether this option is * potentially an IP address specification. * Not static so that plugins can call it to set the addresses */ int setipaddr(arg, argv, doit) char *arg; char **argv; int doit; { struct hostent *hp; char *colon; u32_t local, remote; ipcp_options *wo = &ipcp_wantoptions[0]; static int prio_local = 0, prio_remote = 0; /* * IP address pair separated by ":". */ if ((colon = strchr(arg, ':')) == NULL) return 0; if (!doit) return 1; /* * If colon first character, then no local addr. */ if (colon != arg && option_priority >= prio_local) { *colon = '\0'; if ((local = inet_addr(arg)) == (u32_t) -1) { if ((hp = gethostbyname(arg)) == NULL) { option_error("unknown host: %s", arg); return 0; } local = *(u32_t *)hp->h_addr; } if (bad_ip_adrs(local)) { option_error("bad local IP address %s", ip_ntoa(local)); return 0; } if (local != 0) wo->ouraddr = local; *colon = ':'; prio_local = option_priority; } /* * If colon last character, then no remote addr. */ if (*++colon != '\0' && option_priority >= prio_remote) { if ((remote = inet_addr(colon)) == (u32_t) -1) { if ((hp = gethostbyname(colon)) == NULL) { option_error("unknown host: %s", colon); return 0; } remote = *(u32_t *)hp->h_addr; if (remote_name[0] == 0) strlcpy(remote_name, colon, sizeof(remote_name)); } if (bad_ip_adrs(remote)) { option_error("bad remote IP address %s", ip_ntoa(remote)); return 0; } if (remote != 0) wo->hisaddr = remote; prio_remote = option_priority; } return 1; } static void printipaddr(opt, printer, arg) option_t *opt; void (*printer) (void *, char *, ...); void *arg; { ipcp_options *wo = &ipcp_wantoptions[0]; if (wo->ouraddr != 0) printer(arg, "%I", wo->ouraddr); printer(arg, ":"); if (wo->hisaddr != 0) printer(arg, "%I", wo->hisaddr); } /* * setnetmask - set the netmask to be used on the interface. */ static int setnetmask(argv) char **argv; { u32_t mask; int n; char *p; /* * Unfortunately, if we use inet_addr, we can't tell whether * a result of all 1s is an error or a valid 255.255.255.255. */ p = *argv; n = parse_dotted_ip(p, &mask); mask = htonl(mask); if (n == 0 || p[n] != 0 || (netmask & ~mask) != 0) { option_error("invalid netmask value '%s'", *argv); return 0; } netmask = mask; slprintf(netmask_str, sizeof(netmask_str), "%I", mask); return (1); } int parse_dotted_ip(p, vp) char *p; u32_t *vp; { int n; u32_t v, b; char *endp, *p0 = p; v = 0; for (n = 3;; --n) { b = strtoul(p, &endp, 0); if (endp == p) return 0; if (b > 255) { if (n < 3) return 0; /* accept e.g. 0xffffff00 */ *vp = b; return endp - p0; } v |= b << (n * 8); p = endp; if (n == 0) break; if (*p != '.') return 0; ++p; } *vp = v; return p - p0; } #endif /* PPP_OPTIONS */ /* * ipcp_init - Initialize IPCP. */ static void ipcp_init(ppp_pcb *pcb) { fsm *f = &pcb->ipcp_fsm; ipcp_options *wo = &pcb->ipcp_wantoptions; ipcp_options *ao = &pcb->ipcp_allowoptions; f->pcb = pcb; f->protocol = PPP_IPCP; f->callbacks = &ipcp_callbacks; fsm_init(f); /* * Some 3G modems use repeated IPCP NAKs as a way of stalling * until they can contact a server on the network, so we increase * the default number of NAKs we accept before we start treating * them as rejects. */ f->maxnakloops = 100; memset(wo, 0, sizeof(*wo)); memset(ao, 0, sizeof(*ao)); wo->neg_addr = wo->old_addrs = 1; wo->neg_vj = 1; wo->vj_protocol = IPCP_VJ_COMP; wo->maxslotindex = MAX_STATES - 1; /* really max index */ wo->cflag = 1; #if 0 /* UNUSED */ /* wanting default route by default */ wo->default_route = 1; #endif /* UNUSED */ /* max slots and slot-id compression are currently hardwired in */ /* ppp_if.c to 16 and 1, this needs to be changed (among other */ /* things) gmc */ ao->neg_addr = ao->old_addrs = 1; ao->neg_vj = 1; ao->maxslotindex = MAX_STATES - 1; ao->cflag = 1; #if 0 /* UNUSED */ /* * XXX These control whether the user may use the proxyarp * and defaultroute options. */ ao->proxy_arp = 1; ao->default_route = 1; #endif /* UNUSED */ } /* * ipcp_open - IPCP is allowed to come up. */ static void ipcp_open(ppp_pcb *pcb) { fsm *f = &pcb->ipcp_fsm; fsm_open(f); pcb->ipcp_is_open = 1; } /* * ipcp_close - Take IPCP down. */ static void ipcp_close(ppp_pcb *pcb, char *reason) { fsm *f = &pcb->ipcp_fsm; fsm_close(f, reason); } /* * ipcp_lowerup - The lower layer is up. */ static void ipcp_lowerup(ppp_pcb *pcb) { fsm *f = &pcb->ipcp_fsm; fsm_lowerup(f); } /* * ipcp_lowerdown - The lower layer is down. */ static void ipcp_lowerdown(ppp_pcb *pcb) { fsm *f = &pcb->ipcp_fsm; fsm_lowerdown(f); } /* * ipcp_input - Input IPCP packet. */ static void ipcp_input(ppp_pcb *pcb, u_char *p, int len) { fsm *f = &pcb->ipcp_fsm; fsm_input(f, p, len); } /* * ipcp_protrej - A Protocol-Reject was received for IPCP. * * Pretend the lower layer went down, so we shut up. */ static void ipcp_protrej(ppp_pcb *pcb) { fsm *f = &pcb->ipcp_fsm; fsm_lowerdown(f); } /* * ipcp_resetci - Reset our CI. * Called by fsm_sconfreq, Send Configure Request. */ static void ipcp_resetci(fsm *f) { ppp_pcb *pcb = f->pcb; ipcp_options *wo = &pcb->ipcp_wantoptions; ipcp_options *go = &pcb->ipcp_gotoptions; ipcp_options *ao = &pcb->ipcp_allowoptions; wo->req_addr = (wo->neg_addr || wo->old_addrs) && (ao->neg_addr || ao->old_addrs); if (wo->ouraddr == 0) wo->accept_local = 1; if (wo->hisaddr == 0) wo->accept_remote = 1; wo->req_dns1 = pcb->settings.usepeerdns; /* Request DNS addresses from the peer */ wo->req_dns2 = pcb->settings.usepeerdns; *go = *wo; if (!pcb->ask_for_local) go->ouraddr = 0; #if 0 /* UNUSED */ if (ip_choose_hook) { ip_choose_hook(&wo->hisaddr); if (wo->hisaddr) { wo->accept_remote = 0; } } #endif /* UNUSED */ BZERO(&pcb->ipcp_hisoptions, sizeof(ipcp_options)); } /* * ipcp_cilen - Return length of our CI. * Called by fsm_sconfreq, Send Configure Request. */ static int ipcp_cilen(fsm *f) { ppp_pcb *pcb = f->pcb; ipcp_options *go = &pcb->ipcp_gotoptions; ipcp_options *wo = &pcb->ipcp_wantoptions; ipcp_options *ho = &pcb->ipcp_hisoptions; #define LENCIADDRS(neg) (neg ? CILEN_ADDRS : 0) #define LENCIVJ(neg, old) (neg ? (old? CILEN_COMPRESS : CILEN_VJ) : 0) #define LENCIADDR(neg) (neg ? CILEN_ADDR : 0) #define LENCIDNS(neg) LENCIADDR(neg) #define LENCIWINS(neg) LENCIADDR(neg) /* * First see if we want to change our options to the old * forms because we have received old forms from the peer. */ if (go->neg_addr && go->old_addrs && !ho->neg_addr && ho->old_addrs) go->neg_addr = 0; if (wo->neg_vj && !go->neg_vj && !go->old_vj) { /* try an older style of VJ negotiation */ /* use the old style only if the peer did */ if (ho->neg_vj && ho->old_vj) { go->neg_vj = 1; go->old_vj = 1; go->vj_protocol = ho->vj_protocol; } } return (LENCIADDRS(!go->neg_addr && go->old_addrs) + LENCIVJ(go->neg_vj, go->old_vj) + LENCIADDR(go->neg_addr) + LENCIDNS(go->req_dns1) + LENCIDNS(go->req_dns2) + LENCIWINS(go->winsaddr[0]) + LENCIWINS(go->winsaddr[1])) ; } /* * ipcp_addci - Add our desired CIs to a packet. * Called by fsm_sconfreq, Send Configure Request. */ static void ipcp_addci(fsm *f, u_char *ucp, int *lenp) { ppp_pcb *pcb = f->pcb; ipcp_options *go = &pcb->ipcp_gotoptions; int len = *lenp; #define ADDCIADDRS(opt, neg, val1, val2) \ if (neg) { \ if (len >= CILEN_ADDRS) { \ u32_t l; \ PUTCHAR(opt, ucp); \ PUTCHAR(CILEN_ADDRS, ucp); \ l = ntohl(val1); \ PUTLONG(l, ucp); \ l = ntohl(val2); \ PUTLONG(l, ucp); \ len -= CILEN_ADDRS; \ } else \ go->old_addrs = 0; \ } #define ADDCIVJ(opt, neg, val, old, maxslotindex, cflag) \ if (neg) { \ int vjlen = old? CILEN_COMPRESS : CILEN_VJ; \ if (len >= vjlen) { \ PUTCHAR(opt, ucp); \ PUTCHAR(vjlen, ucp); \ PUTSHORT(val, ucp); \ if (!old) { \ PUTCHAR(maxslotindex, ucp); \ PUTCHAR(cflag, ucp); \ } \ len -= vjlen; \ } else \ neg = 0; \ } #define ADDCIADDR(opt, neg, val) \ if (neg) { \ if (len >= CILEN_ADDR) { \ u32_t l; \ PUTCHAR(opt, ucp); \ PUTCHAR(CILEN_ADDR, ucp); \ l = ntohl(val); \ PUTLONG(l, ucp); \ len -= CILEN_ADDR; \ } else \ neg = 0; \ } #define ADDCIDNS(opt, neg, addr) \ if (neg) { \ if (len >= CILEN_ADDR) { \ u32_t l; \ PUTCHAR(opt, ucp); \ PUTCHAR(CILEN_ADDR, ucp); \ l = ntohl(addr); \ PUTLONG(l, ucp); \ len -= CILEN_ADDR; \ } else \ neg = 0; \ } #define ADDCIWINS(opt, addr) \ if (addr) { \ if (len >= CILEN_ADDR) { \ u32_t l; \ PUTCHAR(opt, ucp); \ PUTCHAR(CILEN_ADDR, ucp); \ l = ntohl(addr); \ PUTLONG(l, ucp); \ len -= CILEN_ADDR; \ } else \ addr = 0; \ } ADDCIADDRS(CI_ADDRS, !go->neg_addr && go->old_addrs, go->ouraddr, go->hisaddr); ADDCIVJ(CI_COMPRESSTYPE, go->neg_vj, go->vj_protocol, go->old_vj, go->maxslotindex, go->cflag); ADDCIADDR(CI_ADDR, go->neg_addr, go->ouraddr); ADDCIDNS(CI_MS_DNS1, go->req_dns1, go->dnsaddr[0]); ADDCIDNS(CI_MS_DNS2, go->req_dns2, go->dnsaddr[1]); ADDCIWINS(CI_MS_WINS1, go->winsaddr[0]); ADDCIWINS(CI_MS_WINS2, go->winsaddr[1]); *lenp -= len; } /* * ipcp_ackci - Ack our CIs. * Called by fsm_rconfack, Receive Configure ACK. * * Returns: * 0 - Ack was bad. * 1 - Ack was good. */ static int ipcp_ackci(fsm *f, u_char *p, int len) { ppp_pcb *pcb = f->pcb; ipcp_options *go = &pcb->ipcp_gotoptions; u_short cilen, citype, cishort; u32_t cilong; u_char cimaxslotindex, cicflag; /* * CIs must be in exactly the same order that we sent... * Check packet length and CI length at each step. * If we find any deviations, then this packet is bad. */ #define ACKCIADDRS(opt, neg, val1, val2) \ if (neg) { \ u32_t l; \ if ((len -= CILEN_ADDRS) < 0) \ goto bad; \ GETCHAR(citype, p); \ GETCHAR(cilen, p); \ if (cilen != CILEN_ADDRS || \ citype != opt) \ goto bad; \ GETLONG(l, p); \ cilong = htonl(l); \ if (val1 != cilong) \ goto bad; \ GETLONG(l, p); \ cilong = htonl(l); \ if (val2 != cilong) \ goto bad; \ } #define ACKCIVJ(opt, neg, val, old, maxslotindex, cflag) \ if (neg) { \ int vjlen = old? CILEN_COMPRESS : CILEN_VJ; \ if ((len -= vjlen) < 0) \ goto bad; \ GETCHAR(citype, p); \ GETCHAR(cilen, p); \ if (cilen != vjlen || \ citype != opt) \ goto bad; \ GETSHORT(cishort, p); \ if (cishort != val) \ goto bad; \ if (!old) { \ GETCHAR(cimaxslotindex, p); \ if (cimaxslotindex != maxslotindex) \ goto bad; \ GETCHAR(cicflag, p); \ if (cicflag != cflag) \ goto bad; \ } \ } #define ACKCIADDR(opt, neg, val) \ if (neg) { \ u32_t l; \ if ((len -= CILEN_ADDR) < 0) \ goto bad; \ GETCHAR(citype, p); \ GETCHAR(cilen, p); \ if (cilen != CILEN_ADDR || \ citype != opt) \ goto bad; \ GETLONG(l, p); \ cilong = htonl(l); \ if (val != cilong) \ goto bad; \ } #define ACKCIDNS(opt, neg, addr) \ if (neg) { \ u32_t l; \ if ((len -= CILEN_ADDR) < 0) \ goto bad; \ GETCHAR(citype, p); \ GETCHAR(cilen, p); \ if (cilen != CILEN_ADDR || citype != opt) \ goto bad; \ GETLONG(l, p); \ cilong = htonl(l); \ if (addr != cilong) \ goto bad; \ } #define ACKCIWINS(opt, addr) \ if (addr) { \ u_int32_t l; \ if ((len -= CILEN_ADDR) < 0) \ goto bad; \ GETCHAR(citype, p); \ GETCHAR(cilen, p); \ if (cilen != CILEN_ADDR || citype != opt) \ goto bad; \ GETLONG(l, p); \ cilong = htonl(l); \ if (addr != cilong) \ goto bad; \ } ACKCIADDRS(CI_ADDRS, !go->neg_addr && go->old_addrs, go->ouraddr, go->hisaddr); ACKCIVJ(CI_COMPRESSTYPE, go->neg_vj, go->vj_protocol, go->old_vj, go->maxslotindex, go->cflag); ACKCIADDR(CI_ADDR, go->neg_addr, go->ouraddr); ACKCIDNS(CI_MS_DNS1, go->req_dns1, go->dnsaddr[0]); ACKCIDNS(CI_MS_DNS2, go->req_dns2, go->dnsaddr[1]); ACKCIWINS(CI_MS_WINS1, go->winsaddr[0]); ACKCIWINS(CI_MS_WINS2, go->winsaddr[1]); /* * If there are any remaining CIs, then this packet is bad. */ if (len != 0) goto bad; return (1); bad: IPCPDEBUG(("ipcp_ackci: received bad Ack!")); return (0); } /* * ipcp_nakci - Peer has sent a NAK for some of our CIs. * This should not modify any state if the Nak is bad * or if IPCP is in the OPENED state. * Calback from fsm_rconfnakrej - Receive Configure-Nak or Configure-Reject. * * Returns: * 0 - Nak was bad. * 1 - Nak was good. */ static int ipcp_nakci(fsm *f, u_char *p, int len, int treat_as_reject) { ppp_pcb *pcb = f->pcb; ipcp_options *go = &pcb->ipcp_gotoptions; u_char cimaxslotindex, cicflag; u_char citype, cilen, *next; u_short cishort; u32_t ciaddr1, ciaddr2, l, cidnsaddr; ipcp_options no; /* options we've seen Naks for */ ipcp_options try; /* options to request next time */ BZERO(&no, sizeof(no)); try = *go; /* * Any Nak'd CIs must be in exactly the same order that we sent. * Check packet length and CI length at each step. * If we find any deviations, then this packet is bad. */ #define NAKCIADDRS(opt, neg, code) \ if ((neg) && \ (cilen = p[1]) == CILEN_ADDRS && \ len >= cilen && \ p[0] == opt) { \ len -= cilen; \ INCPTR(2, p); \ GETLONG(l, p); \ ciaddr1 = htonl(l); \ GETLONG(l, p); \ ciaddr2 = htonl(l); \ no.old_addrs = 1; \ code \ } #define NAKCIVJ(opt, neg, code) \ if (go->neg && \ ((cilen = p[1]) == CILEN_COMPRESS || cilen == CILEN_VJ) && \ len >= cilen && \ p[0] == opt) { \ len -= cilen; \ INCPTR(2, p); \ GETSHORT(cishort, p); \ no.neg = 1; \ code \ } #define NAKCIADDR(opt, neg, code) \ if (go->neg && \ (cilen = p[1]) == CILEN_ADDR && \ len >= cilen && \ p[0] == opt) { \ len -= cilen; \ INCPTR(2, p); \ GETLONG(l, p); \ ciaddr1 = htonl(l); \ no.neg = 1; \ code \ } #define NAKCIDNS(opt, neg, code) \ if (go->neg && \ ((cilen = p[1]) == CILEN_ADDR) && \ len >= cilen && \ p[0] == opt) { \ len -= cilen; \ INCPTR(2, p); \ GETLONG(l, p); \ cidnsaddr = htonl(l); \ no.neg = 1; \ code \ } /* * Accept the peer's idea of {our,his} address, if different * from our idea, only if the accept_{local,remote} flag is set. */ NAKCIADDRS(CI_ADDRS, !go->neg_addr && go->old_addrs, if (treat_as_reject) { try.old_addrs = 0; } else { if (go->accept_local && ciaddr1) { /* take his idea of our address */ try.ouraddr = ciaddr1; } if (go->accept_remote && ciaddr2) { /* take his idea of his address */ try.hisaddr = ciaddr2; } } ); /* * Accept the peer's value of maxslotindex provided that it * is less than what we asked for. Turn off slot-ID compression * if the peer wants. Send old-style compress-type option if * the peer wants. */ NAKCIVJ(CI_COMPRESSTYPE, neg_vj, if (treat_as_reject) { try.neg_vj = 0; } else if (cilen == CILEN_VJ) { GETCHAR(cimaxslotindex, p); GETCHAR(cicflag, p); if (cishort == IPCP_VJ_COMP) { try.old_vj = 0; if (cimaxslotindex < go->maxslotindex) try.maxslotindex = cimaxslotindex; if (!cicflag) try.cflag = 0; } else { try.neg_vj = 0; } } else { if (cishort == IPCP_VJ_COMP || cishort == IPCP_VJ_COMP_OLD) { try.old_vj = 1; try.vj_protocol = cishort; } else { try.neg_vj = 0; } } ); NAKCIADDR(CI_ADDR, neg_addr, if (treat_as_reject) { try.neg_addr = 0; try.old_addrs = 0; } else if (go->accept_local && ciaddr1) { /* take his idea of our address */ try.ouraddr = ciaddr1; } ); NAKCIDNS(CI_MS_DNS1, req_dns1, if (treat_as_reject) { try.req_dns1 = 0; } else { try.dnsaddr[0] = cidnsaddr; } ); NAKCIDNS(CI_MS_DNS2, req_dns2, if (treat_as_reject) { try.req_dns2 = 0; } else { try.dnsaddr[1] = cidnsaddr; } ); /* * There may be remaining CIs, if the peer is requesting negotiation * on an option that we didn't include in our request packet. * If they want to negotiate about IP addresses, we comply. * If they want us to ask for compression, we refuse. * If they want us to ask for ms-dns, we do that, since some * peers get huffy if we don't. */ while (len >= CILEN_VOID) { GETCHAR(citype, p); GETCHAR(cilen, p); if ( cilen < CILEN_VOID || (len -= cilen) < 0 ) goto bad; next = p + cilen - 2; switch (citype) { case CI_COMPRESSTYPE: if (go->neg_vj || no.neg_vj || (cilen != CILEN_VJ && cilen != CILEN_COMPRESS)) goto bad; no.neg_vj = 1; break; case CI_ADDRS: if ((!go->neg_addr && go->old_addrs) || no.old_addrs || cilen != CILEN_ADDRS) goto bad; try.neg_addr = 0; GETLONG(l, p); ciaddr1 = htonl(l); if (ciaddr1 && go->accept_local) try.ouraddr = ciaddr1; GETLONG(l, p); ciaddr2 = htonl(l); if (ciaddr2 && go->accept_remote) try.hisaddr = ciaddr2; no.old_addrs = 1; break; case CI_ADDR: if (go->neg_addr || no.neg_addr || cilen != CILEN_ADDR) goto bad; try.old_addrs = 0; GETLONG(l, p); ciaddr1 = htonl(l); if (ciaddr1 && go->accept_local) try.ouraddr = ciaddr1; if (try.ouraddr != 0) try.neg_addr = 1; no.neg_addr = 1; break; case CI_MS_DNS1: if (go->req_dns1 || no.req_dns1 || cilen != CILEN_ADDR) goto bad; GETLONG(l, p); try.dnsaddr[0] = htonl(l); try.req_dns1 = 1; no.req_dns1 = 1; break; case CI_MS_DNS2: if (go->req_dns2 || no.req_dns2 || cilen != CILEN_ADDR) goto bad; GETLONG(l, p); try.dnsaddr[1] = htonl(l); try.req_dns2 = 1; no.req_dns2 = 1; break; case CI_MS_WINS1: case CI_MS_WINS2: if (cilen != CILEN_ADDR) goto bad; GETLONG(l, p); ciaddr1 = htonl(l); if (ciaddr1) try.winsaddr[citype == CI_MS_WINS2] = ciaddr1; break; } p = next; } /* * OK, the Nak is good. Now we can update state. * If there are any remaining options, we ignore them. */ if (f->state != PPP_FSM_OPENED) *go = try; return 1; bad: IPCPDEBUG(("ipcp_nakci: received bad Nak!")); return 0; } /* * ipcp_rejci - Reject some of our CIs. * Callback from fsm_rconfnakrej. */ static int ipcp_rejci(fsm *f, u_char *p, int len) { ppp_pcb *pcb = f->pcb; ipcp_options *go = &pcb->ipcp_gotoptions; u_char cimaxslotindex, ciflag, cilen; u_short cishort; u32_t cilong; ipcp_options try; /* options to request next time */ try = *go; /* * Any Rejected CIs must be in exactly the same order that we sent. * Check packet length and CI length at each step. * If we find any deviations, then this packet is bad. */ #define REJCIADDRS(opt, neg, val1, val2) \ if ((neg) && \ (cilen = p[1]) == CILEN_ADDRS && \ len >= cilen && \ p[0] == opt) { \ u32_t l; \ len -= cilen; \ INCPTR(2, p); \ GETLONG(l, p); \ cilong = htonl(l); \ /* Check rejected value. */ \ if (cilong != val1) \ goto bad; \ GETLONG(l, p); \ cilong = htonl(l); \ /* Check rejected value. */ \ if (cilong != val2) \ goto bad; \ try.old_addrs = 0; \ } #define REJCIVJ(opt, neg, val, old, maxslot, cflag) \ if (go->neg && \ p[1] == (old? CILEN_COMPRESS : CILEN_VJ) && \ len >= p[1] && \ p[0] == opt) { \ len -= p[1]; \ INCPTR(2, p); \ GETSHORT(cishort, p); \ /* Check rejected value. */ \ if (cishort != val) \ goto bad; \ if (!old) { \ GETCHAR(cimaxslotindex, p); \ if (cimaxslotindex != maxslot) \ goto bad; \ GETCHAR(ciflag, p); \ if (ciflag != cflag) \ goto bad; \ } \ try.neg = 0; \ } #define REJCIADDR(opt, neg, val) \ if (go->neg && \ (cilen = p[1]) == CILEN_ADDR && \ len >= cilen && \ p[0] == opt) { \ u32_t l; \ len -= cilen; \ INCPTR(2, p); \ GETLONG(l, p); \ cilong = htonl(l); \ /* Check rejected value. */ \ if (cilong != val) \ goto bad; \ try.neg = 0; \ } #define REJCIDNS(opt, neg, dnsaddr) \ if (go->neg && \ ((cilen = p[1]) == CILEN_ADDR) && \ len >= cilen && \ p[0] == opt) { \ u32_t l; \ len -= cilen; \ INCPTR(2, p); \ GETLONG(l, p); \ cilong = htonl(l); \ /* Check rejected value. */ \ if (cilong != dnsaddr) \ goto bad; \ try.neg = 0; \ } #define REJCIWINS(opt, addr) \ if (addr && \ ((cilen = p[1]) == CILEN_ADDR) && \ len >= cilen && \ p[0] == opt) { \ u32_t l; \ len -= cilen; \ INCPTR(2, p); \ GETLONG(l, p); \ cilong = htonl(l); \ /* Check rejected value. */ \ if (cilong != addr) \ goto bad; \ try.winsaddr[opt == CI_MS_WINS2] = 0; \ } REJCIADDRS(CI_ADDRS, !go->neg_addr && go->old_addrs, go->ouraddr, go->hisaddr); REJCIVJ(CI_COMPRESSTYPE, neg_vj, go->vj_protocol, go->old_vj, go->maxslotindex, go->cflag); REJCIADDR(CI_ADDR, neg_addr, go->ouraddr); REJCIDNS(CI_MS_DNS1, req_dns1, go->dnsaddr[0]); REJCIDNS(CI_MS_DNS2, req_dns2, go->dnsaddr[1]); REJCIWINS(CI_MS_WINS1, go->winsaddr[0]); REJCIWINS(CI_MS_WINS2, go->winsaddr[1]); /* * If there are any remaining CIs, then this packet is bad. */ if (len != 0) goto bad; /* * Now we can update state. */ if (f->state != PPP_FSM_OPENED) *go = try; return 1; bad: IPCPDEBUG(("ipcp_rejci: received bad Reject!")); return 0; } /* * ipcp_reqci - Check the peer's requested CIs and send appropriate response. * Callback from fsm_rconfreq, Receive Configure Request * * Returns: CONFACK, CONFNAK or CONFREJ and input packet modified * appropriately. If reject_if_disagree is non-zero, doesn't return * CONFNAK; returns CONFREJ if it can't return CONFACK. * * inp = Requested CIs * len = Length of requested CIs */ static int ipcp_reqci(fsm *f, u_char *inp, int *len, int reject_if_disagree) { ppp_pcb *pcb = f->pcb; ipcp_options *wo = &pcb->ipcp_wantoptions; ipcp_options *ho = &pcb->ipcp_hisoptions; ipcp_options *ao = &pcb->ipcp_allowoptions; u_char *cip, *next; /* Pointer to current and next CIs */ u_short cilen, citype; /* Parsed len, type */ u_short cishort; /* Parsed short value */ u32_t tl, ciaddr1, ciaddr2;/* Parsed address values */ int rc = CONFACK; /* Final packet return code */ int orc; /* Individual option return code */ u_char *p; /* Pointer to next char to parse */ u_char *ucp = inp; /* Pointer to current output char */ int l = *len; /* Length left */ u_char maxslotindex, cflag; int d; /* * Reset all his options. */ BZERO(ho, sizeof(*ho)); /* * Process all his options. */ next = inp; while (l) { orc = CONFACK; /* Assume success */ cip = p = next; /* Remember begining of CI */ if (l < 2 || /* Not enough data for CI header or */ p[1] < 2 || /* CI length too small or */ p[1] > l) { /* CI length too big? */ IPCPDEBUG(("ipcp_reqci: bad CI length!")); orc = CONFREJ; /* Reject bad CI */ cilen = l; /* Reject till end of packet */ l = 0; /* Don't loop again */ goto endswitch; } GETCHAR(citype, p); /* Parse CI type */ GETCHAR(cilen, p); /* Parse CI length */ l -= cilen; /* Adjust remaining length */ next += cilen; /* Step to next CI */ switch (citype) { /* Check CI type */ case CI_ADDRS: if (!ao->old_addrs || ho->neg_addr || cilen != CILEN_ADDRS) { /* Check CI length */ orc = CONFREJ; /* Reject CI */ break; } /* * If he has no address, or if we both have his address but * disagree about it, then NAK it with our idea. * In particular, if we don't know his address, but he does, * then accept it. */ GETLONG(tl, p); /* Parse source address (his) */ ciaddr1 = htonl(tl); if (ciaddr1 != wo->hisaddr && (ciaddr1 == 0 || !wo->accept_remote)) { orc = CONFNAK; if (!reject_if_disagree) { DECPTR(sizeof(u32_t), p); tl = ntohl(wo->hisaddr); PUTLONG(tl, p); } } else if (ciaddr1 == 0 && wo->hisaddr == 0) { /* * If neither we nor he knows his address, reject the option. */ orc = CONFREJ; wo->req_addr = 0; /* don't NAK with 0.0.0.0 later */ break; } /* * If he doesn't know our address, or if we both have our address * but disagree about it, then NAK it with our idea. */ GETLONG(tl, p); /* Parse desination address (ours) */ ciaddr2 = htonl(tl); if (ciaddr2 != wo->ouraddr) { if (ciaddr2 == 0 || !wo->accept_local) { orc = CONFNAK; if (!reject_if_disagree) { DECPTR(sizeof(u32_t), p); tl = ntohl(wo->ouraddr); PUTLONG(tl, p); } } else { wo->ouraddr = ciaddr2; /* accept peer's idea */ } } ho->old_addrs = 1; ho->hisaddr = ciaddr1; ho->ouraddr = ciaddr2; break; case CI_ADDR: if (!ao->neg_addr || ho->old_addrs || cilen != CILEN_ADDR) { /* Check CI length */ orc = CONFREJ; /* Reject CI */ break; } /* * If he has no address, or if we both have his address but * disagree about it, then NAK it with our idea. * In particular, if we don't know his address, but he does, * then accept it. */ GETLONG(tl, p); /* Parse source address (his) */ ciaddr1 = htonl(tl); if (ciaddr1 != wo->hisaddr && (ciaddr1 == 0 || !wo->accept_remote)) { orc = CONFNAK; if (!reject_if_disagree) { DECPTR(sizeof(u32_t), p); tl = ntohl(wo->hisaddr); PUTLONG(tl, p); } } else if (ciaddr1 == 0 && wo->hisaddr == 0) { /* * Don't ACK an address of 0.0.0.0 - reject it instead. */ orc = CONFREJ; wo->req_addr = 0; /* don't NAK with 0.0.0.0 later */ break; } ho->neg_addr = 1; ho->hisaddr = ciaddr1; break; case CI_MS_DNS1: case CI_MS_DNS2: /* Microsoft primary or secondary DNS request */ d = citype == CI_MS_DNS2; /* If we do not have a DNS address then we cannot send it */ if (ao->dnsaddr[d] == 0 || cilen != CILEN_ADDR) { /* Check CI length */ orc = CONFREJ; /* Reject CI */ break; } GETLONG(tl, p); if (htonl(tl) != ao->dnsaddr[d]) { DECPTR(sizeof(u32_t), p); tl = ntohl(ao->dnsaddr[d]); PUTLONG(tl, p); orc = CONFNAK; } break; case CI_MS_WINS1: case CI_MS_WINS2: /* Microsoft primary or secondary WINS request */ d = citype == CI_MS_WINS2; /* If we do not have a DNS address then we cannot send it */ if (ao->winsaddr[d] == 0 || cilen != CILEN_ADDR) { /* Check CI length */ orc = CONFREJ; /* Reject CI */ break; } GETLONG(tl, p); if (htonl(tl) != ao->winsaddr[d]) { DECPTR(sizeof(u32_t), p); tl = ntohl(ao->winsaddr[d]); PUTLONG(tl, p); orc = CONFNAK; } break; case CI_COMPRESSTYPE: if (!ao->neg_vj || (cilen != CILEN_VJ && cilen != CILEN_COMPRESS)) { orc = CONFREJ; break; } GETSHORT(cishort, p); if (!(cishort == IPCP_VJ_COMP || (cishort == IPCP_VJ_COMP_OLD && cilen == CILEN_COMPRESS))) { orc = CONFREJ; break; } ho->neg_vj = 1; ho->vj_protocol = cishort; if (cilen == CILEN_VJ) { GETCHAR(maxslotindex, p); if (maxslotindex > ao->maxslotindex) { orc = CONFNAK; if (!reject_if_disagree){ DECPTR(1, p); PUTCHAR(ao->maxslotindex, p); } } GETCHAR(cflag, p); if (cflag && !ao->cflag) { orc = CONFNAK; if (!reject_if_disagree){ DECPTR(1, p); PUTCHAR(wo->cflag, p); } } ho->maxslotindex = maxslotindex; ho->cflag = cflag; } else { ho->old_vj = 1; ho->maxslotindex = MAX_STATES - 1; ho->cflag = 1; } break; default: orc = CONFREJ; break; } endswitch: if (orc == CONFACK && /* Good CI */ rc != CONFACK) /* but prior CI wasnt? */ continue; /* Don't send this one */ if (orc == CONFNAK) { /* Nak this CI? */ if (reject_if_disagree) /* Getting fed up with sending NAKs? */ orc = CONFREJ; /* Get tough if so */ else { if (rc == CONFREJ) /* Rejecting prior CI? */ continue; /* Don't send this one */ if (rc == CONFACK) { /* Ack'd all prior CIs? */ rc = CONFNAK; /* Not anymore... */ ucp = inp; /* Backup */ } } } if (orc == CONFREJ && /* Reject this CI */ rc != CONFREJ) { /* but no prior ones? */ rc = CONFREJ; ucp = inp; /* Backup */ } /* Need to move CI? */ if (ucp != cip) MEMCPY(ucp, cip, cilen); /* Move it */ /* Update output pointer */ INCPTR(cilen, ucp); } /* * If we aren't rejecting this packet, and we want to negotiate * their address, and they didn't send their address, then we * send a NAK with a CI_ADDR option appended. We assume the * input buffer is long enough that we can append the extra * option safely. */ if (rc != CONFREJ && !ho->neg_addr && !ho->old_addrs && wo->req_addr && !reject_if_disagree && !pcb->settings.noremoteip) { if (rc == CONFACK) { rc = CONFNAK; ucp = inp; /* reset pointer */ wo->req_addr = 0; /* don't ask again */ } PUTCHAR(CI_ADDR, ucp); PUTCHAR(CILEN_ADDR, ucp); tl = ntohl(wo->hisaddr); PUTLONG(tl, ucp); } *len = ucp - inp; /* Compute output length */ IPCPDEBUG(("ipcp: returning Configure-%s", CODENAME(rc))); return (rc); /* Return final code */ } #if 0 /* UNUSED */ /* * ip_check_options - check that any IP-related options are OK, * and assign appropriate defaults. */ static void ip_check_options() { struct hostent *hp; u32_t local; ipcp_options *wo = &ipcp_wantoptions[0]; /* * Default our local IP address based on our hostname. * If local IP address already given, don't bother. */ if (wo->ouraddr == 0 && !disable_defaultip) { /* * Look up our hostname (possibly with domain name appended) * and take the first IP address as our local IP address. * If there isn't an IP address for our hostname, too bad. */ wo->accept_local = 1; /* don't insist on this default value */ if ((hp = gethostbyname(hostname)) != NULL) { local = *(u32_t *)hp->h_addr; if (local != 0 && !bad_ip_adrs(local)) wo->ouraddr = local; } } ask_for_local = wo->ouraddr != 0 || !disable_defaultip; } #endif /* UNUSED */ #if DEMAND_SUPPORT /* * ip_demand_conf - configure the interface as though * IPCP were up, for use with dial-on-demand. */ static int ip_demand_conf(u) int u; { ppp_pcb *pcb = &ppp_pcb_list[u]; ipcp_options *wo = &ipcp_wantoptions[u]; if (wo->hisaddr == 0 && !pcb->settings.noremoteip) { /* make up an arbitrary address for the peer */ wo->hisaddr = htonl(0x0a707070 + ifunit); wo->accept_remote = 1; } if (wo->ouraddr == 0) { /* make up an arbitrary address for us */ wo->ouraddr = htonl(0x0a404040 + ifunit); wo->accept_local = 1; ask_for_local = 0; /* don't tell the peer this address */ } if (!sifaddr(pcb, wo->ouraddr, wo->hisaddr, get_mask(wo->ouraddr))) return 0; if (!sifup(pcb)) return 0; if (!sifnpmode(pcb, PPP_IP, NPMODE_QUEUE)) return 0; #if 0 /* UNUSED */ if (wo->default_route) if (sifdefaultroute(pcb, wo->ouraddr, wo->hisaddr, wo->replace_default_route)) default_route_set[u] = 1; #endif /* UNUSED */ if (wo->proxy_arp) if (sifproxyarp(pcb, wo->hisaddr)) proxy_arp_set[u] = 1; ppp_notice("local IP address %I", wo->ouraddr); if (wo->hisaddr) ppp_notice("remote IP address %I", wo->hisaddr); return 1; } #endif /* DEMAND_SUPPORT */ /* * ipcp_up - IPCP has come UP. * * Configure the IP network interface appropriately and bring it up. */ static void ipcp_up(fsm *f) { ppp_pcb *pcb = f->pcb; u32_t mask; ipcp_options *ho = &pcb->ipcp_hisoptions; ipcp_options *go = &pcb->ipcp_gotoptions; ipcp_options *wo = &pcb->ipcp_wantoptions; IPCPDEBUG(("ipcp: up")); /* * We must have a non-zero IP address for both ends of the link. */ if (!ho->neg_addr && !ho->old_addrs) ho->hisaddr = wo->hisaddr; if (!(go->neg_addr || go->old_addrs) && (wo->neg_addr || wo->old_addrs) && wo->ouraddr != 0) { ppp_error("Peer refused to agree to our IP address"); ipcp_close(f->pcb, "Refused our IP address"); return; } if (go->ouraddr == 0) { ppp_error("Could not determine local IP address"); ipcp_close(f->pcb, "Could not determine local IP address"); return; } if (ho->hisaddr == 0 && !pcb->settings.noremoteip) { ho->hisaddr = htonl(0x0a404040); ppp_warn("Could not determine remote IP address: defaulting to %I", ho->hisaddr); } #if 0 /* UNUSED */ script_setenv("IPLOCAL", ip_ntoa(go->ouraddr), 0); if (ho->hisaddr != 0) script_setenv("IPREMOTE", ip_ntoa(ho->hisaddr), 1); #endif /* UNUSED */ if (!go->req_dns1) go->dnsaddr[0] = 0; if (!go->req_dns2) go->dnsaddr[1] = 0; #if 0 /* UNUSED */ if (go->dnsaddr[0]) script_setenv("DNS1", ip_ntoa(go->dnsaddr[0]), 0); if (go->dnsaddr[1]) script_setenv("DNS2", ip_ntoa(go->dnsaddr[1]), 0); #endif /* UNUSED */ if (pcb->settings.usepeerdns && (go->dnsaddr[0] || go->dnsaddr[1])) { sdns(pcb, go->dnsaddr[0], go->dnsaddr[1]); #if 0 /* UNUSED */ script_setenv("USEPEERDNS", "1", 0); create_resolv(go->dnsaddr[0], go->dnsaddr[1]); #endif /* UNUSED */ } /* FIXME: check why it fails, just to know */ #if 0 /* Unused */ /* * Check that the peer is allowed to use the IP address it wants. */ if (ho->hisaddr != 0 && !auth_ip_addr(f->unit, ho->hisaddr)) { ppp_error("Peer is not authorized to use remote address %I", ho->hisaddr); ipcp_close(f->unit, "Unauthorized remote IP address"); return; } #endif /* Unused */ /* set tcp compression */ sifvjcomp(pcb, ho->neg_vj, ho->cflag, ho->maxslotindex); #if DEMAND_SUPPORT /* * If we are doing dial-on-demand, the interface is already * configured, so we put out any saved-up packets, then set the * interface to pass IP packets. */ if (demand) { if (go->ouraddr != wo->ouraddr || ho->hisaddr != wo->hisaddr) { ipcp_clear_addrs(f->unit, wo->ouraddr, wo->hisaddr, wo->replace_default_route); if (go->ouraddr != wo->ouraddr) { ppp_warn("Local IP address changed to %I", go->ouraddr); script_setenv("OLDIPLOCAL", ip_ntoa(wo->ouraddr), 0); wo->ouraddr = go->ouraddr; } else script_unsetenv("OLDIPLOCAL"); if (ho->hisaddr != wo->hisaddr && wo->hisaddr != 0) { ppp_warn("Remote IP address changed to %I", ho->hisaddr); script_setenv("OLDIPREMOTE", ip_ntoa(wo->hisaddr), 0); wo->hisaddr = ho->hisaddr; } else script_unsetenv("OLDIPREMOTE"); /* Set the interface to the new addresses */ mask = get_mask(go->ouraddr); if (!sifaddr(pcb, go->ouraddr, ho->hisaddr, mask)) { #if PPP_DEBUG ppp_warn("Interface configuration failed"); #endif /* PPP_DEBUG */ ipcp_close(f->unit, "Interface configuration failed"); return; } /* assign a default route through the interface if required */ if (ipcp_wantoptions[f->unit].default_route) if (sifdefaultroute(pcb, go->ouraddr, ho->hisaddr, wo->replace_default_route)) default_route_set[f->unit] = 1; /* Make a proxy ARP entry if requested. */ if (ho->hisaddr != 0 && ipcp_wantoptions[f->unit].proxy_arp) if (sifproxyarp(pcb, ho->hisaddr)) proxy_arp_set[f->unit] = 1; } demand_rexmit(PPP_IP,go->ouraddr); sifnpmode(pcb, PPP_IP, NPMODE_PASS); } else #endif /* DEMAND_SUPPORT */ { /* * Set IP addresses and (if specified) netmask. */ mask = get_mask(go->ouraddr); #if !(defined(SVR4) && (defined(SNI) || defined(__USLC__))) if (!sifaddr(pcb, go->ouraddr, ho->hisaddr, mask)) { #if PPP_DEBUG ppp_warn("Interface configuration failed"); #endif /* PPP_DEBUG */ ipcp_close(f->pcb, "Interface configuration failed"); return; } #endif /* bring the interface up for IP */ if (!sifup(pcb)) { #if PPP_DEBUG ppp_warn("Interface failed to come up"); #endif /* PPP_DEBUG */ ipcp_close(f->pcb, "Interface configuration failed"); return; } #if (defined(SVR4) && (defined(SNI) || defined(__USLC__))) if (!sifaddr(pcb, go->ouraddr, ho->hisaddr, mask)) { #if PPP_DEBUG ppp_warn("Interface configuration failed"); #endif /* PPP_DEBUG */ ipcp_close(f->unit, "Interface configuration failed"); return; } #endif sifnpmode(pcb, PPP_IP, NPMODE_PASS); #if 0 /* UNUSED */ /* assign a default route through the interface if required */ if (wo->default_route) if (sifdefaultroute(pcb, go->ouraddr, ho->hisaddr, wo->replace_default_route)) pcb->default_route_set = 1; #endif /* UNUSED */ /* Make a proxy ARP entry if requested. */ if (ho->hisaddr != 0 && wo->proxy_arp) if (sifproxyarp(pcb, ho->hisaddr)) pcb->proxy_arp_set = 1; wo->ouraddr = go->ouraddr; ppp_notice("local IP address %I", go->ouraddr); if (ho->hisaddr != 0) ppp_notice("remote IP address %I", ho->hisaddr); if (go->dnsaddr[0]) ppp_notice("primary DNS address %I", go->dnsaddr[0]); if (go->dnsaddr[1]) ppp_notice("secondary DNS address %I", go->dnsaddr[1]); } #if PPP_STATS_SUPPORT reset_link_stats(f->unit); #endif /* PPP_STATS_SUPPORT */ np_up(pcb, PPP_IP); pcb->ipcp_is_up = 1; #if PPP_NOTIFY notify(ip_up_notifier, 0); #endif /* PPP_NOTIFY */ #if 0 /* UNUSED */ if (ip_up_hook) ip_up_hook(); #endif /* UNUSED */ } /* * ipcp_down - IPCP has gone DOWN. * * Take the IP network interface down, clear its addresses * and delete routes through it. */ static void ipcp_down(fsm *f) { ppp_pcb *pcb = f->pcb; ipcp_options *ho = &pcb->ipcp_hisoptions; ipcp_options *go = &pcb->ipcp_gotoptions; IPCPDEBUG(("ipcp: down")); #if PPP_STATS_SUPPORT /* XXX a bit IPv4-centric here, we only need to get the stats * before the interface is marked down. */ /* XXX more correct: we must get the stats before running the notifiers, * at least for the radius plugin */ update_link_stats(f->unit); #endif /* PPP_STATS_SUPPORT */ #if PPP_NOTIFY notify(ip_down_notifier, 0); #endif /* PPP_NOTIFY */ #if 0 /* UNUSED */ if (ip_down_hook) ip_down_hook(); #endif /* UNUSED */ if (pcb->ipcp_is_up) { pcb->ipcp_is_up = 0; np_down(pcb, PPP_IP); } sifvjcomp(pcb, 0, 0, 0); #if PPP_STATS_SUPPORT print_link_stats(); /* _after_ running the notifiers and ip_down_hook(), * because print_link_stats() sets link_stats_valid * to 0 (zero) */ #endif /* PPP_STATS_SUPPORT */ #if DEMAND_SUPPORT /* * If we are doing dial-on-demand, set the interface * to queue up outgoing packets (for now). */ if (demand) { sifnpmode(pcb, PPP_IP, NPMODE_QUEUE); } else #endif /* DEMAND_SUPPORT */ { sifnpmode(pcb, PPP_IP, NPMODE_DROP); sifdown(pcb); ipcp_clear_addrs(pcb, go->ouraddr, ho->hisaddr, 0); cdns(pcb, go->dnsaddr[0], go->dnsaddr[1]); } } /* * ipcp_clear_addrs() - clear the interface addresses, routes, * proxy arp entries, etc. */ static void ipcp_clear_addrs(ppp_pcb *pcb, u32_t ouraddr, u32_t hisaddr, u8_t replacedefaultroute) { if (pcb->proxy_arp_set) { cifproxyarp(pcb, hisaddr); pcb->proxy_arp_set = 0; } #if 0 /* UNUSED */ /* If replacedefaultroute, sifdefaultroute will be called soon * with replacedefaultroute set and that will overwrite the current * default route. This is the case only when doing demand, otherwise * during demand, this cifdefaultroute would restore the old default * route which is not what we want in this case. In the non-demand * case, we'll delete the default route and restore the old if there * is one saved by an sifdefaultroute with replacedefaultroute. */ if (!replacedefaultroute && pcb->default_route_set) { cifdefaultroute(pcb, ouraddr, hisaddr); pcb->default_route_set = 0; } #endif /* UNUSED */ cifaddr(pcb, ouraddr, hisaddr); } /* * ipcp_finished - possibly shut down the lower layers. */ static void ipcp_finished(fsm *f) { ppp_pcb *pcb = f->pcb; if (pcb->ipcp_is_open) { pcb->ipcp_is_open = 0; np_finished(pcb, PPP_IP); } } #if 0 /* UNUSED */ /* * create_resolv - create the replacement resolv.conf file */ static void create_resolv(peerdns1, peerdns2) u32_t peerdns1, peerdns2; { } #endif /* UNUSED */ #if PRINTPKT_SUPPORT /* * ipcp_printpkt - print the contents of an IPCP packet. */ static char *ipcp_codenames[] = { "ConfReq", "ConfAck", "ConfNak", "ConfRej", "TermReq", "TermAck", "CodeRej" }; static int ipcp_printpkt(u_char *p, int plen, void (*printer) (void *, char *, ...), void *arg) { int code, id, len, olen; u_char *pstart, *optend; u_short cishort; u32_t cilong; if (plen < HEADERLEN) return 0; pstart = p; GETCHAR(code, p); GETCHAR(id, p); GETSHORT(len, p); if (len < HEADERLEN || len > plen) return 0; if (code >= 1 && code <= sizeof(ipcp_codenames) / sizeof(char *)) printer(arg, " %s", ipcp_codenames[code-1]); else printer(arg, " code=0x%x", code); printer(arg, " id=0x%x", id); len -= HEADERLEN; switch (code) { case CONFREQ: case CONFACK: case CONFNAK: case CONFREJ: /* print option list */ while (len >= 2) { GETCHAR(code, p); GETCHAR(olen, p); p -= 2; if (olen < 2 || olen > len) { break; } printer(arg, " <"); len -= olen; optend = p + olen; switch (code) { case CI_ADDRS: if (olen == CILEN_ADDRS) { p += 2; GETLONG(cilong, p); printer(arg, "addrs %I", htonl(cilong)); GETLONG(cilong, p); printer(arg, " %I", htonl(cilong)); } break; case CI_COMPRESSTYPE: if (olen >= CILEN_COMPRESS) { p += 2; GETSHORT(cishort, p); printer(arg, "compress "); switch (cishort) { case IPCP_VJ_COMP: printer(arg, "VJ"); break; case IPCP_VJ_COMP_OLD: printer(arg, "old-VJ"); break; default: printer(arg, "0x%x", cishort); } } break; case CI_ADDR: if (olen == CILEN_ADDR) { p += 2; GETLONG(cilong, p); printer(arg, "addr %I", htonl(cilong)); } break; case CI_MS_DNS1: case CI_MS_DNS2: p += 2; GETLONG(cilong, p); printer(arg, "ms-dns%d %I", (code == CI_MS_DNS1? 1: 2), htonl(cilong)); break; case CI_MS_WINS1: case CI_MS_WINS2: p += 2; GETLONG(cilong, p); printer(arg, "ms-wins %I", htonl(cilong)); break; } while (p < optend) { GETCHAR(code, p); printer(arg, " %.2x", code); } printer(arg, ">"); } break; case TERMACK: case TERMREQ: if (len > 0 && *p >= ' ' && *p < 0x7f) { printer(arg, " "); ppp_print_string((char *)p, len, printer, arg); p += len; len = 0; } break; } /* print the rest of the bytes in the packet */ for (; len > 0; --len) { GETCHAR(code, p); printer(arg, " %.2x", code); } return p - pstart; } #endif /* PRINTPKT_SUPPORT */ #if DEMAND_SUPPORT /* * ip_active_pkt - see if this IP packet is worth bringing the link up for. * We don't bring the link up for IP fragments or for TCP FIN packets * with no data. */ #define IP_HDRLEN 20 /* bytes */ #define IP_OFFMASK 0x1fff #ifndef IPPROTO_TCP #define IPPROTO_TCP 6 #endif #define TCP_HDRLEN 20 #define TH_FIN 0x01 /* * We use these macros because the IP header may be at an odd address, * and some compilers might use word loads to get th_off or ip_hl. */ #define net_short(x) (((x)[0] << 8) + (x)[1]) #define get_iphl(x) (((unsigned char *)(x))[0] & 0xF) #define get_ipoff(x) net_short((unsigned char *)(x) + 6) #define get_ipproto(x) (((unsigned char *)(x))[9]) #define get_tcpoff(x) (((unsigned char *)(x))[12] >> 4) #define get_tcpflags(x) (((unsigned char *)(x))[13]) static int ip_active_pkt(pkt, len) u_char *pkt; int len; { u_char *tcp; int hlen; len -= PPP_HDRLEN; pkt += PPP_HDRLEN; if (len < IP_HDRLEN) return 0; if ((get_ipoff(pkt) & IP_OFFMASK) != 0) return 0; if (get_ipproto(pkt) != IPPROTO_TCP) return 1; hlen = get_iphl(pkt) * 4; if (len < hlen + TCP_HDRLEN) return 0; tcp = pkt + hlen; if ((get_tcpflags(tcp) & TH_FIN) != 0 && len == hlen + get_tcpoff(tcp) * 4) return 0; return 1; } #endif /* DEMAND_SUPPORT */ #endif /* PPP_SUPPORT */ ocproxy-1.60/lwip/src/netif/ppp/ipv6cp.c000066400000000000000000001200531303453231400201630ustar00rootroot00000000000000/* * ipv6cp.c - PPP IPV6 Control Protocol. * * Copyright (c) 1999 Tommi Komulainen. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The name(s) of the authors of this software must not be used to * endorse or promote products derived from this software without * prior written permission. * * 4. Redistributions of any form whatsoever must retain the following * acknowledgment: * "This product includes software developed by Tommi Komulainen * ". * * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * */ /* Original version, based on RFC2023 : Copyright (c) 1995, 1996, 1997 Francis.Dupont@inria.fr, INRIA Rocquencourt, Alain.Durand@imag.fr, IMAG, Jean-Luc.Richier@imag.fr, IMAG-LSR. Copyright (c) 1998, 1999 Francis.Dupont@inria.fr, GIE DYADE, Alain.Durand@imag.fr, IMAG, Jean-Luc.Richier@imag.fr, IMAG-LSR. Ce travail a été fait au sein du GIE DYADE (Groupement d'Intérêt Économique ayant pour membres BULL S.A. et l'INRIA). Ce logiciel informatique est disponible aux conditions usuelles dans la recherche, c'est-à-dire qu'il peut être utilisé, copié, modifié, distribué à l'unique condition que ce texte soit conservé afin que l'origine de ce logiciel soit reconnue. Le nom de l'Institut National de Recherche en Informatique et en Automatique (INRIA), de l'IMAG, ou d'une personne morale ou physique ayant participé à l'élaboration de ce logiciel ne peut être utilisé sans son accord préalable explicite. Ce logiciel est fourni tel quel sans aucune garantie, support ou responsabilité d'aucune sorte. Ce logiciel est dérivé de sources d'origine "University of California at Berkeley" et "Digital Equipment Corporation" couvertes par des copyrights. L'Institut d'Informatique et de Mathématiques Appliquées de Grenoble (IMAG) est une fédération d'unités mixtes de recherche du CNRS, de l'Institut National Polytechnique de Grenoble et de l'Université Joseph Fourier regroupant sept laboratoires dont le laboratoire Logiciels, Systèmes, Réseaux (LSR). This work has been done in the context of GIE DYADE (joint R & D venture between BULL S.A. and INRIA). This software is available with usual "research" terms with the aim of retain credits of the software. Permission to use, copy, modify and distribute this software for any purpose and without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies, and the name of INRIA, IMAG, or any contributor not be used in advertising or publicity pertaining to this material without the prior explicit permission. The software is provided "as is" without any warranties, support or liabilities of any kind. This software is derived from source code from "University of California at Berkeley" and "Digital Equipment Corporation" protected by copyrights. Grenoble's Institute of Computer Science and Applied Mathematics (IMAG) is a federation of seven research units funded by the CNRS, National Polytechnic Institute of Grenoble and University Joseph Fourier. The research unit in Software, Systems, Networks (LSR) is member of IMAG. */ /* * Derived from : * * * ipcp.c - PPP IP Control Protocol. * * Copyright (c) 1984-2000 Carnegie Mellon University. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The name "Carnegie Mellon University" must not be used to * endorse or promote products derived from this software without * prior written permission. For permission or any legal * details, please contact * Office of Technology Transfer * Carnegie Mellon University * 5000 Forbes Avenue * Pittsburgh, PA 15213-3890 * (412) 268-4387, fax: (412) 268-7395 * tech-transfer@andrew.cmu.edu * * 4. Redistributions of any form whatsoever must retain the following * acknowledgment: * "This product includes software developed by Computing Services * at Carnegie Mellon University (http://www.cmu.edu/computing/)." * * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * $Id: ipv6cp.c,v 1.21 2005/08/25 23:59:34 paulus Exp $ */ /* * TODO: * * Proxy Neighbour Discovery. * * Better defines for selecting the ordering of * interface up / set address. (currently checks for __linux__, * since SVR4 && (SNI || __USLC__) didn't work properly) */ #include "lwip/opt.h" #if PPP_SUPPORT && PPP_IPV6_SUPPORT /* don't build if not configured for use in lwipopts.h */ #if 0 /* UNUSED */ #include #include #include #include #include #include #include #include #include #endif /* UNUSED */ #include "netif/ppp/ppp_impl.h" #include "netif/ppp/fsm.h" #include "netif/ppp/ipcp.h" #include "netif/ppp/ipv6cp.h" #include "netif/ppp/magic.h" /* global vars */ #if 0 /* UNUSED */ int no_ifaceid_neg = 0; #endif /* UNUSED */ /* * Callbacks for fsm code. (CI = Configuration Information) */ static void ipv6cp_resetci(fsm *f); /* Reset our CI */ static int ipv6cp_cilen(fsm *f); /* Return length of our CI */ static void ipv6cp_addci(fsm *f, u_char *ucp, int *lenp); /* Add our CI */ static int ipv6cp_ackci(fsm *f, u_char *p, int len); /* Peer ack'd our CI */ static int ipv6cp_nakci(fsm *f, u_char *p, int len, int treat_as_reject); /* Peer nak'd our CI */ static int ipv6cp_rejci(fsm *f, u_char *p, int len); /* Peer rej'd our CI */ static int ipv6cp_reqci(fsm *f, u_char *inp, int *len, int reject_if_disagree); /* Rcv CI */ static void ipv6cp_up(fsm *f); /* We're UP */ static void ipv6cp_down(fsm *f); /* We're DOWN */ static void ipv6cp_finished(fsm *f); /* Don't need lower layer */ static const fsm_callbacks ipv6cp_callbacks = { /* IPV6CP callback routines */ ipv6cp_resetci, /* Reset our Configuration Information */ ipv6cp_cilen, /* Length of our Configuration Information */ ipv6cp_addci, /* Add our Configuration Information */ ipv6cp_ackci, /* ACK our Configuration Information */ ipv6cp_nakci, /* NAK our Configuration Information */ ipv6cp_rejci, /* Reject our Configuration Information */ ipv6cp_reqci, /* Request peer's Configuration Information */ ipv6cp_up, /* Called when fsm reaches OPENED state */ ipv6cp_down, /* Called when fsm leaves OPENED state */ NULL, /* Called when we want the lower layer up */ ipv6cp_finished, /* Called when we want the lower layer down */ NULL, /* Called when Protocol-Reject received */ NULL, /* Retransmission is necessary */ NULL, /* Called to handle protocol-specific codes */ "IPV6CP" /* String name of protocol */ }; #if PPP_OPTIONS /* * Command-line options. */ static int setifaceid(char **arg)); static void printifaceid(option_t *, void (*)(void *, char *, ...), void *)); static option_t ipv6cp_option_list[] = { { "ipv6", o_special, (void *)setifaceid, "Set interface identifiers for IPV6", OPT_A2PRINTER, (void *)printifaceid }, { "+ipv6", o_bool, &ipv6cp_protent.enabled_flag, "Enable IPv6 and IPv6CP", OPT_PRIO | 1 }, { "noipv6", o_bool, &ipv6cp_protent.enabled_flag, "Disable IPv6 and IPv6CP", OPT_PRIOSUB }, { "-ipv6", o_bool, &ipv6cp_protent.enabled_flag, "Disable IPv6 and IPv6CP", OPT_PRIOSUB | OPT_ALIAS }, { "ipv6cp-accept-local", o_bool, &ipv6cp_allowoptions[0].accept_local, "Accept peer's interface identifier for us", 1 }, { "ipv6cp-use-ipaddr", o_bool, &ipv6cp_allowoptions[0].use_ip, "Use (default) IPv4 address as interface identifier", 1 }, #if defined(SOL2) || defined(__linux__) { "ipv6cp-use-persistent", o_bool, &ipv6cp_wantoptions[0].use_persistent, "Use uniquely-available persistent value for link local address", 1 }, #endif /* defined(SOL2) */ { "ipv6cp-restart", o_int, &ipv6cp_fsm[0].timeouttime, "Set timeout for IPv6CP", OPT_PRIO }, { "ipv6cp-max-terminate", o_int, &ipv6cp_fsm[0].maxtermtransmits, "Set max #xmits for term-reqs", OPT_PRIO }, { "ipv6cp-max-configure", o_int, &ipv6cp_fsm[0].maxconfreqtransmits, "Set max #xmits for conf-reqs", OPT_PRIO }, { "ipv6cp-max-failure", o_int, &ipv6cp_fsm[0].maxnakloops, "Set max #conf-naks for IPv6CP", OPT_PRIO }, { NULL } }; #endif /* PPP_OPTIONS */ /* * Protocol entry points from main code. */ static void ipv6cp_init(ppp_pcb *pcb); static void ipv6cp_open(ppp_pcb *pcb); static void ipv6cp_close(ppp_pcb *pcb, char *reason); static void ipv6cp_lowerup(ppp_pcb *pcb); static void ipv6cp_lowerdown(ppp_pcb *pcb); static void ipv6cp_input(ppp_pcb *pcb, u_char *p, int len); static void ipv6cp_protrej(ppp_pcb *pcb); #if PPP_OPTIONS static void ipv6_check_options(void); #endif /* PPP_OPTIONS */ #if DEMAND_SUPPORT static int ipv6_demand_conf(int u); #endif /* DEMAND_SUPPORT */ #if PRINTPKT_SUPPORT static int ipv6cp_printpkt(u_char *p, int plen, void (*printer)(void *, char *, ...), void *arg); #endif /* PRINTPKT_SUPPORT */ #if PPP_DEMAND static int ipv6_active_pkt(u_char *pkt, int len); #endif /* PPP_DEMAND */ const struct protent ipv6cp_protent = { PPP_IPV6CP, ipv6cp_init, ipv6cp_input, ipv6cp_protrej, ipv6cp_lowerup, ipv6cp_lowerdown, ipv6cp_open, ipv6cp_close, #if PRINTPKT_SUPPORT ipv6cp_printpkt, #endif /* PRINTPKT_SUPPORT */ NULL, 1, #if PRINTPKT_SUPPORT "IPV6CP", "IPV6", #endif /* PRINTPKT_SUPPORT */ #if PPP_OPTIONS ipv6cp_option_list, ipv6_check_options, #endif /* PPP_OPTIONS */ #if DEMAND_SUPPORT ipv6_demand_conf, ipv6_active_pkt #endif /* DEMAND_SUPPORT */ }; static void ipv6cp_clear_addrs(ppp_pcb *pcb, eui64_t ourid, eui64_t hisid); #if 0 /* UNUSED */ static void ipv6cp_script(char *)); static void ipv6cp_script_done(void *)); #endif /* UNUSED */ /* * Lengths of configuration options. */ #define CILEN_VOID 2 #define CILEN_COMPRESS 4 /* length for RFC2023 compress opt. */ #define CILEN_IFACEID 10 /* RFC2472, interface identifier */ #define CODENAME(x) ((x) == CONFACK ? "ACK" : \ (x) == CONFNAK ? "NAK" : "REJ") #if 0 /* UNUSED */ /* * This state variable is used to ensure that we don't * run an ipcp-up/down script while one is already running. */ static enum script_state { s_down, s_up, } ipv6cp_script_state; static pid_t ipv6cp_script_pid; #endif /* UNUSED */ #if PPP_OPTIONS /* * setifaceid - set the interface identifiers manually */ static int setifaceid(argv) char **argv; { char *comma, *arg, c; ipv6cp_options *wo = &ipv6cp_wantoptions[0]; struct in6_addr addr; static int prio_local, prio_remote; #define VALIDID(a) ( (((a).s6_addr32[0] == 0) && ((a).s6_addr32[1] == 0)) && \ (((a).s6_addr32[2] != 0) || ((a).s6_addr32[3] != 0)) ) arg = *argv; if ((comma = strchr(arg, ',')) == NULL) comma = arg + strlen(arg); /* * If comma first character, then no local identifier */ if (comma != arg) { c = *comma; *comma = '\0'; if (inet_pton(AF_INET6, arg, &addr) == 0 || !VALIDID(addr)) { option_error("Illegal interface identifier (local): %s", arg); return 0; } if (option_priority >= prio_local) { eui64_copy(addr.s6_addr32[2], wo->ourid); wo->opt_local = 1; prio_local = option_priority; } *comma = c; } /* * If comma last character, the no remote identifier */ if (*comma != 0 && *++comma != '\0') { if (inet_pton(AF_INET6, comma, &addr) == 0 || !VALIDID(addr)) { option_error("Illegal interface identifier (remote): %s", comma); return 0; } if (option_priority >= prio_remote) { eui64_copy(addr.s6_addr32[2], wo->hisid); wo->opt_remote = 1; prio_remote = option_priority; } } if (override_value("+ipv6", option_priority, option_source)) ipv6cp_protent.enabled_flag = 1; return 1; } char *llv6_ntoa(eui64_t ifaceid); static void printifaceid(opt, printer, arg) option_t *opt; void (*printer)(void *, char *, ...)); void *arg; { ipv6cp_options *wo = &ipv6cp_wantoptions[0]; if (wo->opt_local) printer(arg, "%s", llv6_ntoa(wo->ourid)); printer(arg, ","); if (wo->opt_remote) printer(arg, "%s", llv6_ntoa(wo->hisid)); } #endif /* PPP_OPTIONS */ /* * Make a string representation of a network address. */ char * llv6_ntoa(ifaceid) eui64_t ifaceid; { static char b[64]; sprintf(b, "fe80::%s", eui64_ntoa(ifaceid)); return b; } /* * ipv6cp_init - Initialize IPV6CP. */ static void ipv6cp_init(ppp_pcb *pcb) { fsm *f = &pcb->ipv6cp_fsm; ipv6cp_options *wo = &pcb->ipv6cp_wantoptions; ipv6cp_options *ao = &pcb->ipv6cp_allowoptions; f->pcb = pcb; f->protocol = PPP_IPV6CP; f->callbacks = &ipv6cp_callbacks; fsm_init(f); memset(wo, 0, sizeof(*wo)); memset(ao, 0, sizeof(*ao)); wo->accept_local = 1; wo->neg_ifaceid = 1; ao->neg_ifaceid = 1; #ifdef IPV6CP_COMP wo->neg_vj = 1; ao->neg_vj = 1; wo->vj_protocol = IPV6CP_COMP; #endif } /* * ipv6cp_open - IPV6CP is allowed to come up. */ static void ipv6cp_open(ppp_pcb *pcb) { fsm_open(&pcb->ipv6cp_fsm); } /* * ipv6cp_close - Take IPV6CP down. */ static void ipv6cp_close(ppp_pcb *pcb, char *reason) { fsm_close(&pcb->ipv6cp_fsm, reason); } /* * ipv6cp_lowerup - The lower layer is up. */ static void ipv6cp_lowerup(ppp_pcb *pcb) { fsm_lowerup(&pcb->ipv6cp_fsm); } /* * ipv6cp_lowerdown - The lower layer is down. */ static void ipv6cp_lowerdown(ppp_pcb *pcb) { fsm_lowerdown(&pcb->ipv6cp_fsm); } /* * ipv6cp_input - Input IPV6CP packet. */ static void ipv6cp_input(ppp_pcb *pcb, u_char *p, int len) { fsm_input(&pcb->ipv6cp_fsm, p, len); } /* * ipv6cp_protrej - A Protocol-Reject was received for IPV6CP. * * Pretend the lower layer went down, so we shut up. */ static void ipv6cp_protrej(ppp_pcb *pcb) { fsm_lowerdown(&pcb->ipv6cp_fsm); } /* * ipv6cp_resetci - Reset our CI. */ static void ipv6cp_resetci(fsm *f) { ppp_pcb *pcb = f->pcb; ipv6cp_options *wo = &pcb->ipv6cp_wantoptions; ipv6cp_options *go = &pcb->ipv6cp_gotoptions; ipv6cp_options *ao = &pcb->ipv6cp_allowoptions; wo->req_ifaceid = wo->neg_ifaceid && ao->neg_ifaceid; if (!wo->opt_local) { eui64_magic_nz(wo->ourid); } *go = *wo; eui64_zero(go->hisid); /* last proposed interface identifier */ } /* * ipv6cp_cilen - Return length of our CI. */ static int ipv6cp_cilen(fsm *f) { ppp_pcb *pcb = f->pcb; ipv6cp_options *go = &pcb->ipv6cp_gotoptions; #define LENCIVJ(neg) (neg ? CILEN_COMPRESS : 0) #define LENCIIFACEID(neg) (neg ? CILEN_IFACEID : 0) return (LENCIIFACEID(go->neg_ifaceid) + LENCIVJ(go->neg_vj)); } /* * ipv6cp_addci - Add our desired CIs to a packet. */ static void ipv6cp_addci(fsm *f, u_char *ucp, int *lenp) { ppp_pcb *pcb = f->pcb; ipv6cp_options *go = &pcb->ipv6cp_gotoptions; int len = *lenp; #define ADDCIVJ(opt, neg, val) \ if (neg) { \ int vjlen = CILEN_COMPRESS; \ if (len >= vjlen) { \ PUTCHAR(opt, ucp); \ PUTCHAR(vjlen, ucp); \ PUTSHORT(val, ucp); \ len -= vjlen; \ } else \ neg = 0; \ } #define ADDCIIFACEID(opt, neg, val1) \ if (neg) { \ int idlen = CILEN_IFACEID; \ if (len >= idlen) { \ PUTCHAR(opt, ucp); \ PUTCHAR(idlen, ucp); \ eui64_put(val1, ucp); \ len -= idlen; \ } else \ neg = 0; \ } ADDCIIFACEID(CI_IFACEID, go->neg_ifaceid, go->ourid); ADDCIVJ(CI_COMPRESSTYPE, go->neg_vj, go->vj_protocol); *lenp -= len; } /* * ipv6cp_ackci - Ack our CIs. * * Returns: * 0 - Ack was bad. * 1 - Ack was good. */ static int ipv6cp_ackci(fsm *f, u_char *p, int len) { ppp_pcb *pcb = f->pcb; ipv6cp_options *go = &pcb->ipv6cp_gotoptions; u_short cilen, citype, cishort; eui64_t ifaceid; /* * CIs must be in exactly the same order that we sent... * Check packet length and CI length at each step. * If we find any deviations, then this packet is bad. */ #define ACKCIVJ(opt, neg, val) \ if (neg) { \ int vjlen = CILEN_COMPRESS; \ if ((len -= vjlen) < 0) \ goto bad; \ GETCHAR(citype, p); \ GETCHAR(cilen, p); \ if (cilen != vjlen || \ citype != opt) \ goto bad; \ GETSHORT(cishort, p); \ if (cishort != val) \ goto bad; \ } #define ACKCIIFACEID(opt, neg, val1) \ if (neg) { \ int idlen = CILEN_IFACEID; \ if ((len -= idlen) < 0) \ goto bad; \ GETCHAR(citype, p); \ GETCHAR(cilen, p); \ if (cilen != idlen || \ citype != opt) \ goto bad; \ eui64_get(ifaceid, p); \ if (! eui64_equals(val1, ifaceid)) \ goto bad; \ } ACKCIIFACEID(CI_IFACEID, go->neg_ifaceid, go->ourid); ACKCIVJ(CI_COMPRESSTYPE, go->neg_vj, go->vj_protocol); /* * If there are any remaining CIs, then this packet is bad. */ if (len != 0) goto bad; return (1); bad: IPV6CPDEBUG(("ipv6cp_ackci: received bad Ack!")); return (0); } /* * ipv6cp_nakci - Peer has sent a NAK for some of our CIs. * This should not modify any state if the Nak is bad * or if IPV6CP is in the OPENED state. * * Returns: * 0 - Nak was bad. * 1 - Nak was good. */ static int ipv6cp_nakci(fsm *f, u_char *p, int len, int treat_as_reject) { ppp_pcb *pcb = f->pcb; ipv6cp_options *go = &pcb->ipv6cp_gotoptions; u_char citype, cilen, *next; u_short cishort; eui64_t ifaceid; ipv6cp_options no; /* options we've seen Naks for */ ipv6cp_options try; /* options to request next time */ BZERO(&no, sizeof(no)); try = *go; /* * Any Nak'd CIs must be in exactly the same order that we sent. * Check packet length and CI length at each step. * If we find any deviations, then this packet is bad. */ #define NAKCIIFACEID(opt, neg, code) \ if (go->neg && \ len >= (cilen = CILEN_IFACEID) && \ p[1] == cilen && \ p[0] == opt) { \ len -= cilen; \ INCPTR(2, p); \ eui64_get(ifaceid, p); \ no.neg = 1; \ code \ } #define NAKCIVJ(opt, neg, code) \ if (go->neg && \ ((cilen = p[1]) == CILEN_COMPRESS) && \ len >= cilen && \ p[0] == opt) { \ len -= cilen; \ INCPTR(2, p); \ GETSHORT(cishort, p); \ no.neg = 1; \ code \ } /* * Accept the peer's idea of {our,his} interface identifier, if different * from our idea, only if the accept_{local,remote} flag is set. */ NAKCIIFACEID(CI_IFACEID, neg_ifaceid, if (treat_as_reject) { try.neg_ifaceid = 0; } else if (go->accept_local) { while (eui64_iszero(ifaceid) || eui64_equals(ifaceid, go->hisid)) /* bad luck */ eui64_magic(ifaceid); try.ourid = ifaceid; IPV6CPDEBUG(("local LL address %s", llv6_ntoa(ifaceid))); } ); #ifdef IPV6CP_COMP NAKCIVJ(CI_COMPRESSTYPE, neg_vj, { if (cishort == IPV6CP_COMP && !treat_as_reject) { try.vj_protocol = cishort; } else { try.neg_vj = 0; } } ); #else NAKCIVJ(CI_COMPRESSTYPE, neg_vj, { try.neg_vj = 0; } ); #endif /* * There may be remaining CIs, if the peer is requesting negotiation * on an option that we didn't include in our request packet. * If they want to negotiate about interface identifier, we comply. * If they want us to ask for compression, we refuse. */ while (len >= CILEN_VOID) { GETCHAR(citype, p); GETCHAR(cilen, p); if ( cilen < CILEN_VOID || (len -= cilen) < 0 ) goto bad; next = p + cilen - 2; switch (citype) { case CI_COMPRESSTYPE: if (go->neg_vj || no.neg_vj || (cilen != CILEN_COMPRESS)) goto bad; no.neg_vj = 1; break; case CI_IFACEID: if (go->neg_ifaceid || no.neg_ifaceid || cilen != CILEN_IFACEID) goto bad; try.neg_ifaceid = 1; eui64_get(ifaceid, p); if (go->accept_local) { while (eui64_iszero(ifaceid) || eui64_equals(ifaceid, go->hisid)) /* bad luck */ eui64_magic(ifaceid); try.ourid = ifaceid; } no.neg_ifaceid = 1; break; } p = next; } /* If there is still anything left, this packet is bad. */ if (len != 0) goto bad; /* * OK, the Nak is good. Now we can update state. */ if (f->state != PPP_FSM_OPENED) *go = try; return 1; bad: IPV6CPDEBUG(("ipv6cp_nakci: received bad Nak!")); return 0; } /* * ipv6cp_rejci - Reject some of our CIs. */ static int ipv6cp_rejci(fsm *f, u_char *p, int len) { ppp_pcb *pcb = f->pcb; ipv6cp_options *go = &pcb->ipv6cp_gotoptions; u_char cilen; u_short cishort; eui64_t ifaceid; ipv6cp_options try; /* options to request next time */ try = *go; /* * Any Rejected CIs must be in exactly the same order that we sent. * Check packet length and CI length at each step. * If we find any deviations, then this packet is bad. */ #define REJCIIFACEID(opt, neg, val1) \ if (go->neg && \ len >= (cilen = CILEN_IFACEID) && \ p[1] == cilen && \ p[0] == opt) { \ len -= cilen; \ INCPTR(2, p); \ eui64_get(ifaceid, p); \ /* Check rejected value. */ \ if (! eui64_equals(ifaceid, val1)) \ goto bad; \ try.neg = 0; \ } #define REJCIVJ(opt, neg, val) \ if (go->neg && \ p[1] == CILEN_COMPRESS && \ len >= p[1] && \ p[0] == opt) { \ len -= p[1]; \ INCPTR(2, p); \ GETSHORT(cishort, p); \ /* Check rejected value. */ \ if (cishort != val) \ goto bad; \ try.neg = 0; \ } REJCIIFACEID(CI_IFACEID, neg_ifaceid, go->ourid); REJCIVJ(CI_COMPRESSTYPE, neg_vj, go->vj_protocol); /* * If there are any remaining CIs, then this packet is bad. */ if (len != 0) goto bad; /* * Now we can update state. */ if (f->state != PPP_FSM_OPENED) *go = try; return 1; bad: IPV6CPDEBUG(("ipv6cp_rejci: received bad Reject!")); return 0; } /* * ipv6cp_reqci - Check the peer's requested CIs and send appropriate response. * * Returns: CONFACK, CONFNAK or CONFREJ and input packet modified * appropriately. If reject_if_disagree is non-zero, doesn't return * CONFNAK; returns CONFREJ if it can't return CONFACK. * * inp = Requested CIs * len = Length of requested CIs * */ static int ipv6cp_reqci(fsm *f, u_char *inp, int *len, int reject_if_disagree) { ppp_pcb *pcb = f->pcb; ipv6cp_options *wo = &pcb->ipv6cp_wantoptions; ipv6cp_options *ho = &pcb->ipv6cp_hisoptions; ipv6cp_options *ao = &pcb->ipv6cp_allowoptions; ipv6cp_options *go = &pcb->ipv6cp_gotoptions; u_char *cip, *next; /* Pointer to current and next CIs */ u_short cilen, citype; /* Parsed len, type */ u_short cishort; /* Parsed short value */ eui64_t ifaceid; /* Parsed interface identifier */ int rc = CONFACK; /* Final packet return code */ int orc; /* Individual option return code */ u_char *p; /* Pointer to next char to parse */ u_char *ucp = inp; /* Pointer to current output char */ int l = *len; /* Length left */ /* * Reset all his options. */ BZERO(ho, sizeof(*ho)); /* * Process all his options. */ next = inp; while (l) { orc = CONFACK; /* Assume success */ cip = p = next; /* Remember begining of CI */ if (l < 2 || /* Not enough data for CI header or */ p[1] < 2 || /* CI length too small or */ p[1] > l) { /* CI length too big? */ IPV6CPDEBUG(("ipv6cp_reqci: bad CI length!")); orc = CONFREJ; /* Reject bad CI */ cilen = l; /* Reject till end of packet */ l = 0; /* Don't loop again */ goto endswitch; } GETCHAR(citype, p); /* Parse CI type */ GETCHAR(cilen, p); /* Parse CI length */ l -= cilen; /* Adjust remaining length */ next += cilen; /* Step to next CI */ switch (citype) { /* Check CI type */ case CI_IFACEID: IPV6CPDEBUG(("ipv6cp: received interface identifier ")); if (!ao->neg_ifaceid || cilen != CILEN_IFACEID) { /* Check CI length */ orc = CONFREJ; /* Reject CI */ break; } /* * If he has no interface identifier, or if we both have same * identifier then NAK it with new idea. * In particular, if we don't know his identifier, but he does, * then accept it. */ eui64_get(ifaceid, p); IPV6CPDEBUG(("(%s)", llv6_ntoa(ifaceid))); if (eui64_iszero(ifaceid) && eui64_iszero(go->ourid)) { orc = CONFREJ; /* Reject CI */ break; } if (!eui64_iszero(wo->hisid) && !eui64_equals(ifaceid, wo->hisid) && eui64_iszero(go->hisid)) { orc = CONFNAK; ifaceid = wo->hisid; go->hisid = ifaceid; DECPTR(sizeof(ifaceid), p); eui64_put(ifaceid, p); } else if (eui64_iszero(ifaceid) || eui64_equals(ifaceid, go->ourid)) { orc = CONFNAK; if (eui64_iszero(go->hisid)) /* first time, try option */ ifaceid = wo->hisid; while (eui64_iszero(ifaceid) || eui64_equals(ifaceid, go->ourid)) /* bad luck */ eui64_magic(ifaceid); go->hisid = ifaceid; DECPTR(sizeof(ifaceid), p); eui64_put(ifaceid, p); } ho->neg_ifaceid = 1; ho->hisid = ifaceid; break; case CI_COMPRESSTYPE: IPV6CPDEBUG(("ipv6cp: received COMPRESSTYPE ")); if (!ao->neg_vj || (cilen != CILEN_COMPRESS)) { orc = CONFREJ; break; } GETSHORT(cishort, p); IPV6CPDEBUG(("(%d)", cishort)); #ifdef IPV6CP_COMP if (!(cishort == IPV6CP_COMP)) { orc = CONFREJ; break; } ho->neg_vj = 1; ho->vj_protocol = cishort; break; #else orc = CONFREJ; break; #endif default: orc = CONFREJ; break; } endswitch: IPV6CPDEBUG((" (%s)\n", CODENAME(orc))); if (orc == CONFACK && /* Good CI */ rc != CONFACK) /* but prior CI wasnt? */ continue; /* Don't send this one */ if (orc == CONFNAK) { /* Nak this CI? */ if (reject_if_disagree) /* Getting fed up with sending NAKs? */ orc = CONFREJ; /* Get tough if so */ else { if (rc == CONFREJ) /* Rejecting prior CI? */ continue; /* Don't send this one */ if (rc == CONFACK) { /* Ack'd all prior CIs? */ rc = CONFNAK; /* Not anymore... */ ucp = inp; /* Backup */ } } } if (orc == CONFREJ && /* Reject this CI */ rc != CONFREJ) { /* but no prior ones? */ rc = CONFREJ; ucp = inp; /* Backup */ } /* Need to move CI? */ if (ucp != cip) MEMCPY(ucp, cip, cilen); /* Move it */ /* Update output pointer */ INCPTR(cilen, ucp); } /* * If we aren't rejecting this packet, and we want to negotiate * their identifier and they didn't send their identifier, then we * send a NAK with a CI_IFACEID option appended. We assume the * input buffer is long enough that we can append the extra * option safely. */ if (rc != CONFREJ && !ho->neg_ifaceid && wo->req_ifaceid && !reject_if_disagree) { if (rc == CONFACK) { rc = CONFNAK; ucp = inp; /* reset pointer */ wo->req_ifaceid = 0; /* don't ask again */ } PUTCHAR(CI_IFACEID, ucp); PUTCHAR(CILEN_IFACEID, ucp); eui64_put(wo->hisid, ucp); } *len = ucp - inp; /* Compute output length */ IPV6CPDEBUG(("ipv6cp: returning Configure-%s", CODENAME(rc))); return (rc); /* Return final code */ } #if PPP_OPTION /* * ipv6_check_options - check that any IP-related options are OK, * and assign appropriate defaults. */ static void ipv6_check_options() { ipv6cp_options *wo = &ipv6cp_wantoptions[0]; if (!ipv6cp_protent.enabled_flag) return; #if defined(SOL2) || defined(__linux__) /* * Persistent link-local id is only used when user has not explicitly * configure/hard-code the id */ if ((wo->use_persistent) && (!wo->opt_local) && (!wo->opt_remote)) { /* * On systems where there are no Ethernet interfaces used, there * may be other ways to obtain a persistent id. Right now, it * will fall back to using magic [see eui64_magic] below when * an EUI-48 from MAC address can't be obtained. Other possibilities * include obtaining EEPROM serial numbers, or some other unique * yet persistent number. On Sparc platforms, this is possible, * but too bad there's no standards yet for x86 machines. */ if (ether_to_eui64(&wo->ourid)) { wo->opt_local = 1; } } #endif if (!wo->opt_local) { /* init interface identifier */ if (wo->use_ip && eui64_iszero(wo->ourid)) { eui64_setlo32(wo->ourid, ntohl(ipcp_wantoptions[0].ouraddr)); if (!eui64_iszero(wo->ourid)) wo->opt_local = 1; } while (eui64_iszero(wo->ourid)) eui64_magic(wo->ourid); } if (!wo->opt_remote) { if (wo->use_ip && eui64_iszero(wo->hisid)) { eui64_setlo32(wo->hisid, ntohl(ipcp_wantoptions[0].hisaddr)); if (!eui64_iszero(wo->hisid)) wo->opt_remote = 1; } } if (demand && (eui64_iszero(wo->ourid) || eui64_iszero(wo->hisid))) { option_error("local/remote LL address required for demand-dialling\n"); exit(1); } } #endif /* PPP_OPTION */ #if DEMAND_SUPPORT /* * ipv6_demand_conf - configure the interface as though * IPV6CP were up, for use with dial-on-demand. */ static int ipv6_demand_conf(int u) { ipv6cp_options *wo = &ipv6cp_wantoptions[u]; #if defined(__linux__) || defined(SOL2) || (defined(SVR4) && (defined(SNI) || defined(__USLC__))) #if defined(SOL2) if (!sif6up(u)) return 0; #else if (!sifup(u)) return 0; #endif /* defined(SOL2) */ #endif if (!sif6addr(u, wo->ourid, wo->hisid)) return 0; #if !defined(__linux__) && !(defined(SVR4) && (defined(SNI) || defined(__USLC__))) if (!sifup(u)) return 0; #endif if (!sifnpmode(u, PPP_IPV6, NPMODE_QUEUE)) return 0; ppp_notice("ipv6_demand_conf"); ppp_notice("local LL address %s", llv6_ntoa(wo->ourid)); ppp_notice("remote LL address %s", llv6_ntoa(wo->hisid)); return 1; } #endif /* DEMAND_SUPPORT */ /* * ipv6cp_up - IPV6CP has come UP. * * Configure the IPv6 network interface appropriately and bring it up. */ static void ipv6cp_up(fsm *f) { ppp_pcb *pcb = f->pcb; ipv6cp_options *wo = &pcb->ipv6cp_wantoptions; ipv6cp_options *ho = &pcb->ipv6cp_hisoptions; ipv6cp_options *go = &pcb->ipv6cp_gotoptions; IPV6CPDEBUG(("ipv6cp: up")); /* * We must have a non-zero LL address for both ends of the link. */ if (!ho->neg_ifaceid) ho->hisid = wo->hisid; #if 0 /* UNUSED */ if(!no_ifaceid_neg) { #endif /* UNUSED */ if (eui64_iszero(ho->hisid)) { ppp_error("Could not determine remote LL address"); ipv6cp_close(f->pcb, "Could not determine remote LL address"); return; } if (eui64_iszero(go->ourid)) { ppp_error("Could not determine local LL address"); ipv6cp_close(f->pcb, "Could not determine local LL address"); return; } if (eui64_equals(go->ourid, ho->hisid)) { ppp_error("local and remote LL addresses are equal"); ipv6cp_close(f->pcb, "local and remote LL addresses are equal"); return; } #if 0 /* UNUSED */ } #endif /* UNUSED */ #if 0 /* UNUSED */ script_setenv("LLLOCAL", llv6_ntoa(go->ourid), 0); script_setenv("LLREMOTE", llv6_ntoa(ho->hisid), 0); #endif /* UNUSED */ #ifdef IPV6CP_COMP /* set tcp compression */ sif6comp(f->unit, ho->neg_vj); #endif #if DEMAND_SUPPORT /* * If we are doing dial-on-demand, the interface is already * configured, so we put out any saved-up packets, then set the * interface to pass IPv6 packets. */ if (demand) { if (! eui64_equals(go->ourid, wo->ourid) || ! eui64_equals(ho->hisid, wo->hisid)) { if (! eui64_equals(go->ourid, wo->ourid)) warn("Local LL address changed to %s", llv6_ntoa(go->ourid)); if (! eui64_equals(ho->hisid, wo->hisid)) warn("Remote LL address changed to %s", llv6_ntoa(ho->hisid)); ipv6cp_clear_addrs(f->pcb, go->ourid, ho->hisid); /* Set the interface to the new addresses */ if (!sif6addr(f->pcb, go->ourid, ho->hisid)) { if (debug) warn("sif6addr failed"); ipv6cp_close(f->unit, "Interface configuration failed"); return; } } demand_rexmit(PPP_IPV6); sifnpmode(f->unit, PPP_IPV6, NPMODE_PASS); } else #endif /* DEMAND_SUPPORT */ { /* * Set LL addresses */ if (!sif6addr(f->pcb, go->ourid, ho->hisid)) { PPPDEBUG(LOG_DEBUG, ("sif6addr failed")); ipv6cp_close(f->pcb, "Interface configuration failed"); return; } /* bring the interface up for IPv6 */ if (!sifup(f->pcb)) { PPPDEBUG(LOG_DEBUG, ("sifup failed (IPV6)")); ipv6cp_close(f->pcb, "Interface configuration failed"); return; } sifnpmode(f->pcb, PPP_IPV6, NPMODE_PASS); ppp_notice("local LL address %s", llv6_ntoa(go->ourid)); ppp_notice("remote LL address %s", llv6_ntoa(ho->hisid)); } np_up(f->pcb, PPP_IPV6); pcb->ipv6cp_is_up = 1; #if 0 /* UNUSED */ /* * Execute the ipv6-up script, like this: * /etc/ppp/ipv6-up interface tty speed local-LL remote-LL */ if (ipv6cp_script_state == s_down && ipv6cp_script_pid == 0) { ipv6cp_script_state = s_up; ipv6cp_script(_PATH_IPV6UP); } #endif /* UNUSED */ } /* * ipv6cp_down - IPV6CP has gone DOWN. * * Take the IPv6 network interface down, clear its addresses * and delete routes through it. */ static void ipv6cp_down(fsm *f) { ppp_pcb *pcb = f->pcb; ipv6cp_options *go = &pcb->ipv6cp_gotoptions; ipv6cp_options *ho = &pcb->ipv6cp_hisoptions; IPV6CPDEBUG(("ipv6cp: down")); #if PPP_STATS_SUPPORT update_link_stats(f->unit); #endif /* PPP_STATS_SUPPORT */ if (pcb->ipv6cp_is_up) { pcb->ipv6cp_is_up = 0; np_down(f->pcb, PPP_IPV6); } #ifdef IPV6CP_COMP sif6comp(f->unit, 0); #endif #if PPP_DEMAND /* * If we are doing dial-on-demand, set the interface * to queue up outgoing packets (for now). */ if (demand) { sifnpmode(f->pcb, PPP_IPV6, NPMODE_QUEUE); } else #endif /* PPP_DEMAND */ { sifnpmode(f->pcb, PPP_IPV6, NPMODE_DROP); ipv6cp_clear_addrs(f->pcb, go->ourid, ho->hisid); sifdown(f->pcb); } #if 0 /* UNUSED */ /* Execute the ipv6-down script */ if (ipv6cp_script_state == s_up && ipv6cp_script_pid == 0) { ipv6cp_script_state = s_down; ipv6cp_script(_PATH_IPV6DOWN); } #endif /* UNUSED */ } /* * ipv6cp_clear_addrs() - clear the interface addresses, routes, * proxy neighbour discovery entries, etc. */ static void ipv6cp_clear_addrs(ppp_pcb *pcb, eui64_t ourid, eui64_t hisid) { cif6addr(pcb, ourid, hisid); } /* * ipv6cp_finished - possibly shut down the lower layers. */ static void ipv6cp_finished(fsm *f) { np_finished(f->pcb, PPP_IPV6); } #if 0 /* UNUSED */ /* * ipv6cp_script_done - called when the ipv6-up or ipv6-down script * has finished. */ static void ipv6cp_script_done(arg) void *arg; { ipv6cp_script_pid = 0; switch (ipv6cp_script_state) { case s_up: if (ipv6cp_fsm[0].state != PPP_FSM_OPENED) { ipv6cp_script_state = s_down; ipv6cp_script(_PATH_IPV6DOWN); } break; case s_down: if (ipv6cp_fsm[0].state == PPP_FSM_OPENED) { ipv6cp_script_state = s_up; ipv6cp_script(_PATH_IPV6UP); } break; } } /* * ipv6cp_script - Execute a script with arguments * interface-name tty-name speed local-LL remote-LL. */ static void ipv6cp_script(script) char *script; { char strspeed[32], strlocal[32], strremote[32]; char *argv[8]; sprintf(strspeed, "%d", baud_rate); strcpy(strlocal, llv6_ntoa(ipv6cp_gotoptions[0].ourid)); strcpy(strremote, llv6_ntoa(ipv6cp_hisoptions[0].hisid)); argv[0] = script; argv[1] = ifname; argv[2] = devnam; argv[3] = strspeed; argv[4] = strlocal; argv[5] = strremote; argv[6] = ipparam; argv[7] = NULL; ipv6cp_script_pid = run_program(script, argv, 0, ipv6cp_script_done, NULL, 0); } #endif /* UNUSED */ #if PRINTPKT_SUPPORT /* * ipv6cp_printpkt - print the contents of an IPV6CP packet. */ static char *ipv6cp_codenames[] = { "ConfReq", "ConfAck", "ConfNak", "ConfRej", "TermReq", "TermAck", "CodeRej" }; static int ipv6cp_printpkt(u_char *p, int plen, void (*printer)(void *, char *, ...), void *arg) { int code, id, len, olen; u_char *pstart, *optend; u_short cishort; eui64_t ifaceid; if (plen < HEADERLEN) return 0; pstart = p; GETCHAR(code, p); GETCHAR(id, p); GETSHORT(len, p); if (len < HEADERLEN || len > plen) return 0; if (code >= 1 && code <= sizeof(ipv6cp_codenames) / sizeof(char *)) printer(arg, " %s", ipv6cp_codenames[code-1]); else printer(arg, " code=0x%x", code); printer(arg, " id=0x%x", id); len -= HEADERLEN; switch (code) { case CONFREQ: case CONFACK: case CONFNAK: case CONFREJ: /* print option list */ while (len >= 2) { GETCHAR(code, p); GETCHAR(olen, p); p -= 2; if (olen < 2 || olen > len) { break; } printer(arg, " <"); len -= olen; optend = p + olen; switch (code) { case CI_COMPRESSTYPE: if (olen >= CILEN_COMPRESS) { p += 2; GETSHORT(cishort, p); printer(arg, "compress "); printer(arg, "0x%x", cishort); } break; case CI_IFACEID: if (olen == CILEN_IFACEID) { p += 2; eui64_get(ifaceid, p); printer(arg, "addr %s", llv6_ntoa(ifaceid)); } break; } while (p < optend) { GETCHAR(code, p); printer(arg, " %.2x", code); } printer(arg, ">"); } break; case TERMACK: case TERMREQ: if (len > 0 && *p >= ' ' && *p < 0x7f) { printer(arg, " "); ppp_print_string((char *)p, len, printer, arg); p += len; len = 0; } break; } /* print the rest of the bytes in the packet */ for (; len > 0; --len) { GETCHAR(code, p); printer(arg, " %.2x", code); } return p - pstart; } #endif /* PRINTPKT_SUPPORT */ #if PPP_DEMAND /* * ipv6_active_pkt - see if this IP packet is worth bringing the link up for. * We don't bring the link up for IP fragments or for TCP FIN packets * with no data. */ #define IP6_HDRLEN 40 /* bytes */ #define IP6_NHDR_FRAG 44 /* fragment IPv6 header */ #define TCP_HDRLEN 20 #define TH_FIN 0x01 /* * We use these macros because the IP header may be at an odd address, * and some compilers might use word loads to get th_off or ip_hl. */ #define get_ip6nh(x) (((unsigned char *)(x))[6]) #define get_tcpoff(x) (((unsigned char *)(x))[12] >> 4) #define get_tcpflags(x) (((unsigned char *)(x))[13]) static int ipv6_active_pkt(u_char *pkt, int len) { u_char *tcp; len -= PPP_HDRLEN; pkt += PPP_HDRLEN; if (len < IP6_HDRLEN) return 0; if (get_ip6nh(pkt) == IP6_NHDR_FRAG) return 0; if (get_ip6nh(pkt) != IPPROTO_TCP) return 1; if (len < IP6_HDRLEN + TCP_HDRLEN) return 0; tcp = pkt + IP6_HDRLEN; if ((get_tcpflags(tcp) & TH_FIN) != 0 && len == IP6_HDRLEN + get_tcpoff(tcp) * 4) return 0; return 1; } #endif /* PPP_DEMAND */ #endif /* PPP_SUPPORT && PPP_IPV6_SUPPORT */ ocproxy-1.60/lwip/src/netif/ppp/lcp.c000066400000000000000000002144411303453231400175370ustar00rootroot00000000000000/* * lcp.c - PPP Link Control Protocol. * * Copyright (c) 1984-2000 Carnegie Mellon University. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The name "Carnegie Mellon University" must not be used to * endorse or promote products derived from this software without * prior written permission. For permission or any legal * details, please contact * Office of Technology Transfer * Carnegie Mellon University * 5000 Forbes Avenue * Pittsburgh, PA 15213-3890 * (412) 268-4387, fax: (412) 268-7395 * tech-transfer@andrew.cmu.edu * * 4. Redistributions of any form whatsoever must retain the following * acknowledgment: * "This product includes software developed by Computing Services * at Carnegie Mellon University (http://www.cmu.edu/computing/)." * * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "lwip/opt.h" #if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */ /* * TODO: */ #if 0 /* UNUSED */ #include #include #include #endif /* UNUSED */ #include "netif/ppp/ppp_impl.h" #include "netif/ppp/fsm.h" #include "netif/ppp/lcp.h" #if CHAP_SUPPORT #include "netif/ppp/chap-new.h" #endif /* CHAP_SUPPORT */ #include "netif/ppp/magic.h" /* * When the link comes up we want to be able to wait for a short while, * or until seeing some input from the peer, before starting to send * configure-requests. We do this by delaying the fsm_lowerup call. */ /* steal a bit in fsm flags word */ #define DELAYED_UP 0x80 static void lcp_delayed_up(void *arg); /* * LCP-related command-line options. */ #if 0 /* UNUSED */ int lcp_echo_interval = 0; /* Interval between LCP echo-requests */ int lcp_echo_fails = 0; /* Tolerance to unanswered echo-requests */ #endif /* UNUSED */ #if 0 /* UNUSED */ /* options */ static u_int lcp_echo_interval = LCP_ECHOINTERVAL; /* Interval between LCP echo-requests */ static u_int lcp_echo_fails = LCP_MAXECHOFAILS; /* Tolerance to unanswered echo-requests */ #endif /* UNUSED */ #if 0 /* UNUSED */ #if PPP_LCP_ADAPTIVE bool lcp_echo_adaptive = 0; /* request echo only if the link was idle */ #endif bool lax_recv = 0; /* accept control chars in asyncmap */ bool noendpoint = 0; /* don't send/accept endpoint discriminator */ #endif /* UNUSED */ #if PPP_OPTIONS static int noopt (char **); #endif /* PPP_OPTIONS */ #ifdef HAVE_MULTILINK static int setendpoint (char **); static void printendpoint (option_t *, void (*)(void *, char *, ...), void *); #endif /* HAVE_MULTILINK */ #if PPP_OPTIONS static option_t lcp_option_list[] = { /* LCP options */ { "-all", o_special_noarg, (void *)noopt, "Don't request/allow any LCP options" }, { "noaccomp", o_bool, &lcp_wantoptions[0].neg_accompression, "Disable address/control compression", OPT_A2CLR, &lcp_allowoptions[0].neg_accompression }, { "-ac", o_bool, &lcp_wantoptions[0].neg_accompression, "Disable address/control compression", OPT_ALIAS | OPT_A2CLR, &lcp_allowoptions[0].neg_accompression }, { "asyncmap", o_uint32, &lcp_wantoptions[0].asyncmap, "Set asyncmap (for received packets)", OPT_OR, &lcp_wantoptions[0].neg_asyncmap }, { "-as", o_uint32, &lcp_wantoptions[0].asyncmap, "Set asyncmap (for received packets)", OPT_ALIAS | OPT_OR, &lcp_wantoptions[0].neg_asyncmap }, { "default-asyncmap", o_uint32, &lcp_wantoptions[0].asyncmap, "Disable asyncmap negotiation", OPT_OR | OPT_NOARG | OPT_VAL(~0U) | OPT_A2CLR, &lcp_allowoptions[0].neg_asyncmap }, { "-am", o_uint32, &lcp_wantoptions[0].asyncmap, "Disable asyncmap negotiation", OPT_ALIAS | OPT_OR | OPT_NOARG | OPT_VAL(~0U) | OPT_A2CLR, &lcp_allowoptions[0].neg_asyncmap }, { "nomagic", o_bool, &lcp_wantoptions[0].neg_magicnumber, "Disable magic number negotiation (looped-back line detection)", OPT_A2CLR, &lcp_allowoptions[0].neg_magicnumber }, { "-mn", o_bool, &lcp_wantoptions[0].neg_magicnumber, "Disable magic number negotiation (looped-back line detection)", OPT_ALIAS | OPT_A2CLR, &lcp_allowoptions[0].neg_magicnumber }, { "mru", o_int, &lcp_wantoptions[0].mru, "Set MRU (maximum received packet size) for negotiation", OPT_PRIO, &lcp_wantoptions[0].neg_mru }, { "default-mru", o_bool, &lcp_wantoptions[0].neg_mru, "Disable MRU negotiation (use default 1500)", OPT_PRIOSUB | OPT_A2CLR, &lcp_allowoptions[0].neg_mru }, { "-mru", o_bool, &lcp_wantoptions[0].neg_mru, "Disable MRU negotiation (use default 1500)", OPT_ALIAS | OPT_PRIOSUB | OPT_A2CLR, &lcp_allowoptions[0].neg_mru }, { "mtu", o_int, &lcp_allowoptions[0].mru, "Set our MTU", OPT_LIMITS, NULL, MAXMRU, MINMRU }, { "nopcomp", o_bool, &lcp_wantoptions[0].neg_pcompression, "Disable protocol field compression", OPT_A2CLR, &lcp_allowoptions[0].neg_pcompression }, { "-pc", o_bool, &lcp_wantoptions[0].neg_pcompression, "Disable protocol field compression", OPT_ALIAS | OPT_A2CLR, &lcp_allowoptions[0].neg_pcompression }, { "passive", o_bool, &lcp_wantoptions[0].passive, "Set passive mode", 1 }, { "-p", o_bool, &lcp_wantoptions[0].passive, "Set passive mode", OPT_ALIAS | 1 }, { "silent", o_bool, &lcp_wantoptions[0].silent, "Set silent mode", 1 }, { "lcp-echo-failure", o_int, &lcp_echo_fails, "Set number of consecutive echo failures to indicate link failure", OPT_PRIO }, { "lcp-echo-interval", o_int, &lcp_echo_interval, "Set time in seconds between LCP echo requests", OPT_PRIO }, #if PPP_LCP_ADAPTIVE { "lcp-echo-adaptive", o_bool, &lcp_echo_adaptive, "Suppress LCP echo requests if traffic was received", 1 }, #endif { "lcp-restart", o_int, &lcp_fsm[0].timeouttime, "Set time in seconds between LCP retransmissions", OPT_PRIO }, { "lcp-max-terminate", o_int, &lcp_fsm[0].maxtermtransmits, "Set maximum number of LCP terminate-request transmissions", OPT_PRIO }, { "lcp-max-configure", o_int, &lcp_fsm[0].maxconfreqtransmits, "Set maximum number of LCP configure-request transmissions", OPT_PRIO }, { "lcp-max-failure", o_int, &lcp_fsm[0].maxnakloops, "Set limit on number of LCP configure-naks", OPT_PRIO }, { "receive-all", o_bool, &lax_recv, "Accept all received control characters", 1 }, #ifdef HAVE_MULTILINK { "mrru", o_int, &lcp_wantoptions[0].mrru, "Maximum received packet size for multilink bundle", OPT_PRIO, &lcp_wantoptions[0].neg_mrru }, { "mpshortseq", o_bool, &lcp_wantoptions[0].neg_ssnhf, "Use short sequence numbers in multilink headers", OPT_PRIO | 1, &lcp_allowoptions[0].neg_ssnhf }, { "nompshortseq", o_bool, &lcp_wantoptions[0].neg_ssnhf, "Don't use short sequence numbers in multilink headers", OPT_PRIOSUB | OPT_A2CLR, &lcp_allowoptions[0].neg_ssnhf }, { "endpoint", o_special, (void *) setendpoint, "Endpoint discriminator for multilink", OPT_PRIO | OPT_A2PRINTER, (void *) printendpoint }, #endif /* HAVE_MULTILINK */ { "noendpoint", o_bool, &noendpoint, "Don't send or accept multilink endpoint discriminator", 1 }, {NULL} }; #endif /* PPP_OPTIONS */ /* * Callbacks for fsm code. (CI = Configuration Information) */ static void lcp_resetci(fsm *f); /* Reset our CI */ static int lcp_cilen(fsm *f); /* Return length of our CI */ static void lcp_addci(fsm *f, u_char *ucp, int *lenp); /* Add our CI to pkt */ static int lcp_ackci(fsm *f, u_char *p, int len); /* Peer ack'd our CI */ static int lcp_nakci(fsm *f, u_char *p, int len, int treat_as_reject); /* Peer nak'd our CI */ static int lcp_rejci(fsm *f, u_char *p, int len); /* Peer rej'd our CI */ static int lcp_reqci(fsm *f, u_char *inp, int *lenp, int reject_if_disagree); /* Rcv peer CI */ static void lcp_up(fsm *f); /* We're UP */ static void lcp_down(fsm *f); /* We're DOWN */ static void lcp_starting (fsm *); /* We need lower layer up */ static void lcp_finished (fsm *); /* We need lower layer down */ static int lcp_extcode(fsm *f, int code, int id, u_char *inp, int len); static void lcp_rprotrej(fsm *f, u_char *inp, int len); /* * routines to send LCP echos to peer */ static void lcp_echo_lowerup(ppp_pcb *pcb); static void lcp_echo_lowerdown(ppp_pcb *pcb); static void LcpEchoTimeout(void *arg); static void lcp_received_echo_reply(fsm *f, int id, u_char *inp, int len); static void LcpSendEchoRequest(fsm *f); static void LcpLinkFailure(fsm *f); static void LcpEchoCheck(fsm *f); static const fsm_callbacks lcp_callbacks = { /* LCP callback routines */ lcp_resetci, /* Reset our Configuration Information */ lcp_cilen, /* Length of our Configuration Information */ lcp_addci, /* Add our Configuration Information */ lcp_ackci, /* ACK our Configuration Information */ lcp_nakci, /* NAK our Configuration Information */ lcp_rejci, /* Reject our Configuration Information */ lcp_reqci, /* Request peer's Configuration Information */ lcp_up, /* Called when fsm reaches OPENED state */ lcp_down, /* Called when fsm leaves OPENED state */ lcp_starting, /* Called when we want the lower layer up */ lcp_finished, /* Called when we want the lower layer down */ NULL, /* Called when Protocol-Reject received */ NULL, /* Retransmission is necessary */ lcp_extcode, /* Called to handle LCP-specific codes */ "LCP" /* String name of protocol */ }; /* * Protocol entry points. * Some of these are called directly. */ static void lcp_init(ppp_pcb *pcb); static void lcp_input(ppp_pcb *pcb, u_char *p, int len); static void lcp_protrej(ppp_pcb *pcb); #if PRINTPKT_SUPPORT static int lcp_printpkt(u_char *p, int plen, void (*printer) (void *, char *, ...), void *arg); #endif /* PRINTPKT_SUPPORT */ const struct protent lcp_protent = { PPP_LCP, lcp_init, lcp_input, lcp_protrej, lcp_lowerup, lcp_lowerdown, lcp_open, lcp_close, #if PRINTPKT_SUPPORT lcp_printpkt, #endif /* PRINTPKT_SUPPORT */ NULL, 1, #if PRINTPKT_SUPPORT "LCP", NULL, #endif /* PRINTPKT_SUPPORT */ #if PPP_OPTIONS lcp_option_list, NULL, #endif /* PPP_OPTIONS */ #if DEMAND_SUPPORT NULL, NULL #endif /* DEMAND_SUPPORT */ }; /* * Length of each type of configuration option (in octets) */ #define CILEN_VOID 2 #define CILEN_CHAR 3 #define CILEN_SHORT 4 /* CILEN_VOID + 2 */ #if CHAP_SUPPORT #define CILEN_CHAP 5 /* CILEN_VOID + 2 + 1 */ #endif /* CHAP_SUPPORT */ #define CILEN_LONG 6 /* CILEN_VOID + 4 */ #if LQR_SUPPORT #define CILEN_LQR 8 /* CILEN_VOID + 2 + 4 */ #endif /* LQR_SUPPORT */ #define CILEN_CBCP 3 #define CODENAME(x) ((x) == CONFACK ? "ACK" : \ (x) == CONFNAK ? "NAK" : "REJ") #if PPP_OPTIONS /* * noopt - Disable all options (why?). */ static int noopt(argv) char **argv; { BZERO((char *) &lcp_wantoptions[0], sizeof (struct lcp_options)); BZERO((char *) &lcp_allowoptions[0], sizeof (struct lcp_options)); return (1); } #endif /* PPP_OPTIONS */ #ifdef HAVE_MULTILINK static int setendpoint(argv) char **argv; { if (str_to_epdisc(&lcp_wantoptions[0].endpoint, *argv)) { lcp_wantoptions[0].neg_endpoint = 1; return 1; } option_error("Can't parse '%s' as an endpoint discriminator", *argv); return 0; } static void printendpoint(opt, printer, arg) option_t *opt; void (*printer) (void *, char *, ...); void *arg; { printer(arg, "%s", epdisc_to_str(&lcp_wantoptions[0].endpoint)); } #endif /* HAVE_MULTILINK */ /* * lcp_init - Initialize LCP. */ static void lcp_init(ppp_pcb *pcb) { fsm *f = &pcb->lcp_fsm; lcp_options *wo = &pcb->lcp_wantoptions; lcp_options *ao = &pcb->lcp_allowoptions; f->pcb = pcb; f->protocol = PPP_LCP; f->callbacks = &lcp_callbacks; fsm_init(f); BZERO(wo, sizeof(*wo)); wo->neg_mru = 1; wo->mru = DEFMRU; wo->neg_asyncmap = 1; wo->neg_magicnumber = 1; wo->neg_pcompression = 1; wo->neg_accompression = 1; BZERO(ao, sizeof(*ao)); ao->neg_mru = 1; ao->mru = MAXMRU; ao->neg_asyncmap = 1; #if CHAP_SUPPORT ao->neg_chap = 1; ao->chap_mdtype = CHAP_MDTYPE_SUPPORTED; #endif /* CHAP_SUPPORT */ #if PAP_SUPPORT ao->neg_upap = 1; #endif /* PAP_SUPPORT */ #if EAP_SUPPORT ao->neg_eap = 1; #endif /* EAP_SUPPORT */ ao->neg_magicnumber = 1; ao->neg_pcompression = 1; ao->neg_accompression = 1; ao->neg_endpoint = 1; #if PPPOS_SUPPORT /* * Set transmit escape for the flag and escape characters plus anything * set for the allowable options. */ memset(pcb->xmit_accm, 0, sizeof(ext_accm)); pcb->xmit_accm[15] = 0x60; pcb->xmit_accm[0] = (u_char)((ao->asyncmap & 0xFF)); pcb->xmit_accm[1] = (u_char)((ao->asyncmap >> 8) & 0xFF); pcb->xmit_accm[2] = (u_char)((ao->asyncmap >> 16) & 0xFF); pcb->xmit_accm[3] = (u_char)((ao->asyncmap >> 24) & 0xFF); LCPDEBUG(("lcp_init: xmit_accm=%X %X %X %X\n", pcb->xmit_accm[0], pcb->xmit_accm[1], pcb->xmit_accm[2], pcb->xmit_accm[3])); #endif /* PPPOS_SUPPORT */ } /* * lcp_open - LCP is allowed to come up. */ void lcp_open(ppp_pcb *pcb) { fsm *f = &pcb->lcp_fsm; lcp_options *wo = &pcb->lcp_wantoptions; f->flags &= ~(OPT_PASSIVE | OPT_SILENT); if (wo->passive) f->flags |= OPT_PASSIVE; if (wo->silent) f->flags |= OPT_SILENT; fsm_open(f); } /* * lcp_close - Take LCP down. */ void lcp_close(ppp_pcb *pcb, char *reason) { fsm *f = &pcb->lcp_fsm; int oldstate; if (pcb->phase != PPP_PHASE_DEAD && pcb->phase != PPP_PHASE_MASTER) new_phase(pcb, PPP_PHASE_TERMINATE); if (f->flags & DELAYED_UP) { UNTIMEOUT(lcp_delayed_up, f); f->state = PPP_FSM_STOPPED; } oldstate = f->state; fsm_close(f, reason); if (oldstate == PPP_FSM_STOPPED && (f->flags & (OPT_PASSIVE|OPT_SILENT|DELAYED_UP))) { /* * This action is not strictly according to the FSM in RFC1548, * but it does mean that the program terminates if you do a * lcp_close() when a connection hasn't been established * because we are in passive/silent mode or because we have * delayed the fsm_lowerup() call and it hasn't happened yet. */ f->flags &= ~DELAYED_UP; lcp_finished(f); } } /* * lcp_lowerup - The lower layer is up. */ void lcp_lowerup(ppp_pcb *pcb) { lcp_options *wo = &pcb->lcp_wantoptions; #if PPPOS_SUPPORT lcp_options *ao = &pcb->lcp_allowoptions; #endif /* PPPOS_SUPPORT */ fsm *f = &pcb->lcp_fsm; /* * Don't use A/C or protocol compression on transmission, * but accept A/C and protocol compressed packets * if we are going to ask for A/C and protocol compression. */ #if PPPOS_SUPPORT ppp_set_xaccm(pcb, &pcb->xmit_accm); #endif /* PPPOS_SUPPORT */ if (ppp_send_config(pcb, PPP_MRU, 0xffffffff, 0, 0) < 0 || ppp_recv_config(pcb, PPP_MRU, (pcb->settings.lax_recv? 0: 0xffffffff), wo->neg_pcompression, wo->neg_accompression) < 0) return; pcb->peer_mru = PPP_MRU; #if PPPOS_SUPPORT ao->asyncmap = (u_long)pcb->xmit_accm[0] | ((u_long)pcb->xmit_accm[1] << 8) | ((u_long)pcb->xmit_accm[2] << 16) | ((u_long)pcb->xmit_accm[3] << 24); LCPDEBUG(("lcp_lowerup: asyncmap=%X %X %X %X\n", pcb->xmit_accm[3], pcb->xmit_accm[2], pcb->xmit_accm[1], pcb->xmit_accm[0])); #endif /* PPPOS_SUPPORT */ if (pcb->settings.listen_time != 0) { f->flags |= DELAYED_UP; TIMEOUTMS(lcp_delayed_up, f, pcb->settings.listen_time); } else fsm_lowerup(f); } /* * lcp_lowerdown - The lower layer is down. */ void lcp_lowerdown(ppp_pcb *pcb) { fsm *f = &pcb->lcp_fsm; if (f->flags & DELAYED_UP) { f->flags &= ~DELAYED_UP; UNTIMEOUT(lcp_delayed_up, f); } else fsm_lowerdown(f); } /* * lcp_delayed_up - Bring the lower layer up now. */ static void lcp_delayed_up(void *arg) { fsm *f = arg; if (f->flags & DELAYED_UP) { f->flags &= ~DELAYED_UP; fsm_lowerup(f); } } /* * lcp_input - Input LCP packet. */ static void lcp_input(ppp_pcb *pcb, u_char *p, int len) { fsm *f = &pcb->lcp_fsm; if (f->flags & DELAYED_UP) { f->flags &= ~DELAYED_UP; UNTIMEOUT(lcp_delayed_up, f); fsm_lowerup(f); } fsm_input(f, p, len); } /* * lcp_extcode - Handle a LCP-specific code. */ static int lcp_extcode(fsm *f, int code, int id, u_char *inp, int len) { ppp_pcb *pcb = f->pcb; lcp_options *go = &pcb->lcp_gotoptions; u_char *magp; switch( code ){ case PROTREJ: lcp_rprotrej(f, inp, len); break; case ECHOREQ: if (f->state != PPP_FSM_OPENED) break; magp = inp; PUTLONG(go->magicnumber, magp); fsm_sdata(f, ECHOREP, id, inp, len); break; case ECHOREP: lcp_received_echo_reply(f, id, inp, len); break; case DISCREQ: case IDENTIF: case TIMEREM: break; default: return 0; } return 1; } /* * lcp_rprotrej - Receive an Protocol-Reject. * * Figure out which protocol is rejected and inform it. */ static void lcp_rprotrej(fsm *f, u_char *inp, int len) { int i; const struct protent *protp; u_short prot; #if PPP_PROTOCOLNAME const char *pname; #endif /* PPP_PROTOCOLNAME */ if (len < 2) { LCPDEBUG(("lcp_rprotrej: Rcvd short Protocol-Reject packet!")); return; } GETSHORT(prot, inp); /* * Protocol-Reject packets received in any state other than the LCP * OPENED state SHOULD be silently discarded. */ if( f->state != PPP_FSM_OPENED ){ LCPDEBUG(("Protocol-Reject discarded: LCP in state %d", f->state)); return; } #if PPP_PROTOCOLNAME pname = protocol_name(prot); #endif /* PPP_PROTOCOLNAME */ /* * Upcall the proper Protocol-Reject routine. */ for (i = 0; (protp = protocols[i]) != NULL; ++i) if (protp->protocol == prot && protp->enabled_flag) { #if PPP_PROTOCOLNAME if (pname != NULL) ppp_dbglog("Protocol-Reject for '%s' (0x%x) received", pname, prot); else #endif /* PPP_PROTOCOLNAME */ ppp_dbglog("Protocol-Reject for 0x%x received", prot); (*protp->protrej)(f->pcb); return; } #if PPP_PROTOCOLNAME if (pname != NULL) ppp_warn("Protocol-Reject for unsupported protocol '%s' (0x%x)", pname, prot); else #endif /* #if PPP_PROTOCOLNAME */ ppp_warn("Protocol-Reject for unsupported protocol 0x%x", prot); } /* * lcp_protrej - A Protocol-Reject was received. */ /*ARGSUSED*/ static void lcp_protrej(ppp_pcb *pcb) { /* * Can't reject LCP! */ ppp_error("Received Protocol-Reject for LCP!"); fsm_protreject(&pcb->lcp_fsm); } /* * lcp_sprotrej - Send a Protocol-Reject for some protocol. */ void lcp_sprotrej(ppp_pcb *pcb, u_char *p, int len) { fsm *f = &pcb->lcp_fsm; /* * Send back the protocol and the information field of the * rejected packet. We only get here if LCP is in the OPENED state. */ #if 0 p += 2; len -= 2; #endif fsm_sdata(f, PROTREJ, ++f->id, p, len); } /* * lcp_resetci - Reset our CI. */ static void lcp_resetci(fsm *f) { ppp_pcb *pcb = f->pcb; lcp_options *wo = &pcb->lcp_wantoptions; lcp_options *go = &pcb->lcp_gotoptions; lcp_options *ao = &pcb->lcp_allowoptions; wo->magicnumber = magic(); wo->numloops = 0; *go = *wo; #ifdef HAVE_MULTILINK if (!multilink) { go->neg_mrru = 0; #endif /* HAVE_MULTILINK */ go->neg_ssnhf = 0; go->neg_endpoint = 0; #ifdef HAVE_MULTILINK } #endif /* HAVE_MULTILINK */ if (pcb->settings.noendpoint) ao->neg_endpoint = 0; pcb->peer_mru = PPP_MRU; auth_reset(pcb); } /* * lcp_cilen - Return length of our CI. */ static int lcp_cilen(fsm *f) { ppp_pcb *pcb = f->pcb; lcp_options *go = &pcb->lcp_gotoptions; #define LENCIVOID(neg) ((neg) ? CILEN_VOID : 0) #if CHAP_SUPPORT #define LENCICHAP(neg) ((neg) ? CILEN_CHAP : 0) #endif /* CHAP_SUPPORT */ #define LENCISHORT(neg) ((neg) ? CILEN_SHORT : 0) #define LENCILONG(neg) ((neg) ? CILEN_LONG : 0) #if LQR_SUPPORT #define LENCILQR(neg) ((neg) ? CILEN_LQR: 0) #endif /* LQR_SUPPORT */ #define LENCICBCP(neg) ((neg) ? CILEN_CBCP: 0) /* * NB: we only ask for one of CHAP, UPAP, or EAP, even if we will * accept more than one. We prefer EAP first, then CHAP, then * PAP. */ return (LENCISHORT(go->neg_mru && go->mru != DEFMRU) + LENCILONG(go->neg_asyncmap && go->asyncmap != 0xFFFFFFFF) + #if EAP_SUPPORT LENCISHORT(go->neg_eap) + #endif /* EAP_SUPPORT */ #if CHAP_SUPPORT /* cannot be improved, embedding a directive within macro arguments is not portable */ #if EAP_SUPPORT LENCICHAP(!go->neg_eap && go->neg_chap) + #endif /* EAP_SUPPORT */ #if !EAP_SUPPORT LENCICHAP(go->neg_chap) + #endif /* !EAP_SUPPORT */ #endif /* CHAP_SUPPORT */ #if PAP_SUPPORT /* cannot be improved, embedding a directive within macro arguments is not portable */ #if EAP_SUPPORT && CHAP_SUPPORT LENCISHORT(!go->neg_eap && !go->neg_chap && go->neg_upap) + #endif /* EAP_SUPPORT && CHAP_SUPPORT */ #if EAP_SUPPORT && !CHAP_SUPPORT LENCISHORT(!go->neg_eap && go->neg_upap) + #endif /* EAP_SUPPORT && !CHAP_SUPPORT */ #if !EAP_SUPPORT && CHAP_SUPPORT LENCISHORT(!go->neg_chap && go->neg_upap) + #endif /* !EAP_SUPPORT && CHAP_SUPPORT */ #if !EAP_SUPPORT && !CHAP_SUPPORT LENCISHORT(go->neg_upap) + #endif /* !EAP_SUPPORT && !CHAP_SUPPORT */ #endif /* PAP_SUPPORT */ #if LQR_SUPPORT LENCILQR(go->neg_lqr) + #endif /* LQR_SUPPORT */ LENCICBCP(go->neg_cbcp) + LENCILONG(go->neg_magicnumber) + LENCIVOID(go->neg_pcompression) + LENCIVOID(go->neg_accompression) + #ifdef HAVE_MULTILINK LENCISHORT(go->neg_mrru) + #endif /* HAVE_MULTILINK */ LENCIVOID(go->neg_ssnhf) + (go->neg_endpoint? CILEN_CHAR + go->endpoint.length: 0)); } /* * lcp_addci - Add our desired CIs to a packet. */ static void lcp_addci(fsm *f, u_char *ucp, int *lenp) { ppp_pcb *pcb = f->pcb; lcp_options *go = &pcb->lcp_gotoptions; u_char *start_ucp = ucp; #define ADDCIVOID(opt, neg) \ if (neg) { \ PUTCHAR(opt, ucp); \ PUTCHAR(CILEN_VOID, ucp); \ } #define ADDCISHORT(opt, neg, val) \ if (neg) { \ PUTCHAR(opt, ucp); \ PUTCHAR(CILEN_SHORT, ucp); \ PUTSHORT(val, ucp); \ } #if CHAP_SUPPORT #define ADDCICHAP(opt, neg, val) \ if (neg) { \ PUTCHAR((opt), ucp); \ PUTCHAR(CILEN_CHAP, ucp); \ PUTSHORT(PPP_CHAP, ucp); \ PUTCHAR((CHAP_DIGEST(val)), ucp); \ } #endif /* CHAP_SUPPORT */ #define ADDCILONG(opt, neg, val) \ if (neg) { \ PUTCHAR(opt, ucp); \ PUTCHAR(CILEN_LONG, ucp); \ PUTLONG(val, ucp); \ } #if LQR_SUPPORT #define ADDCILQR(opt, neg, val) \ if (neg) { \ PUTCHAR(opt, ucp); \ PUTCHAR(CILEN_LQR, ucp); \ PUTSHORT(PPP_LQR, ucp); \ PUTLONG(val, ucp); \ } #endif /* LQR_SUPPORT */ #define ADDCICHAR(opt, neg, val) \ if (neg) { \ PUTCHAR(opt, ucp); \ PUTCHAR(CILEN_CHAR, ucp); \ PUTCHAR(val, ucp); \ } #define ADDCIENDP(opt, neg, class, val, len) \ if (neg) { \ int i; \ PUTCHAR(opt, ucp); \ PUTCHAR(CILEN_CHAR + len, ucp); \ PUTCHAR(class, ucp); \ for (i = 0; i < len; ++i) \ PUTCHAR(val[i], ucp); \ } ADDCISHORT(CI_MRU, go->neg_mru && go->mru != DEFMRU, go->mru); ADDCILONG(CI_ASYNCMAP, go->neg_asyncmap && go->asyncmap != 0xFFFFFFFF, go->asyncmap); #if EAP_SUPPORT ADDCISHORT(CI_AUTHTYPE, go->neg_eap, PPP_EAP); #endif /* EAP_SUPPORT */ #if CHAP_SUPPORT /* cannot be improved, embedding a directive within macro arguments is not portable */ #if EAP_SUPPORT ADDCICHAP(CI_AUTHTYPE, !go->neg_eap && go->neg_chap, go->chap_mdtype); #endif /* EAP_SUPPORT */ #if !EAP_SUPPORT ADDCICHAP(CI_AUTHTYPE, go->neg_chap, go->chap_mdtype); #endif /* !EAP_SUPPORT */ #endif /* CHAP_SUPPORT */ #if PAP_SUPPORT /* cannot be improved, embedding a directive within macro arguments is not portable */ #if EAP_SUPPORT && CHAP_SUPPORT ADDCISHORT(CI_AUTHTYPE, !go->neg_eap && !go->neg_chap && go->neg_upap, PPP_PAP); #endif /* EAP_SUPPORT && CHAP_SUPPORT */ #if EAP_SUPPORT && !CHAP_SUPPORT ADDCISHORT(CI_AUTHTYPE, !go->neg_eap && go->neg_upap, PPP_PAP); #endif /* EAP_SUPPORT && !CHAP_SUPPORT */ #if !EAP_SUPPORT && CHAP_SUPPORT ADDCISHORT(CI_AUTHTYPE, !go->neg_chap && go->neg_upap, PPP_PAP); #endif /* !EAP_SUPPORT && CHAP_SUPPORT */ #if !EAP_SUPPORT && !CHAP_SUPPORT ADDCISHORT(CI_AUTHTYPE, go->neg_upap, PPP_PAP); #endif /* !EAP_SUPPORT && !CHAP_SUPPORT */ #endif /* PAP_SUPPORT */ #if LQR_SUPPORT ADDCILQR(CI_QUALITY, go->neg_lqr, go->lqr_period); #endif /* LQR_SUPPORT */ ADDCICHAR(CI_CALLBACK, go->neg_cbcp, CBCP_OPT); ADDCILONG(CI_MAGICNUMBER, go->neg_magicnumber, go->magicnumber); ADDCIVOID(CI_PCOMPRESSION, go->neg_pcompression); ADDCIVOID(CI_ACCOMPRESSION, go->neg_accompression); #ifdef HAVE_MULTILINK ADDCISHORT(CI_MRRU, go->neg_mrru, go->mrru); #endif ADDCIVOID(CI_SSNHF, go->neg_ssnhf); ADDCIENDP(CI_EPDISC, go->neg_endpoint, go->endpoint.class_, go->endpoint.value, go->endpoint.length); if (ucp - start_ucp != *lenp) { /* this should never happen, because peer_mtu should be 1500 */ ppp_error("Bug in lcp_addci: wrong length"); } } /* * lcp_ackci - Ack our CIs. * This should not modify any state if the Ack is bad. * * Returns: * 0 - Ack was bad. * 1 - Ack was good. */ static int lcp_ackci(fsm *f, u_char *p, int len) { ppp_pcb *pcb = f->pcb; lcp_options *go = &pcb->lcp_gotoptions; u_char cilen, citype, cichar; u_short cishort; u32_t cilong; /* * CIs must be in exactly the same order that we sent. * Check packet length and CI length at each step. * If we find any deviations, then this packet is bad. */ #define ACKCIVOID(opt, neg) \ if (neg) { \ if ((len -= CILEN_VOID) < 0) \ goto bad; \ GETCHAR(citype, p); \ GETCHAR(cilen, p); \ if (cilen != CILEN_VOID || \ citype != opt) \ goto bad; \ } #define ACKCISHORT(opt, neg, val) \ if (neg) { \ if ((len -= CILEN_SHORT) < 0) \ goto bad; \ GETCHAR(citype, p); \ GETCHAR(cilen, p); \ if (cilen != CILEN_SHORT || \ citype != opt) \ goto bad; \ GETSHORT(cishort, p); \ if (cishort != val) \ goto bad; \ } #define ACKCICHAR(opt, neg, val) \ if (neg) { \ if ((len -= CILEN_CHAR) < 0) \ goto bad; \ GETCHAR(citype, p); \ GETCHAR(cilen, p); \ if (cilen != CILEN_CHAR || \ citype != opt) \ goto bad; \ GETCHAR(cichar, p); \ if (cichar != val) \ goto bad; \ } #if CHAP_SUPPORT #define ACKCICHAP(opt, neg, val) \ if (neg) { \ if ((len -= CILEN_CHAP) < 0) \ goto bad; \ GETCHAR(citype, p); \ GETCHAR(cilen, p); \ if (cilen != CILEN_CHAP || \ citype != (opt)) \ goto bad; \ GETSHORT(cishort, p); \ if (cishort != PPP_CHAP) \ goto bad; \ GETCHAR(cichar, p); \ if (cichar != (CHAP_DIGEST(val))) \ goto bad; \ } #endif /* CHAP_SUPPORT */ #define ACKCILONG(opt, neg, val) \ if (neg) { \ if ((len -= CILEN_LONG) < 0) \ goto bad; \ GETCHAR(citype, p); \ GETCHAR(cilen, p); \ if (cilen != CILEN_LONG || \ citype != opt) \ goto bad; \ GETLONG(cilong, p); \ if (cilong != val) \ goto bad; \ } #if LQR_SUPPORT #define ACKCILQR(opt, neg, val) \ if (neg) { \ if ((len -= CILEN_LQR) < 0) \ goto bad; \ GETCHAR(citype, p); \ GETCHAR(cilen, p); \ if (cilen != CILEN_LQR || \ citype != opt) \ goto bad; \ GETSHORT(cishort, p); \ if (cishort != PPP_LQR) \ goto bad; \ GETLONG(cilong, p); \ if (cilong != val) \ goto bad; \ } #endif /* LQR_SUPPORT */ #define ACKCIENDP(opt, neg, class, val, vlen) \ if (neg) { \ int i; \ if ((len -= CILEN_CHAR + vlen) < 0) \ goto bad; \ GETCHAR(citype, p); \ GETCHAR(cilen, p); \ if (cilen != CILEN_CHAR + vlen || \ citype != opt) \ goto bad; \ GETCHAR(cichar, p); \ if (cichar != class) \ goto bad; \ for (i = 0; i < vlen; ++i) { \ GETCHAR(cichar, p); \ if (cichar != val[i]) \ goto bad; \ } \ } ACKCISHORT(CI_MRU, go->neg_mru && go->mru != DEFMRU, go->mru); ACKCILONG(CI_ASYNCMAP, go->neg_asyncmap && go->asyncmap != 0xFFFFFFFF, go->asyncmap); #if EAP_SUPPORT ACKCISHORT(CI_AUTHTYPE, go->neg_eap, PPP_EAP); #endif /* EAP_SUPPORT */ #if CHAP_SUPPORT /* cannot be improved, embedding a directive within macro arguments is not portable */ #if EAP_SUPPORT ACKCICHAP(CI_AUTHTYPE, !go->neg_eap && go->neg_chap, go->chap_mdtype); #endif /* EAP_SUPPORT */ #if !EAP_SUPPORT ACKCICHAP(CI_AUTHTYPE, go->neg_chap, go->chap_mdtype); #endif /* !EAP_SUPPORT */ #endif /* CHAP_SUPPORT */ #if PAP_SUPPORT /* cannot be improved, embedding a directive within macro arguments is not portable */ #if EAP_SUPPORT && CHAP_SUPPORT ACKCISHORT(CI_AUTHTYPE, !go->neg_eap && !go->neg_chap && go->neg_upap, PPP_PAP); #endif /* EAP_SUPPORT && CHAP_SUPPORT */ #if EAP_SUPPORT && !CHAP_SUPPORT ACKCISHORT(CI_AUTHTYPE, !go->neg_eap && go->neg_upap, PPP_PAP); #endif /* EAP_SUPPORT && !CHAP_SUPPORT */ #if !EAP_SUPPORT && CHAP_SUPPORT ACKCISHORT(CI_AUTHTYPE, !go->neg_chap && go->neg_upap, PPP_PAP); #endif /* !EAP_SUPPORT && CHAP_SUPPORT */ #if !EAP_SUPPORT && !CHAP_SUPPORT ACKCISHORT(CI_AUTHTYPE, go->neg_upap, PPP_PAP); #endif /* !EAP_SUPPORT && !CHAP_SUPPORT */ #endif /* PAP_SUPPORT */ #if LQR_SUPPORT ACKCILQR(CI_QUALITY, go->neg_lqr, go->lqr_period); #endif /* LQR_SUPPORT */ ACKCICHAR(CI_CALLBACK, go->neg_cbcp, CBCP_OPT); ACKCILONG(CI_MAGICNUMBER, go->neg_magicnumber, go->magicnumber); ACKCIVOID(CI_PCOMPRESSION, go->neg_pcompression); ACKCIVOID(CI_ACCOMPRESSION, go->neg_accompression); #ifdef HAVE_MULTILINK ACKCISHORT(CI_MRRU, go->neg_mrru, go->mrru); #endif /* HAVE_MULTILINK */ ACKCIVOID(CI_SSNHF, go->neg_ssnhf); ACKCIENDP(CI_EPDISC, go->neg_endpoint, go->endpoint.class_, go->endpoint.value, go->endpoint.length); /* * If there are any remaining CIs, then this packet is bad. */ if (len != 0) goto bad; return (1); bad: LCPDEBUG(("lcp_acki: received bad Ack!")); return (0); } /* * lcp_nakci - Peer has sent a NAK for some of our CIs. * This should not modify any state if the Nak is bad * or if LCP is in the OPENED state. * * Returns: * 0 - Nak was bad. * 1 - Nak was good. */ static int lcp_nakci(fsm *f, u_char *p, int len, int treat_as_reject) { ppp_pcb *pcb = f->pcb; lcp_options *go = &pcb->lcp_gotoptions; lcp_options *wo = &pcb->lcp_wantoptions; u_char citype, cichar, *next; u_short cishort; u32_t cilong; lcp_options no; /* options we've seen Naks for */ lcp_options try_; /* options to request next time */ int looped_back = 0; int cilen; BZERO(&no, sizeof(no)); try_ = *go; /* * Any Nak'd CIs must be in exactly the same order that we sent. * Check packet length and CI length at each step. * If we find any deviations, then this packet is bad. */ #define NAKCIVOID(opt, neg) \ if (go->neg && \ len >= CILEN_VOID && \ p[1] == CILEN_VOID && \ p[0] == opt) { \ len -= CILEN_VOID; \ INCPTR(CILEN_VOID, p); \ no.neg = 1; \ try_.neg = 0; \ } #if CHAP_SUPPORT #define NAKCICHAP(opt, neg, code) \ if (go->neg && \ len >= CILEN_CHAP && \ p[1] == CILEN_CHAP && \ p[0] == opt) { \ len -= CILEN_CHAP; \ INCPTR(2, p); \ GETSHORT(cishort, p); \ GETCHAR(cichar, p); \ no.neg = 1; \ code \ } #endif /* CHAP_SUPPORT */ #define NAKCICHAR(opt, neg, code) \ if (go->neg && \ len >= CILEN_CHAR && \ p[1] == CILEN_CHAR && \ p[0] == opt) { \ len -= CILEN_CHAR; \ INCPTR(2, p); \ GETCHAR(cichar, p); \ no.neg = 1; \ code \ } #define NAKCISHORT(opt, neg, code) \ if (go->neg && \ len >= CILEN_SHORT && \ p[1] == CILEN_SHORT && \ p[0] == opt) { \ len -= CILEN_SHORT; \ INCPTR(2, p); \ GETSHORT(cishort, p); \ no.neg = 1; \ code \ } #define NAKCILONG(opt, neg, code) \ if (go->neg && \ len >= CILEN_LONG && \ p[1] == CILEN_LONG && \ p[0] == opt) { \ len -= CILEN_LONG; \ INCPTR(2, p); \ GETLONG(cilong, p); \ no.neg = 1; \ code \ } #if LQR_SUPPORT #define NAKCILQR(opt, neg, code) \ if (go->neg && \ len >= CILEN_LQR && \ p[1] == CILEN_LQR && \ p[0] == opt) { \ len -= CILEN_LQR; \ INCPTR(2, p); \ GETSHORT(cishort, p); \ GETLONG(cilong, p); \ no.neg = 1; \ code \ } #endif /* LQR_SUPPORT */ #define NAKCIENDP(opt, neg) \ if (go->neg && \ len >= CILEN_CHAR && \ p[0] == opt && \ p[1] >= CILEN_CHAR && \ p[1] <= len) { \ len -= p[1]; \ INCPTR(p[1], p); \ no.neg = 1; \ try_.neg = 0; \ } /* * NOTE! There must be no assignments to individual fields of *go in * the code below. Any such assignment is a BUG! */ /* * We don't care if they want to send us smaller packets than * we want. Therefore, accept any MRU less than what we asked for, * but then ignore the new value when setting the MRU in the kernel. * If they send us a bigger MRU than what we asked, accept it, up to * the limit of the default MRU we'd get if we didn't negotiate. */ if (go->neg_mru && go->mru != DEFMRU) { NAKCISHORT(CI_MRU, neg_mru, if (cishort <= wo->mru || cishort <= DEFMRU) try_.mru = cishort; ); } /* * Add any characters they want to our (receive-side) asyncmap. */ if (go->neg_asyncmap && go->asyncmap != 0xFFFFFFFF) { NAKCILONG(CI_ASYNCMAP, neg_asyncmap, try_.asyncmap = go->asyncmap | cilong; ); } /* * If they've nak'd our authentication-protocol, check whether * they are proposing a different protocol, or a different * hash algorithm for CHAP. */ if ((0 #if CHAP_SUPPORT || go->neg_chap #endif /* CHAP_SUPPORT */ #if PAP_SUPPORT || go->neg_upap #endif /* PAP_SUPPORT */ #if EAP_SUPPORT || go->neg_eap #endif /* EAP_SUPPORT */ ) && len >= CILEN_SHORT && p[0] == CI_AUTHTYPE && p[1] >= CILEN_SHORT && p[1] <= len) { cilen = p[1]; len -= cilen; #if CHAP_SUPPORT no.neg_chap = go->neg_chap; #endif /* CHAP_SUPPORT */ #if PAP_SUPPORT no.neg_upap = go->neg_upap; #endif /* PAP_SUPPORT */ #if EAP_SUPPORT no.neg_eap = go->neg_eap; #endif /* EAP_SUPPORT */ INCPTR(2, p); GETSHORT(cishort, p); #if PAP_SUPPORT if (cishort == PPP_PAP && cilen == CILEN_SHORT) { #if EAP_SUPPORT /* If we were asking for EAP, then we need to stop that. */ if (go->neg_eap) try_.neg_eap = 0; else #endif /* EAP_SUPPORT */ #if CHAP_SUPPORT /* If we were asking for CHAP, then we need to stop that. */ if (go->neg_chap) try_.neg_chap = 0; else #endif /* CHAP_SUPPORT */ /* * If we weren't asking for CHAP or EAP, then we were asking for * PAP, in which case this Nak is bad. */ goto bad; } else #endif /* PAP_SUPPORT */ #if CHAP_SUPPORT if (cishort == PPP_CHAP && cilen == CILEN_CHAP) { GETCHAR(cichar, p); #if EAP_SUPPORT /* Stop asking for EAP, if we were. */ if (go->neg_eap) { try_.neg_eap = 0; /* Try to set up to use their suggestion, if possible */ if (CHAP_CANDIGEST(go->chap_mdtype, cichar)) try_.chap_mdtype = CHAP_MDTYPE_D(cichar); } else #endif /* EAP_SUPPORT */ if (go->neg_chap) { /* * We were asking for our preferred algorithm, they must * want something different. */ if (cichar != CHAP_DIGEST(go->chap_mdtype)) { if (CHAP_CANDIGEST(go->chap_mdtype, cichar)) { /* Use their suggestion if we support it ... */ try_.chap_mdtype = CHAP_MDTYPE_D(cichar); } else { /* ... otherwise, try our next-preferred algorithm. */ try_.chap_mdtype &= ~(CHAP_MDTYPE(try_.chap_mdtype)); if (try_.chap_mdtype == MDTYPE_NONE) /* out of algos */ try_.neg_chap = 0; } } else { /* * Whoops, they Nak'd our algorithm of choice * but then suggested it back to us. */ goto bad; } } else { /* * Stop asking for PAP if we were asking for it. */ #if PAP_SUPPORT try_.neg_upap = 0; #endif /* PAP_SUPPORT */ } } else #endif /* CHAP_SUPPORT */ { #if EAP_SUPPORT /* * If we were asking for EAP, and they're Conf-Naking EAP, * well, that's just strange. Nobody should do that. */ if (cishort == PPP_EAP && cilen == CILEN_SHORT && go->neg_eap) ppp_dbglog("Unexpected Conf-Nak for EAP"); /* * We don't recognize what they're suggesting. * Stop asking for what we were asking for. */ if (go->neg_eap) try_.neg_eap = 0; else #endif /* EAP_SUPPORT */ #if CHAP_SUPPORT if (go->neg_chap) try_.neg_chap = 0; else #endif /* CHAP_SUPPORT */ #if PAP_SUPPORT if(1) try_.neg_upap = 0; else #endif /* PAP_SUPPORT */ {} p += cilen - CILEN_SHORT; } } #if LQR_SUPPORT /* * If they can't cope with our link quality protocol, we'll have * to stop asking for LQR. We haven't got any other protocol. * If they Nak the reporting period, take their value XXX ? */ NAKCILQR(CI_QUALITY, neg_lqr, if (cishort != PPP_LQR) try_.neg_lqr = 0; else try_.lqr_period = cilong; ); #endif /* LQR_SUPPORT */ /* * Only implementing CBCP...not the rest of the callback options */ NAKCICHAR(CI_CALLBACK, neg_cbcp, try_.neg_cbcp = 0; (void)cichar; /* if CHAP support is not compiled, cichar is set but not used, which makes some compilers complaining */ ); /* * Check for a looped-back line. */ NAKCILONG(CI_MAGICNUMBER, neg_magicnumber, try_.magicnumber = magic(); looped_back = 1; ); /* * Peer shouldn't send Nak for protocol compression or * address/control compression requests; they should send * a Reject instead. If they send a Nak, treat it as a Reject. */ NAKCIVOID(CI_PCOMPRESSION, neg_pcompression); NAKCIVOID(CI_ACCOMPRESSION, neg_accompression); #ifdef HAVE_MULTILINK /* * Nak for MRRU option - accept their value if it is smaller * than the one we want. */ if (go->neg_mrru) { NAKCISHORT(CI_MRRU, neg_mrru, if (treat_as_reject) try_.neg_mrru = 0; else if (cishort <= wo->mrru) try_.mrru = cishort; ); } #endif /* HAVE_MULTILINK */ /* * Nak for short sequence numbers shouldn't be sent, treat it * like a reject. */ NAKCIVOID(CI_SSNHF, neg_ssnhf); /* * Nak of the endpoint discriminator option is not permitted, * treat it like a reject. */ NAKCIENDP(CI_EPDISC, neg_endpoint); /* * There may be remaining CIs, if the peer is requesting negotiation * on an option that we didn't include in our request packet. * If we see an option that we requested, or one we've already seen * in this packet, then this packet is bad. * If we wanted to respond by starting to negotiate on the requested * option(s), we could, but we don't, because except for the * authentication type and quality protocol, if we are not negotiating * an option, it is because we were told not to. * For the authentication type, the Nak from the peer means * `let me authenticate myself with you' which is a bit pointless. * For the quality protocol, the Nak means `ask me to send you quality * reports', but if we didn't ask for them, we don't want them. * An option we don't recognize represents the peer asking to * negotiate some option we don't support, so ignore it. */ while (len >= CILEN_VOID) { GETCHAR(citype, p); GETCHAR(cilen, p); if (cilen < CILEN_VOID || (len -= cilen) < 0) goto bad; next = p + cilen - 2; switch (citype) { case CI_MRU: if ((go->neg_mru && go->mru != DEFMRU) || no.neg_mru || cilen != CILEN_SHORT) goto bad; GETSHORT(cishort, p); if (cishort < DEFMRU) { try_.neg_mru = 1; try_.mru = cishort; } break; case CI_ASYNCMAP: if ((go->neg_asyncmap && go->asyncmap != 0xFFFFFFFF) || no.neg_asyncmap || cilen != CILEN_LONG) goto bad; break; case CI_AUTHTYPE: if (0 #if CHAP_SUPPORT || go->neg_chap || no.neg_chap #endif /* CHAP_SUPPORT */ #if PAP_SUPPORT || go->neg_upap || no.neg_upap #endif /* PAP_SUPPORT */ #if EAP_SUPPORT || go->neg_eap || no.neg_eap #endif /* EAP_SUPPORT */ ) goto bad; break; case CI_MAGICNUMBER: if (go->neg_magicnumber || no.neg_magicnumber || cilen != CILEN_LONG) goto bad; break; case CI_PCOMPRESSION: if (go->neg_pcompression || no.neg_pcompression || cilen != CILEN_VOID) goto bad; break; case CI_ACCOMPRESSION: if (go->neg_accompression || no.neg_accompression || cilen != CILEN_VOID) goto bad; break; #if LQR_SUPPORT case CI_QUALITY: if (go->neg_lqr || no.neg_lqr || cilen != CILEN_LQR) goto bad; break; #endif /* LQR_SUPPORT */ #ifdef HAVE_MULTILINK case CI_MRRU: if (go->neg_mrru || no.neg_mrru || cilen != CILEN_SHORT) goto bad; break; #endif /* HAVE_MULTILINK */ case CI_SSNHF: if (go->neg_ssnhf || no.neg_ssnhf || cilen != CILEN_VOID) goto bad; try_.neg_ssnhf = 1; break; case CI_EPDISC: if (go->neg_endpoint || no.neg_endpoint || cilen < CILEN_CHAR) goto bad; break; } p = next; } /* * OK, the Nak is good. Now we can update state. * If there are any options left we ignore them. */ if (f->state != PPP_FSM_OPENED) { if (looped_back) { if (++try_.numloops >= pcb->settings.lcp_loopbackfail) { int errcode = PPPERR_LOOPBACK; ppp_notice("Serial line is looped back."); ppp_ioctl(pcb, PPPCTLS_ERRCODE, &errcode); lcp_close(f->pcb, "Loopback detected"); } } else try_.numloops = 0; *go = try_; } return 1; bad: LCPDEBUG(("lcp_nakci: received bad Nak!")); return 0; } /* * lcp_rejci - Peer has Rejected some of our CIs. * This should not modify any state if the Reject is bad * or if LCP is in the OPENED state. * * Returns: * 0 - Reject was bad. * 1 - Reject was good. */ static int lcp_rejci(fsm *f, u_char *p, int len) { ppp_pcb *pcb = f->pcb; lcp_options *go = &pcb->lcp_gotoptions; u_char cichar; u_short cishort; u32_t cilong; lcp_options try_; /* options to request next time */ try_ = *go; /* * Any Rejected CIs must be in exactly the same order that we sent. * Check packet length and CI length at each step. * If we find any deviations, then this packet is bad. */ #define REJCIVOID(opt, neg) \ if (go->neg && \ len >= CILEN_VOID && \ p[1] == CILEN_VOID && \ p[0] == opt) { \ len -= CILEN_VOID; \ INCPTR(CILEN_VOID, p); \ try_.neg = 0; \ } #define REJCISHORT(opt, neg, val) \ if (go->neg && \ len >= CILEN_SHORT && \ p[1] == CILEN_SHORT && \ p[0] == opt) { \ len -= CILEN_SHORT; \ INCPTR(2, p); \ GETSHORT(cishort, p); \ /* Check rejected value. */ \ if (cishort != val) \ goto bad; \ try_.neg = 0; \ } #if CHAP_SUPPORT && EAP_SUPPORT && PAP_SUPPORT #define REJCICHAP(opt, neg, val) \ if (go->neg && \ len >= CILEN_CHAP && \ p[1] == CILEN_CHAP && \ p[0] == opt) { \ len -= CILEN_CHAP; \ INCPTR(2, p); \ GETSHORT(cishort, p); \ GETCHAR(cichar, p); \ /* Check rejected value. */ \ if ((cishort != PPP_CHAP) || (cichar != (CHAP_DIGEST(val)))) \ goto bad; \ try_.neg = 0; \ try_.neg_eap = try_.neg_upap = 0; \ } #endif /* CHAP_SUPPORT && EAP_SUPPORT && PAP_SUPPORT */ #if CHAP_SUPPORT && !EAP_SUPPORT && PAP_SUPPORT #define REJCICHAP(opt, neg, val) \ if (go->neg && \ len >= CILEN_CHAP && \ p[1] == CILEN_CHAP && \ p[0] == opt) { \ len -= CILEN_CHAP; \ INCPTR(2, p); \ GETSHORT(cishort, p); \ GETCHAR(cichar, p); \ /* Check rejected value. */ \ if ((cishort != PPP_CHAP) || (cichar != (CHAP_DIGEST(val)))) \ goto bad; \ try_.neg = 0; \ try_.neg_upap = 0; \ } #endif /* CHAP_SUPPORT && !EAP_SUPPORT && PAP_SUPPORT */ #if CHAP_SUPPORT && EAP_SUPPORT && !PAP_SUPPORT #define REJCICHAP(opt, neg, val) \ if (go->neg && \ len >= CILEN_CHAP && \ p[1] == CILEN_CHAP && \ p[0] == opt) { \ len -= CILEN_CHAP; \ INCPTR(2, p); \ GETSHORT(cishort, p); \ GETCHAR(cichar, p); \ /* Check rejected value. */ \ if ((cishort != PPP_CHAP) || (cichar != (CHAP_DIGEST(val)))) \ goto bad; \ try_.neg = 0; \ try_.neg_eap = 0; \ } #endif /* CHAP_SUPPORT && EAP_SUPPORT && !PAP_SUPPORT */ #if CHAP_SUPPORT && !EAP_SUPPORT && !PAP_SUPPORT #define REJCICHAP(opt, neg, val) \ if (go->neg && \ len >= CILEN_CHAP && \ p[1] == CILEN_CHAP && \ p[0] == opt) { \ len -= CILEN_CHAP; \ INCPTR(2, p); \ GETSHORT(cishort, p); \ GETCHAR(cichar, p); \ /* Check rejected value. */ \ if ((cishort != PPP_CHAP) || (cichar != (CHAP_DIGEST(val)))) \ goto bad; \ try_.neg = 0; \ } #endif /* CHAP_SUPPORT && !EAP_SUPPORT && !PAP_SUPPORT */ #define REJCILONG(opt, neg, val) \ if (go->neg && \ len >= CILEN_LONG && \ p[1] == CILEN_LONG && \ p[0] == opt) { \ len -= CILEN_LONG; \ INCPTR(2, p); \ GETLONG(cilong, p); \ /* Check rejected value. */ \ if (cilong != val) \ goto bad; \ try_.neg = 0; \ } #if LQR_SUPPORT #define REJCILQR(opt, neg, val) \ if (go->neg && \ len >= CILEN_LQR && \ p[1] == CILEN_LQR && \ p[0] == opt) { \ len -= CILEN_LQR; \ INCPTR(2, p); \ GETSHORT(cishort, p); \ GETLONG(cilong, p); \ /* Check rejected value. */ \ if (cishort != PPP_LQR || cilong != val) \ goto bad; \ try_.neg = 0; \ } #endif /* LQR_SUPPORT */ #define REJCICBCP(opt, neg, val) \ if (go->neg && \ len >= CILEN_CBCP && \ p[1] == CILEN_CBCP && \ p[0] == opt) { \ len -= CILEN_CBCP; \ INCPTR(2, p); \ GETCHAR(cichar, p); \ /* Check rejected value. */ \ if (cichar != val) \ goto bad; \ try_.neg = 0; \ } #define REJCIENDP(opt, neg, class, val, vlen) \ if (go->neg && \ len >= CILEN_CHAR + vlen && \ p[0] == opt && \ p[1] == CILEN_CHAR + vlen) { \ int i; \ len -= CILEN_CHAR + vlen; \ INCPTR(2, p); \ GETCHAR(cichar, p); \ if (cichar != class) \ goto bad; \ for (i = 0; i < vlen; ++i) { \ GETCHAR(cichar, p); \ if (cichar != val[i]) \ goto bad; \ } \ try_.neg = 0; \ } REJCISHORT(CI_MRU, neg_mru, go->mru); REJCILONG(CI_ASYNCMAP, neg_asyncmap, go->asyncmap); #if EAP_SUPPORT REJCISHORT(CI_AUTHTYPE, neg_eap, PPP_EAP); if (!go->neg_eap) { #endif /* EAP_SUPPORT */ #if CHAP_SUPPORT REJCICHAP(CI_AUTHTYPE, neg_chap, go->chap_mdtype); if (!go->neg_chap) { #endif /* CHAP_SUPPORT */ #if PAP_SUPPORT REJCISHORT(CI_AUTHTYPE, neg_upap, PPP_PAP); #endif /* PAP_SUPPORT */ #if CHAP_SUPPORT } #endif /* CHAP_SUPPORT */ #if EAP_SUPPORT } #endif /* EAP_SUPPORT */ #if LQR_SUPPORT REJCILQR(CI_QUALITY, neg_lqr, go->lqr_period); #endif /* LQR_SUPPORT */ REJCICBCP(CI_CALLBACK, neg_cbcp, CBCP_OPT); REJCILONG(CI_MAGICNUMBER, neg_magicnumber, go->magicnumber); REJCIVOID(CI_PCOMPRESSION, neg_pcompression); REJCIVOID(CI_ACCOMPRESSION, neg_accompression); #ifdef HAVE_MULTILINK REJCISHORT(CI_MRRU, neg_mrru, go->mrru); #endif /* HAVE_MULTILINK */ REJCIVOID(CI_SSNHF, neg_ssnhf); REJCIENDP(CI_EPDISC, neg_endpoint, go->endpoint.class_, go->endpoint.value, go->endpoint.length); /* * If there are any remaining CIs, then this packet is bad. */ if (len != 0) goto bad; /* * Now we can update state. */ if (f->state != PPP_FSM_OPENED) *go = try_; return 1; bad: LCPDEBUG(("lcp_rejci: received bad Reject!")); return 0; } /* * lcp_reqci - Check the peer's requested CIs and send appropriate response. * * Returns: CONFACK, CONFNAK or CONFREJ and input packet modified * appropriately. If reject_if_disagree is non-zero, doesn't return * CONFNAK; returns CONFREJ if it can't return CONFACK. * * inp = Requested CIs * lenp = Length of requested CIs */ static int lcp_reqci(fsm *f, u_char *inp, int *lenp, int reject_if_disagree) { ppp_pcb *pcb = f->pcb; lcp_options *go = &pcb->lcp_gotoptions; lcp_options *ho = &pcb->lcp_hisoptions; lcp_options *ao = &pcb->lcp_allowoptions; u_char *cip, *next; /* Pointer to current and next CIs */ int cilen, citype, cichar; /* Parsed len, type, char value */ u_short cishort; /* Parsed short value */ u32_t cilong; /* Parse long value */ int rc = CONFACK; /* Final packet return code */ int orc; /* Individual option return code */ u_char *p; /* Pointer to next char to parse */ u_char *rejp; /* Pointer to next char in reject frame */ struct pbuf *nakp; /* Nak buffer */ u_char *nakoutp; /* Pointer to next char in Nak frame */ int l = *lenp; /* Length left */ /* * Reset all his options. */ BZERO(ho, sizeof(*ho)); /* * Process all his options. */ next = inp; nakp = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_CTRL_PBUF_MAX_SIZE), PPP_CTRL_PBUF_TYPE); if(NULL == nakp) return 0; if(nakp->tot_len != nakp->len) { pbuf_free(nakp); return 0; } nakoutp = nakp->payload; rejp = inp; while (l) { orc = CONFACK; /* Assume success */ cip = p = next; /* Remember begining of CI */ if (l < 2 || /* Not enough data for CI header or */ p[1] < 2 || /* CI length too small or */ p[1] > l) { /* CI length too big? */ LCPDEBUG(("lcp_reqci: bad CI length!")); orc = CONFREJ; /* Reject bad CI */ cilen = l; /* Reject till end of packet */ l = 0; /* Don't loop again */ citype = 0; goto endswitch; } GETCHAR(citype, p); /* Parse CI type */ GETCHAR(cilen, p); /* Parse CI length */ l -= cilen; /* Adjust remaining length */ next += cilen; /* Step to next CI */ switch (citype) { /* Check CI type */ case CI_MRU: if (!ao->neg_mru || /* Allow option? */ cilen != CILEN_SHORT) { /* Check CI length */ orc = CONFREJ; /* Reject CI */ break; } GETSHORT(cishort, p); /* Parse MRU */ /* * He must be able to receive at least our minimum. * No need to check a maximum. If he sends a large number, * we'll just ignore it. */ if (cishort < MINMRU) { orc = CONFNAK; /* Nak CI */ PUTCHAR(CI_MRU, nakoutp); PUTCHAR(CILEN_SHORT, nakoutp); PUTSHORT(MINMRU, nakoutp); /* Give him a hint */ break; } ho->neg_mru = 1; /* Remember he sent MRU */ ho->mru = cishort; /* And remember value */ break; case CI_ASYNCMAP: if (!ao->neg_asyncmap || cilen != CILEN_LONG) { orc = CONFREJ; break; } GETLONG(cilong, p); /* * Asyncmap must have set at least the bits * which are set in lcp_allowoptions[unit].asyncmap. */ if ((ao->asyncmap & ~cilong) != 0) { orc = CONFNAK; PUTCHAR(CI_ASYNCMAP, nakoutp); PUTCHAR(CILEN_LONG, nakoutp); PUTLONG(ao->asyncmap | cilong, nakoutp); break; } ho->neg_asyncmap = 1; ho->asyncmap = cilong; break; case CI_AUTHTYPE: if (cilen < CILEN_SHORT || !(0 #if PAP_SUPPORT || ao->neg_upap #endif /* PAP_SUPPORT */ #if CHAP_SUPPORT || ao->neg_chap #endif /* CHAP_SUPPORT */ #if EAP_SUPPORT || ao->neg_eap #endif /* EAP_SUPPORT */ )) { /* * Reject the option if we're not willing to authenticate. */ ppp_dbglog("No auth is possible"); orc = CONFREJ; break; } GETSHORT(cishort, p); /* * Authtype must be PAP, CHAP, or EAP. * * Note: if more than one of ao->neg_upap, ao->neg_chap, and * ao->neg_eap are set, and the peer sends a Configure-Request * with two or more authenticate-protocol requests, then we will * reject the second request. * Whether we end up doing CHAP, UPAP, or EAP depends then on * the ordering of the CIs in the peer's Configure-Request. */ #if PAP_SUPPORT if (cishort == PPP_PAP) { /* we've already accepted CHAP or EAP */ if (0 #if CHAP_SUPPORT || ho->neg_chap #endif /* CHAP_SUPPORT */ #if EAP_SUPPORT || ho->neg_eap #endif /* EAP_SUPPORT */ || cilen != CILEN_SHORT) { LCPDEBUG(("lcp_reqci: rcvd AUTHTYPE PAP, rejecting...")); orc = CONFREJ; break; } if (!ao->neg_upap) { /* we don't want to do PAP */ orc = CONFNAK; /* NAK it and suggest CHAP or EAP */ PUTCHAR(CI_AUTHTYPE, nakoutp); #if EAP_SUPPORT if (ao->neg_eap) { PUTCHAR(CILEN_SHORT, nakoutp); PUTSHORT(PPP_EAP, nakoutp); } else { #endif /* EAP_SUPPORT */ #if CHAP_SUPPORT PUTCHAR(CILEN_CHAP, nakoutp); PUTSHORT(PPP_CHAP, nakoutp); PUTCHAR(CHAP_DIGEST(ao->chap_mdtype), nakoutp); #endif /* CHAP_SUPPORT */ #if EAP_SUPPORT } #endif /* EAP_SUPPORT */ break; } ho->neg_upap = 1; break; } #endif /* PAP_SUPPORT */ #if CHAP_SUPPORT if (cishort == PPP_CHAP) { /* we've already accepted PAP or EAP */ if ( #if PAP_SUPPORT ho->neg_upap || #endif /* PAP_SUPPORT */ #if EAP_SUPPORT ho->neg_eap || #endif /* EAP_SUPPORT */ cilen != CILEN_CHAP) { LCPDEBUG(("lcp_reqci: rcvd AUTHTYPE CHAP, rejecting...")); orc = CONFREJ; break; } if (!ao->neg_chap) { /* we don't want to do CHAP */ orc = CONFNAK; /* NAK it and suggest EAP or PAP */ PUTCHAR(CI_AUTHTYPE, nakoutp); PUTCHAR(CILEN_SHORT, nakoutp); #if EAP_SUPPORT if (ao->neg_eap) { PUTSHORT(PPP_EAP, nakoutp); } else #endif /* EAP_SUPPORT */ #if PAP_SUPPORT if(1) { PUTSHORT(PPP_PAP, nakoutp); } else #endif /* PAP_SUPPORT */ {} break; } GETCHAR(cichar, p); /* get digest type */ if (!(CHAP_CANDIGEST(ao->chap_mdtype, cichar))) { /* * We can't/won't do the requested type, * suggest something else. */ orc = CONFNAK; PUTCHAR(CI_AUTHTYPE, nakoutp); PUTCHAR(CILEN_CHAP, nakoutp); PUTSHORT(PPP_CHAP, nakoutp); PUTCHAR(CHAP_DIGEST(ao->chap_mdtype), nakoutp); break; } ho->chap_mdtype = CHAP_MDTYPE_D(cichar); /* save md type */ ho->neg_chap = 1; break; } #endif /* CHAP_SUPPORT */ #if EAP_SUPPORT if (cishort == PPP_EAP) { /* we've already accepted CHAP or PAP */ if ( #if CHAP_SUPPORT ho->neg_chap || #endif /* CHAP_SUPPORT */ #if PAP_SUPPORT ho->neg_upap || #endif /* PAP_SUPPORT */ cilen != CILEN_SHORT) { LCPDEBUG(("lcp_reqci: rcvd AUTHTYPE EAP, rejecting...")); orc = CONFREJ; break; } if (!ao->neg_eap) { /* we don't want to do EAP */ orc = CONFNAK; /* NAK it and suggest CHAP or PAP */ PUTCHAR(CI_AUTHTYPE, nakoutp); #if CHAP_SUPPORT if (ao->neg_chap) { PUTCHAR(CILEN_CHAP, nakoutp); PUTSHORT(PPP_CHAP, nakoutp); PUTCHAR(CHAP_DIGEST(ao->chap_mdtype), nakoutp); } else #endif /* CHAP_SUPPORT */ #if PAP_SUPPORT if(1) { PUTCHAR(CILEN_SHORT, nakoutp); PUTSHORT(PPP_PAP, nakoutp); } else #endif /* PAP_SUPPORT */ {} break; } ho->neg_eap = 1; break; } #endif /* EAP_SUPPORT */ /* * We don't recognize the protocol they're asking for. * Nak it with something we're willing to do. * (At this point we know ao->neg_upap || ao->neg_chap || * ao->neg_eap.) */ orc = CONFNAK; PUTCHAR(CI_AUTHTYPE, nakoutp); #if EAP_SUPPORT if (ao->neg_eap) { PUTCHAR(CILEN_SHORT, nakoutp); PUTSHORT(PPP_EAP, nakoutp); } else #endif /* EAP_SUPPORT */ #if CHAP_SUPPORT if (ao->neg_chap) { PUTCHAR(CILEN_CHAP, nakoutp); PUTSHORT(PPP_CHAP, nakoutp); PUTCHAR(CHAP_DIGEST(ao->chap_mdtype), nakoutp); } else #endif /* CHAP_SUPPORT */ #if PAP_SUPPORT if(1) { PUTCHAR(CILEN_SHORT, nakoutp); PUTSHORT(PPP_PAP, nakoutp); } else #endif /* PAP_SUPPORT */ {} break; #if LQR_SUPPORT case CI_QUALITY: if (!ao->neg_lqr || cilen != CILEN_LQR) { orc = CONFREJ; break; } GETSHORT(cishort, p); GETLONG(cilong, p); /* * Check the protocol and the reporting period. * XXX When should we Nak this, and what with? */ if (cishort != PPP_LQR) { orc = CONFNAK; PUTCHAR(CI_QUALITY, nakoutp); PUTCHAR(CILEN_LQR, nakoutp); PUTSHORT(PPP_LQR, nakoutp); PUTLONG(ao->lqr_period, nakoutp); break; } break; #endif /* LQR_SUPPORT */ case CI_MAGICNUMBER: if (!(ao->neg_magicnumber || go->neg_magicnumber) || cilen != CILEN_LONG) { orc = CONFREJ; break; } GETLONG(cilong, p); /* * He must have a different magic number. */ if (go->neg_magicnumber && cilong == go->magicnumber) { cilong = magic(); /* Don't put magic() inside macro! */ orc = CONFNAK; PUTCHAR(CI_MAGICNUMBER, nakoutp); PUTCHAR(CILEN_LONG, nakoutp); PUTLONG(cilong, nakoutp); break; } ho->neg_magicnumber = 1; ho->magicnumber = cilong; break; case CI_PCOMPRESSION: if (!ao->neg_pcompression || cilen != CILEN_VOID) { orc = CONFREJ; break; } ho->neg_pcompression = 1; break; case CI_ACCOMPRESSION: if (!ao->neg_accompression || cilen != CILEN_VOID) { orc = CONFREJ; break; } ho->neg_accompression = 1; break; #ifdef HAVE_MULTILINK case CI_MRRU: if (!ao->neg_mrru || !multilink || cilen != CILEN_SHORT) { orc = CONFREJ; break; } GETSHORT(cishort, p); /* possibly should insist on a minimum/maximum MRRU here */ ho->neg_mrru = 1; ho->mrru = cishort; break; #endif /* HAVE_MULTILINK */ case CI_SSNHF: if (!ao->neg_ssnhf #ifdef HAVE_MULTILINK || !multilink #endif /* HAVE_MULTILINK */ || cilen != CILEN_VOID) { orc = CONFREJ; break; } ho->neg_ssnhf = 1; break; case CI_EPDISC: if (!ao->neg_endpoint || cilen < CILEN_CHAR || cilen > CILEN_CHAR + MAX_ENDP_LEN) { orc = CONFREJ; break; } GETCHAR(cichar, p); cilen -= CILEN_CHAR; ho->neg_endpoint = 1; ho->endpoint.class_ = cichar; ho->endpoint.length = cilen; MEMCPY(ho->endpoint.value, p, cilen); INCPTR(cilen, p); break; default: LCPDEBUG(("lcp_reqci: rcvd unknown option %d", citype)); orc = CONFREJ; break; } endswitch: if (orc == CONFACK && /* Good CI */ rc != CONFACK) /* but prior CI wasnt? */ continue; /* Don't send this one */ if (orc == CONFNAK) { /* Nak this CI? */ if (reject_if_disagree /* Getting fed up with sending NAKs? */ && citype != CI_MAGICNUMBER) { orc = CONFREJ; /* Get tough if so */ } else { if (rc == CONFREJ) /* Rejecting prior CI? */ continue; /* Don't send this one */ rc = CONFNAK; } } if (orc == CONFREJ) { /* Reject this CI */ rc = CONFREJ; if (cip != rejp) /* Need to move rejected CI? */ MEMCPY(rejp, cip, cilen); /* Move it */ INCPTR(cilen, rejp); /* Update output pointer */ } } /* * If we wanted to send additional NAKs (for unsent CIs), the * code would go here. The extra NAKs would go at *nakoutp. * At present there are no cases where we want to ask the * peer to negotiate an option. */ switch (rc) { case CONFACK: *lenp = next - inp; break; case CONFNAK: /* * Copy the Nak'd options from the nak buffer to the caller's buffer. */ *lenp = nakoutp - (u_char*)nakp->payload; MEMCPY(inp, nakp->payload, *lenp); break; case CONFREJ: *lenp = rejp - inp; break; } pbuf_free(nakp); LCPDEBUG(("lcp_reqci: returning CONF%s.", CODENAME(rc))); return (rc); /* Return final code */ } /* * lcp_up - LCP has come UP. */ static void lcp_up(fsm *f) { ppp_pcb *pcb = f->pcb; lcp_options *wo = &pcb->lcp_wantoptions; lcp_options *ho = &pcb->lcp_hisoptions; lcp_options *go = &pcb->lcp_gotoptions; lcp_options *ao = &pcb->lcp_allowoptions; int mtu, mru; if (!go->neg_magicnumber) go->magicnumber = 0; if (!ho->neg_magicnumber) ho->magicnumber = 0; /* * Set our MTU to the smaller of the MTU we wanted and * the MRU our peer wanted. If we negotiated an MRU, * set our MRU to the larger of value we wanted and * the value we got in the negotiation. * Note on the MTU: the link MTU can be the MRU the peer wanted, * the interface MTU is set to the lowest of that, the * MTU we want to use, and our link MRU. */ mtu = ho->neg_mru? ho->mru: PPP_MRU; mru = go->neg_mru? LWIP_MAX(wo->mru, go->mru): PPP_MRU; #ifdef HAVE_MULTILINK if (!(multilink && go->neg_mrru && ho->neg_mrru)) #endif /* HAVE_MULTILINK */ netif_set_mtu(pcb, LWIP_MIN(LWIP_MIN(mtu, mru), ao->mru)); ppp_send_config(pcb, mtu, (ho->neg_asyncmap? ho->asyncmap: 0xffffffff), ho->neg_pcompression, ho->neg_accompression); ppp_recv_config(pcb, mru, (pcb->settings.lax_recv? 0: go->neg_asyncmap? go->asyncmap: 0xffffffff), go->neg_pcompression, go->neg_accompression); if (ho->neg_mru) pcb->peer_mru = ho->mru; lcp_echo_lowerup(f->pcb); /* Enable echo messages */ link_established(pcb); } /* * lcp_down - LCP has gone DOWN. * * Alert other protocols. */ static void lcp_down(fsm *f) { ppp_pcb *pcb = f->pcb; lcp_options *go = &pcb->lcp_gotoptions; lcp_echo_lowerdown(f->pcb); link_down(pcb); ppp_send_config(pcb, PPP_MRU, 0xffffffff, 0, 0); ppp_recv_config(pcb, PPP_MRU, (go->neg_asyncmap? go->asyncmap: 0xffffffff), go->neg_pcompression, go->neg_accompression); pcb->peer_mru = PPP_MRU; } /* * lcp_starting - LCP needs the lower layer up. */ static void lcp_starting(fsm *f) { ppp_pcb *pcb = f->pcb; link_required(pcb); } /* * lcp_finished - LCP has finished with the lower layer. */ static void lcp_finished(fsm *f) { ppp_pcb *pcb = f->pcb; link_terminated(pcb); } #if PRINTPKT_SUPPORT /* * lcp_printpkt - print the contents of an LCP packet. */ static char *lcp_codenames[] = { "ConfReq", "ConfAck", "ConfNak", "ConfRej", "TermReq", "TermAck", "CodeRej", "ProtRej", "EchoReq", "EchoRep", "DiscReq", "Ident", "TimeRem" }; static int lcp_printpkt(u_char *p, int plen, void (*printer) (void *, char *, ...), void *arg) { int code, id, len, olen, i; u_char *pstart, *optend; u_short cishort; u32_t cilong; if (plen < HEADERLEN) return 0; pstart = p; GETCHAR(code, p); GETCHAR(id, p); GETSHORT(len, p); if (len < HEADERLEN || len > plen) return 0; if (code >= 1 && code <= sizeof(lcp_codenames) / sizeof(char *)) printer(arg, " %s", lcp_codenames[code-1]); else printer(arg, " code=0x%x", code); printer(arg, " id=0x%x", id); len -= HEADERLEN; switch (code) { case CONFREQ: case CONFACK: case CONFNAK: case CONFREJ: /* print option list */ while (len >= 2) { GETCHAR(code, p); GETCHAR(olen, p); p -= 2; if (olen < 2 || olen > len) { break; } printer(arg, " <"); len -= olen; optend = p + olen; switch (code) { case CI_MRU: if (olen == CILEN_SHORT) { p += 2; GETSHORT(cishort, p); printer(arg, "mru %d", cishort); } break; case CI_ASYNCMAP: if (olen == CILEN_LONG) { p += 2; GETLONG(cilong, p); printer(arg, "asyncmap 0x%x", cilong); } break; case CI_AUTHTYPE: if (olen >= CILEN_SHORT) { p += 2; printer(arg, "auth "); GETSHORT(cishort, p); switch (cishort) { #if PAP_SUPPORT case PPP_PAP: printer(arg, "pap"); break; #endif /* PAP_SUPPORT */ #if CHAP_SUPPORT case PPP_CHAP: printer(arg, "chap"); if (p < optend) { switch (*p) { case CHAP_MD5: printer(arg, " MD5"); ++p; break; #if MSCHAP_SUPPORT case CHAP_MICROSOFT: printer(arg, " MS"); ++p; break; case CHAP_MICROSOFT_V2: printer(arg, " MS-v2"); ++p; break; #endif /* MSCHAP_SUPPORT */ } } break; #endif /* CHAP_SUPPORT */ #if EAP_SUPPORT case PPP_EAP: printer(arg, "eap"); break; #endif /* EAP_SUPPORT */ default: printer(arg, "0x%x", cishort); } } break; #if LQR_SUPPORT case CI_QUALITY: if (olen >= CILEN_SHORT) { p += 2; printer(arg, "quality "); GETSHORT(cishort, p); switch (cishort) { case PPP_LQR: printer(arg, "lqr"); break; default: printer(arg, "0x%x", cishort); } } break; #endif /* LQR_SUPPORT */ case CI_CALLBACK: if (olen >= CILEN_CHAR) { p += 2; printer(arg, "callback "); GETCHAR(cishort, p); switch (cishort) { case CBCP_OPT: printer(arg, "CBCP"); break; default: printer(arg, "0x%x", cishort); } } break; case CI_MAGICNUMBER: if (olen == CILEN_LONG) { p += 2; GETLONG(cilong, p); printer(arg, "magic 0x%x", cilong); } break; case CI_PCOMPRESSION: if (olen == CILEN_VOID) { p += 2; printer(arg, "pcomp"); } break; case CI_ACCOMPRESSION: if (olen == CILEN_VOID) { p += 2; printer(arg, "accomp"); } break; case CI_MRRU: if (olen == CILEN_SHORT) { p += 2; GETSHORT(cishort, p); printer(arg, "mrru %d", cishort); } break; case CI_SSNHF: if (olen == CILEN_VOID) { p += 2; printer(arg, "ssnhf"); } break; case CI_EPDISC: #ifdef HAVE_MULTILINK if (olen >= CILEN_CHAR) { struct epdisc epd; p += 2; GETCHAR(epd.class, p); epd.length = olen - CILEN_CHAR; if (epd.length > MAX_ENDP_LEN) epd.length = MAX_ENDP_LEN; if (epd.length > 0) { MEMCPY(epd.value, p, epd.length); p += epd.length; } printer(arg, "endpoint [%s]", epdisc_to_str(&epd)); } #else printer(arg, "endpoint"); #endif break; } while (p < optend) { GETCHAR(code, p); printer(arg, " %.2x", code); } printer(arg, ">"); } break; case TERMACK: case TERMREQ: if (len > 0 && *p >= ' ' && *p < 0x7f) { printer(arg, " "); ppp_print_string((char *)p, len, printer, arg); p += len; len = 0; } break; case ECHOREQ: case ECHOREP: case DISCREQ: if (len >= 4) { GETLONG(cilong, p); printer(arg, " magic=0x%x", cilong); len -= 4; } break; case IDENTIF: case TIMEREM: if (len >= 4) { GETLONG(cilong, p); printer(arg, " magic=0x%x", cilong); len -= 4; } if (code == TIMEREM) { if (len < 4) break; GETLONG(cilong, p); printer(arg, " seconds=%u", cilong); len -= 4; } if (len > 0) { printer(arg, " "); ppp_print_string((char *)p, len, printer, arg); p += len; len = 0; } break; } /* print the rest of the bytes in the packet */ for (i = 0; i < len && i < 32; ++i) { GETCHAR(code, p); printer(arg, " %.2x", code); } if (i < len) { printer(arg, " ..."); p += len - i; } return p - pstart; } #endif /* PRINTPKT_SUPPORT */ /* * Time to shut down the link because there is nothing out there. */ static void LcpLinkFailure(fsm *f) { ppp_pcb *pcb = f->pcb; if (f->state == PPP_FSM_OPENED) { int errcode = PPPERR_PEERDEAD; ppp_info("No response to %d echo-requests", pcb->lcp_echos_pending); ppp_notice("Serial link appears to be disconnected."); ppp_ioctl(pcb, PPPCTLS_ERRCODE, &errcode); lcp_close(pcb, "Peer not responding"); } } /* * Timer expired for the LCP echo requests from this process. */ static void LcpEchoCheck(fsm *f) { ppp_pcb *pcb = f->pcb; LcpSendEchoRequest (f); if (f->state != PPP_FSM_OPENED) return; /* * Start the timer for the next interval. */ if (pcb->lcp_echo_timer_running) ppp_warn("assertion lcp_echo_timer_running==0 failed"); TIMEOUT (LcpEchoTimeout, f, pcb->settings.lcp_echo_interval); pcb->lcp_echo_timer_running = 1; } /* * LcpEchoTimeout - Timer expired on the LCP echo */ static void LcpEchoTimeout(void *arg) { fsm *f = (fsm*)arg; ppp_pcb *pcb = f->pcb; if (pcb->lcp_echo_timer_running != 0) { pcb->lcp_echo_timer_running = 0; LcpEchoCheck ((fsm *) arg); } } /* * LcpEchoReply - LCP has received a reply to the echo */ static void lcp_received_echo_reply(fsm *f, int id, u_char *inp, int len) { ppp_pcb *pcb = f->pcb; lcp_options *go = &pcb->lcp_gotoptions; u32_t magic; /* Check the magic number - don't count replies from ourselves. */ if (len < 4) { ppp_dbglog("lcp: received short Echo-Reply, length %d", len); return; } GETLONG(magic, inp); if (go->neg_magicnumber && magic == go->magicnumber) { ppp_warn("appear to have received our own echo-reply!"); return; } /* Reset the number of outstanding echo frames */ pcb->lcp_echos_pending = 0; } /* * LcpSendEchoRequest - Send an echo request frame to the peer */ static void LcpSendEchoRequest(fsm *f) { ppp_pcb *pcb = f->pcb; lcp_options *go = &pcb->lcp_gotoptions; u32_t lcp_magic; u_char pkt[4], *pktp; /* * Detect the failure of the peer at this point. */ if (pcb->settings.lcp_echo_fails != 0) { if (pcb->lcp_echos_pending >= pcb->settings.lcp_echo_fails) { LcpLinkFailure(f); pcb->lcp_echos_pending = 0; } } #if PPP_LCP_ADAPTIVE /* * If adaptive echos have been enabled, only send the echo request if * no traffic was received since the last one. */ if (pcb->settings.lcp_echo_adaptive) { static unsigned int last_pkts_in = 0; #if PPP_STATS_SUPPORT update_link_stats(f->unit); link_stats_valid = 0; #endif /* PPP_STATS_SUPPORT */ if (link_stats.pkts_in != last_pkts_in) { last_pkts_in = link_stats.pkts_in; return; } } #endif /* * Make and send the echo request frame. */ if (f->state == PPP_FSM_OPENED) { lcp_magic = go->magicnumber; pktp = pkt; PUTLONG(lcp_magic, pktp); fsm_sdata(f, ECHOREQ, pcb->lcp_echo_number++, pkt, pktp - pkt); ++pcb->lcp_echos_pending; } } /* * lcp_echo_lowerup - Start the timer for the LCP frame */ static void lcp_echo_lowerup(ppp_pcb *pcb) { fsm *f = &pcb->lcp_fsm; /* Clear the parameters for generating echo frames */ pcb->lcp_echos_pending = 0; pcb->lcp_echo_number = 0; pcb->lcp_echo_timer_running = 0; /* If a timeout interval is specified then start the timer */ if (pcb->settings.lcp_echo_interval != 0) LcpEchoCheck (f); } /* * lcp_echo_lowerdown - Stop the timer for the LCP frame */ static void lcp_echo_lowerdown(ppp_pcb *pcb) { fsm *f = &pcb->lcp_fsm; if (pcb->lcp_echo_timer_running != 0) { UNTIMEOUT (LcpEchoTimeout, f); pcb->lcp_echo_timer_running = 0; } } #endif /* PPP_SUPPORT */ ocproxy-1.60/lwip/src/netif/ppp/magic.c000066400000000000000000000223731303453231400200420ustar00rootroot00000000000000/* * magic.c - PPP Magic Number routines. * * Copyright (c) 1984-2000 Carnegie Mellon University. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The name "Carnegie Mellon University" must not be used to * endorse or promote products derived from this software without * prior written permission. For permission or any legal * details, please contact * Office of Technology Transfer * Carnegie Mellon University * 5000 Forbes Avenue * Pittsburgh, PA 15213-3890 * (412) 268-4387, fax: (412) 268-7395 * tech-transfer@andrew.cmu.edu * * 4. Redistributions of any form whatsoever must retain the following * acknowledgment: * "This product includes software developed by Computing Services * at Carnegie Mellon University (http://www.cmu.edu/computing/)." * * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /***************************************************************************** * randm.c - Random number generator program file. * * Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc. * Copyright (c) 1998 by Global Election Systems Inc. * * The authors hereby grant permission to use, copy, modify, distribute, * and license this software and its documentation for any purpose, provided * that existing copyright notices are retained in all copies and that this * notice and the following disclaimer are included verbatim in any * distributions. No written agreement, license, or royalty fee is required * for any of the authorized uses. * * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ****************************************************************************** * REVISION HISTORY * * 03-01-01 Marc Boucher * Ported to lwIP. * 98-06-03 Guy Lancaster , Global Election Systems Inc. * Extracted from avos. *****************************************************************************/ #include "lwip/opt.h" #if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */ #include "netif/ppp/ppp_impl.h" #include "netif/ppp/magic.h" #if PPP_MD5_RANDM /* Using MD5 for better randomness if enabled */ #if LWIP_INCLUDED_POLARSSL_MD5 #include "netif/ppp/polarssl/md5.h" #else #include "polarssl/md5.h" #endif #define MAGIC_RANDPOOLSIZE 16 /* Bytes stored in the pool of randomness. */ /*****************************/ /*** LOCAL DATA STRUCTURES ***/ /*****************************/ static char magic_randpool[MAGIC_RANDPOOLSIZE]; /* Pool of randomness. */ static long magic_randcount = 0; /* Pseudo-random incrementer */ /***********************************/ /*** PUBLIC FUNCTION DEFINITIONS ***/ /***********************************/ /* * Churn the randomness pool on a random event. Call this early and often * on random and semi-random system events to build randomness in time for * usage. For randomly timed events, pass a null pointer and a zero length * and this will use the system timer and other sources to add randomness. * If new random data is available, pass a pointer to that and it will be * included. * * Ref: Applied Cryptography 2nd Ed. by Bruce Schneier p. 427 */ void magic_churnrand(char *rand_data, u32_t rand_len) { md5_context md5; /* LWIP_DEBUGF(LOG_INFO, ("magic_churnrand: %u@%P\n", rand_len, rand_data)); */ md5_starts(&md5); md5_update(&md5, (u_char *)magic_randpool, sizeof(magic_randpool)); if (rand_data) { md5_update(&md5, (u_char *)rand_data, rand_len); } else { struct { /* INCLUDE fields for any system sources of randomness */ u32_t jiffies; } sys_data; sys_data.jiffies = sys_jiffies(); /* Load sys_data fields here. */ md5_update(&md5, (u_char *)&sys_data, sizeof(sys_data)); } md5_finish(&md5, (u_char *)magic_randpool); /* LWIP_DEBUGF(LOG_INFO, ("magic_churnrand: -> 0\n")); */ } /* * Initialize the random number generator. */ void magic_init() { magic_churnrand(NULL, 0); } /* * Randomize our random seed value. */ void magic_randomize(void) { magic_churnrand(NULL, 0); } /* * random_bytes - Fill a buffer with random bytes. * * Use the random pool to generate random data. This degrades to pseudo * random when used faster than randomness is supplied using magic_churnrand(). * Note: It's important that there be sufficient randomness in magic_randpool * before this is called for otherwise the range of the result may be * narrow enough to make a search feasible. * * Ref: Applied Cryptography 2nd Ed. by Bruce Schneier p. 427 * * XXX Why does he not just call magic_churnrand() for each block? Probably * so that you don't ever publish the seed which could possibly help * predict future values. * XXX Why don't we preserve md5 between blocks and just update it with * magic_randcount each time? Probably there is a weakness but I wish that * it was documented. */ void random_bytes(unsigned char *buf, u32_t buf_len) { md5_context md5; u_char tmp[16]; u32_t n; while (buf_len > 0) { n = LWIP_MIN(buf_len, MAGIC_RANDPOOLSIZE); md5_starts(&md5); md5_update(&md5, (u_char *)magic_randpool, sizeof(magic_randpool)); md5_update(&md5, (u_char *)&magic_randcount, sizeof(magic_randcount)); md5_finish(&md5, tmp); magic_randcount++; MEMCPY(buf, tmp, n); buf += n; buf_len -= n; } } /* * Return a new random number. */ u32_t magic() { u32_t new_rand; random_bytes((unsigned char *)&new_rand, sizeof(new_rand)); return new_rand; } #else /* PPP_MD5_RANDM */ /*****************************/ /*** LOCAL DATA STRUCTURES ***/ /*****************************/ static int magic_randomized = 0; /* Set when truely randomized. */ static u32_t magic_randomseed = 0; /* Seed used for random number generation. */ /***********************************/ /*** PUBLIC FUNCTION DEFINITIONS ***/ /***********************************/ /* * Initialize the random number generator. * * Here we attempt to compute a random number seed but even if * it isn't random, we'll randomize it later. * * The current method uses the fields from the real time clock, * the idle process counter, the millisecond counter, and the * hardware timer tick counter. When this is invoked * in startup(), then the idle counter and timer values may * repeat after each boot and the real time clock may not be * operational. Thus we call it again on the first random * event. */ void magic_init() { magic_randomseed += sys_jiffies(); /* Initialize the Borland random number generator. */ srand((unsigned)magic_randomseed); } /* * magic_init - Initialize the magic number generator. * * Randomize our random seed value. Here we use the fact that * this function is called at *truely random* times by the polling * and network functions. Here we only get 16 bits of new random * value but we use the previous value to randomize the other 16 * bits. */ void magic_randomize(void) { static u32_t last_jiffies; if (!magic_randomized) { magic_randomized = !0; magic_init(); /* The initialization function also updates the seed. */ } else { /* magic_randomseed += (magic_randomseed << 16) + TM1; */ magic_randomseed += (sys_jiffies() - last_jiffies); /* XXX */ } last_jiffies = sys_jiffies(); } /* * Return a new random number. * * Here we use the Borland rand() function to supply a pseudo random * number which we make truely random by combining it with our own * seed which is randomized by truely random events. * Thus the numbers will be truely random unless there have been no * operator or network events in which case it will be pseudo random * seeded by the real time clock. */ u32_t magic() { return ((((u32_t)rand() << 16) + rand()) + magic_randomseed); } #endif /* PPP_MD5_RANDM */ #endif /* PPP_SUPPORT */ ocproxy-1.60/lwip/src/netif/ppp/multilink.c000066400000000000000000000332641303453231400207730ustar00rootroot00000000000000/* * multilink.c - support routines for multilink. * * Copyright (c) 2000-2002 Paul Mackerras. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. The name(s) of the authors of this software must not be used to * endorse or promote products derived from this software without * prior written permission. * * 3. Redistributions of any form whatsoever must retain the following * acknowledgment: * "This product includes software developed by Paul Mackerras * ". * * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "lwip/opt.h" #if PPP_SUPPORT && HAVE_MULTILINK /* don't build if not configured for use in lwipopts.h */ /* Multilink support * * Multilink uses Samba TDB (Trivial Database Library), which * we cannot port, because it needs a filesystem. * * We have to choose between doing a memory-shared TDB-clone, * or dropping multilink support at all. */ #include #include #include #include #include #include #include #include #include "netif/ppp/ppp_impl.h" #include "netif/ppp/fsm.h" #include "netif/ppp/lcp.h" #include "netif/ppp/tdb.h" bool endpoint_specified; /* user gave explicit endpoint discriminator */ char *bundle_id; /* identifier for our bundle */ char *blinks_id; /* key for the list of links */ bool doing_multilink; /* multilink was enabled and agreed to */ bool multilink_master; /* we own the multilink bundle */ extern TDB_CONTEXT *pppdb; extern char db_key[]; static void make_bundle_links (int append); static void remove_bundle_link (void); static void iterate_bundle_links (void (*func) (char *)); static int get_default_epdisc (struct epdisc *); static int parse_num (char *str, const char *key, int *valp); static int owns_unit (TDB_DATA pid, int unit); #define set_ip_epdisc(ep, addr) do { \ ep->length = 4; \ ep->value[0] = addr >> 24; \ ep->value[1] = addr >> 16; \ ep->value[2] = addr >> 8; \ ep->value[3] = addr; \ } while (0) #define LOCAL_IP_ADDR(addr) \ (((addr) & 0xff000000) == 0x0a000000 /* 10.x.x.x */ \ || ((addr) & 0xfff00000) == 0xac100000 /* 172.16.x.x */ \ || ((addr) & 0xffff0000) == 0xc0a80000) /* 192.168.x.x */ #define process_exists(n) (kill((n), 0) == 0 || errno != ESRCH) void mp_check_options() { lcp_options *wo = &lcp_wantoptions[0]; lcp_options *ao = &lcp_allowoptions[0]; doing_multilink = 0; if (!multilink) return; /* if we're doing multilink, we have to negotiate MRRU */ if (!wo->neg_mrru) { /* mrru not specified, default to mru */ wo->mrru = wo->mru; wo->neg_mrru = 1; } ao->mrru = ao->mru; ao->neg_mrru = 1; if (!wo->neg_endpoint && !noendpoint) { /* get a default endpoint value */ wo->neg_endpoint = get_default_epdisc(&wo->endpoint); } } /* * Make a new bundle or join us to an existing bundle * if we are doing multilink. */ int mp_join_bundle() { lcp_options *go = &lcp_gotoptions[0]; lcp_options *ho = &lcp_hisoptions[0]; lcp_options *ao = &lcp_allowoptions[0]; int unit, pppd_pid; int l, mtu; char *p; TDB_DATA key, pid, rec; if (doing_multilink) { /* have previously joined a bundle */ if (!go->neg_mrru || !ho->neg_mrru) { notice("oops, didn't get multilink on renegotiation"); lcp_close(pcb, "multilink required"); return 0; } /* XXX should check the peer_authname and ho->endpoint are the same as previously */ return 0; } if (!go->neg_mrru || !ho->neg_mrru) { /* not doing multilink */ if (go->neg_mrru) notice("oops, multilink negotiated only for receive"); mtu = ho->neg_mru? ho->mru: PPP_MRU; if (mtu > ao->mru) mtu = ao->mru; if (demand) { /* already have a bundle */ cfg_bundle(0, 0, 0, 0); netif_set_mtu(pcb, mtu); return 0; } make_new_bundle(0, 0, 0, 0); set_ifunit(1); netif_set_mtu(pcb, mtu); return 0; } doing_multilink = 1; /* * Find the appropriate bundle or join a new one. * First we make up a name for the bundle. * The length estimate is worst-case assuming every * character has to be quoted. */ l = 4 * strlen(peer_authname) + 10; if (ho->neg_endpoint) l += 3 * ho->endpoint.length + 8; if (bundle_name) l += 3 * strlen(bundle_name) + 2; bundle_id = malloc(l); if (bundle_id == 0) novm("bundle identifier"); p = bundle_id; p += slprintf(p, l-1, "BUNDLE=\"%q\"", peer_authname); if (ho->neg_endpoint || bundle_name) *p++ = '/'; if (ho->neg_endpoint) p += slprintf(p, bundle_id+l-p, "%s", epdisc_to_str(&ho->endpoint)); if (bundle_name) p += slprintf(p, bundle_id+l-p, "/%v", bundle_name); /* Make the key for the list of links belonging to the bundle */ l = p - bundle_id; blinks_id = malloc(l + 7); if (blinks_id == NULL) novm("bundle links key"); slprintf(blinks_id, l + 7, "BUNDLE_LINKS=%s", bundle_id + 7); /* * For demand mode, we only need to configure the bundle * and attach the link. */ mtu = LWIP_MIN(ho->mrru, ao->mru); if (demand) { cfg_bundle(go->mrru, ho->mrru, go->neg_ssnhf, ho->neg_ssnhf); netif_set_mtu(pcb, mtu); script_setenv("BUNDLE", bundle_id + 7, 1); return 0; } /* * Check if the bundle ID is already in the database. */ unit = -1; lock_db(); key.dptr = bundle_id; key.dsize = p - bundle_id; pid = tdb_fetch(pppdb, key); if (pid.dptr != NULL) { /* bundle ID exists, see if the pppd record exists */ rec = tdb_fetch(pppdb, pid); if (rec.dptr != NULL && rec.dsize > 0) { /* make sure the string is null-terminated */ rec.dptr[rec.dsize-1] = 0; /* parse the interface number */ parse_num(rec.dptr, "IFNAME=ppp", &unit); /* check the pid value */ if (!parse_num(rec.dptr, "PPPD_PID=", &pppd_pid) || !process_exists(pppd_pid) || !owns_unit(pid, unit)) unit = -1; free(rec.dptr); } free(pid.dptr); } if (unit >= 0) { /* attach to existing unit */ if (bundle_attach(unit)) { set_ifunit(0); script_setenv("BUNDLE", bundle_id + 7, 0); make_bundle_links(1); unlock_db(); info("Link attached to %s", ifname); return 1; } /* attach failed because bundle doesn't exist */ } /* we have to make a new bundle */ make_new_bundle(go->mrru, ho->mrru, go->neg_ssnhf, ho->neg_ssnhf); set_ifunit(1); netif_set_mtu(pcb, mtu); script_setenv("BUNDLE", bundle_id + 7, 1); make_bundle_links(pcb); unlock_db(); info("New bundle %s created", ifname); multilink_master = 1; return 0; } void mp_exit_bundle() { lock_db(); remove_bundle_link(); unlock_db(); } static void sendhup(char *str) { int pid; if (parse_num(str, "PPPD_PID=", &pid) && pid != getpid()) { if (debug) dbglog("sending SIGHUP to process %d", pid); kill(pid, SIGHUP); } } void mp_bundle_terminated() { TDB_DATA key; bundle_terminating = 1; upper_layers_down(pcb); notice("Connection terminated."); #if PPP_STATS_SUPPORT print_link_stats(); #endif /* PPP_STATS_SUPPORT */ if (!demand) { remove_pidfiles(); script_unsetenv("IFNAME"); } lock_db(); destroy_bundle(); iterate_bundle_links(sendhup); key.dptr = blinks_id; key.dsize = strlen(blinks_id); tdb_delete(pppdb, key); unlock_db(); new_phase(PPP_PHASE_DEAD); doing_multilink = 0; multilink_master = 0; } static void make_bundle_links(int append) { TDB_DATA key, rec; char *p; char entry[32]; int l; key.dptr = blinks_id; key.dsize = strlen(blinks_id); slprintf(entry, sizeof(entry), "%s;", db_key); p = entry; if (append) { rec = tdb_fetch(pppdb, key); if (rec.dptr != NULL && rec.dsize > 0) { rec.dptr[rec.dsize-1] = 0; if (strstr(rec.dptr, db_key) != NULL) { /* already in there? strange */ warn("link entry already exists in tdb"); return; } l = rec.dsize + strlen(entry); p = malloc(l); if (p == NULL) novm("bundle link list"); slprintf(p, l, "%s%s", rec.dptr, entry); } else { warn("bundle link list not found"); } if (rec.dptr != NULL) free(rec.dptr); } rec.dptr = p; rec.dsize = strlen(p) + 1; if (tdb_store(pppdb, key, rec, TDB_REPLACE)) error("couldn't %s bundle link list", append? "update": "create"); if (p != entry) free(p); } static void remove_bundle_link() { TDB_DATA key, rec; char entry[32]; char *p, *q; int l; key.dptr = blinks_id; key.dsize = strlen(blinks_id); slprintf(entry, sizeof(entry), "%s;", db_key); rec = tdb_fetch(pppdb, key); if (rec.dptr == NULL || rec.dsize <= 0) { if (rec.dptr != NULL) free(rec.dptr); return; } rec.dptr[rec.dsize-1] = 0; p = strstr(rec.dptr, entry); if (p != NULL) { q = p + strlen(entry); l = strlen(q) + 1; memmove(p, q, l); rec.dsize = p - rec.dptr + l; if (tdb_store(pppdb, key, rec, TDB_REPLACE)) error("couldn't update bundle link list (removal)"); } free(rec.dptr); } static void iterate_bundle_links(void (*func)(char *)) { TDB_DATA key, rec, pp; char *p, *q; key.dptr = blinks_id; key.dsize = strlen(blinks_id); rec = tdb_fetch(pppdb, key); if (rec.dptr == NULL || rec.dsize <= 0) { error("bundle link list not found (iterating list)"); if (rec.dptr != NULL) free(rec.dptr); return; } p = rec.dptr; p[rec.dsize-1] = 0; while ((q = strchr(p, ';')) != NULL) { *q = 0; key.dptr = p; key.dsize = q - p; pp = tdb_fetch(pppdb, key); if (pp.dptr != NULL && pp.dsize > 0) { pp.dptr[pp.dsize-1] = 0; func(pp.dptr); } if (pp.dptr != NULL) free(pp.dptr); p = q + 1; } free(rec.dptr); } static int parse_num(str, key, valp) char *str; const char *key; int *valp; { char *p, *endp; int i; p = strstr(str, key); if (p != 0) { p += strlen(key); i = strtol(p, &endp, 10); if (endp != p && (*endp == 0 || *endp == ';')) { *valp = i; return 1; } } return 0; } /* * Check whether the pppd identified by `key' still owns ppp unit `unit'. */ static int owns_unit(key, unit) TDB_DATA key; int unit; { char ifkey[32]; TDB_DATA kd, vd; int ret = 0; slprintf(ifkey, sizeof(ifkey), "IFNAME=ppp%d", unit); kd.dptr = ifkey; kd.dsize = strlen(ifkey); vd = tdb_fetch(pppdb, kd); if (vd.dptr != NULL) { ret = vd.dsize == key.dsize && memcmp(vd.dptr, key.dptr, vd.dsize) == 0; free(vd.dptr); } return ret; } static int get_default_epdisc(ep) struct epdisc *ep; { char *p; struct hostent *hp; u32_t addr; /* First try for an ethernet MAC address */ p = get_first_ethernet(); if (p != 0 && get_if_hwaddr(ep->value, p) >= 0) { ep->class = EPD_MAC; ep->length = 6; return 1; } /* see if our hostname corresponds to a reasonable IP address */ hp = gethostbyname(hostname); if (hp != NULL) { addr = *(u32_t *)hp->h_addr; if (!bad_ip_adrs(addr)) { addr = ntohl(addr); if (!LOCAL_IP_ADDR(addr)) { ep->class = EPD_IP; set_ip_epdisc(ep, addr); return 1; } } } return 0; } /* * epdisc_to_str - make a printable string from an endpoint discriminator. */ static char *endp_class_names[] = { "null", "local", "IP", "MAC", "magic", "phone" }; char * epdisc_to_str(ep) struct epdisc *ep; { static char str[MAX_ENDP_LEN*3+8]; u_char *p = ep->value; int i, mask = 0; char *q, c, c2; if (ep->class == EPD_NULL && ep->length == 0) return "null"; if (ep->class == EPD_IP && ep->length == 4) { u32_t addr; GETLONG(addr, p); slprintf(str, sizeof(str), "IP:%I", htonl(addr)); return str; } c = ':'; c2 = '.'; if (ep->class == EPD_MAC && ep->length == 6) c2 = ':'; else if (ep->class == EPD_MAGIC && (ep->length % 4) == 0) mask = 3; q = str; if (ep->class <= EPD_PHONENUM) q += slprintf(q, sizeof(str)-1, "%s", endp_class_names[ep->class]); else q += slprintf(q, sizeof(str)-1, "%d", ep->class); c = ':'; for (i = 0; i < ep->length && i < MAX_ENDP_LEN; ++i) { if ((i & mask) == 0) { *q++ = c; c = c2; } q += slprintf(q, str + sizeof(str) - q, "%.2x", ep->value[i]); } return str; } static int hexc_val(int c) { if (c >= 'a') return c - 'a' + 10; if (c >= 'A') return c - 'A' + 10; return c - '0'; } int str_to_epdisc(ep, str) struct epdisc *ep; char *str; { int i, l; char *p, *endp; for (i = EPD_NULL; i <= EPD_PHONENUM; ++i) { int sl = strlen(endp_class_names[i]); if (strncasecmp(str, endp_class_names[i], sl) == 0) { str += sl; break; } } if (i > EPD_PHONENUM) { /* not a class name, try a decimal class number */ i = strtol(str, &endp, 10); if (endp == str) return 0; /* can't parse class number */ str = endp; } ep->class = i; if (*str == 0) { ep->length = 0; return 1; } if (*str != ':' && *str != '.') return 0; ++str; if (i == EPD_IP) { u32_t addr; i = parse_dotted_ip(str, &addr); if (i == 0 || str[i] != 0) return 0; set_ip_epdisc(ep, addr); return 1; } if (i == EPD_MAC && get_if_hwaddr(ep->value, str) >= 0) { ep->length = 6; return 1; } p = str; for (l = 0; l < MAX_ENDP_LEN; ++l) { if (*str == 0) break; if (p <= str) for (p = str; isxdigit(*p); ++p) ; i = p - str; if (i == 0) return 0; ep->value[l] = hexc_val(*str++); if ((i & 1) == 0) ep->value[l] = (ep->value[l] << 4) + hexc_val(*str++); if (*str == ':' || *str == '.') ++str; } if (*str != 0 || (ep->class == EPD_MAC && l != 6)) return 0; ep->length = l; return 1; } #endif /* PPP_SUPPORT && HAVE_MULTILINK */ ocproxy-1.60/lwip/src/netif/ppp/polarssl/000077500000000000000000000000001303453231400204465ustar00rootroot00000000000000ocproxy-1.60/lwip/src/netif/ppp/polarssl/README000066400000000000000000000022451303453231400213310ustar00rootroot00000000000000About PolarSSL files into lwIP PPP support ------------------------------------------ This folder contains some files fetched from the latest BSD release of the PolarSSL project for ciphers and encryption methods we need for lwIP PPP support. The PolarSSL files were cleaned to contain only the necessary struct fields and functions needed for lwIP. The PolarSSL API was not changed at all, so if you are already using PolarSSL you can choose to skip the compilation of the included PolarSSL library into lwIP: The following defines are available for flexibility: LWIP_INCLUDED_POLARSSL_MD4 ; Use lwIP internal PolarSSL for MD4 LWIP_INCLUDED_POLARSSL_MD5 ; Use lwIP internal PolarSSL for MD5 LWIP_INCLUDED_POLARSSL_SHA1 ; Use lwIP internal PolarSSL for SHA1 LWIP_INCLUDED_POLARSSL_DES ; Use lwIP internal PolarSSL for DES If set (=1), the default if required by another enabled PPP feature unless explicitly set to 0, using included lwIP PolarSSL. If clear (=0), using external PolarSSL. Undefined if not needed. Beware of the stack requirements which can be a lot larger if you are not using our cleaned PolarSSL library. PolarSSL project website: http://polarssl.org/ ocproxy-1.60/lwip/src/netif/ppp/polarssl/des.c000066400000000000000000000400031303453231400213620ustar00rootroot00000000000000/* * FIPS-46-3 compliant Triple-DES implementation * * Based on XySSL: Copyright (C) 2006-2008 Christophe Devine * * Copyright (C) 2009 Paul Bakker * * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the names of PolarSSL or XySSL nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * DES, on which TDES is based, was originally designed by Horst Feistel * at IBM in 1974, and was adopted as a standard by NIST (formerly NBS). * * http://csrc.nist.gov/publications/fips/fips46-3/fips46-3.pdf */ #include "lwip/opt.h" #if LWIP_INCLUDED_POLARSSL_DES #include "netif/ppp/polarssl/des.h" /* * 32-bit integer manipulation macros (big endian) */ #ifndef GET_ULONG_BE #define GET_ULONG_BE(n,b,i) \ { \ (n) = ( (unsigned long) (b)[(i) ] << 24 ) \ | ( (unsigned long) (b)[(i) + 1] << 16 ) \ | ( (unsigned long) (b)[(i) + 2] << 8 ) \ | ( (unsigned long) (b)[(i) + 3] ); \ } #endif #ifndef PUT_ULONG_BE #define PUT_ULONG_BE(n,b,i) \ { \ (b)[(i) ] = (unsigned char) ( (n) >> 24 ); \ (b)[(i) + 1] = (unsigned char) ( (n) >> 16 ); \ (b)[(i) + 2] = (unsigned char) ( (n) >> 8 ); \ (b)[(i) + 3] = (unsigned char) ( (n) ); \ } #endif /* * Expanded DES S-boxes */ static const unsigned long SB1[64] = { 0x01010400, 0x00000000, 0x00010000, 0x01010404, 0x01010004, 0x00010404, 0x00000004, 0x00010000, 0x00000400, 0x01010400, 0x01010404, 0x00000400, 0x01000404, 0x01010004, 0x01000000, 0x00000004, 0x00000404, 0x01000400, 0x01000400, 0x00010400, 0x00010400, 0x01010000, 0x01010000, 0x01000404, 0x00010004, 0x01000004, 0x01000004, 0x00010004, 0x00000000, 0x00000404, 0x00010404, 0x01000000, 0x00010000, 0x01010404, 0x00000004, 0x01010000, 0x01010400, 0x01000000, 0x01000000, 0x00000400, 0x01010004, 0x00010000, 0x00010400, 0x01000004, 0x00000400, 0x00000004, 0x01000404, 0x00010404, 0x01010404, 0x00010004, 0x01010000, 0x01000404, 0x01000004, 0x00000404, 0x00010404, 0x01010400, 0x00000404, 0x01000400, 0x01000400, 0x00000000, 0x00010004, 0x00010400, 0x00000000, 0x01010004 }; static const unsigned long SB2[64] = { 0x80108020, 0x80008000, 0x00008000, 0x00108020, 0x00100000, 0x00000020, 0x80100020, 0x80008020, 0x80000020, 0x80108020, 0x80108000, 0x80000000, 0x80008000, 0x00100000, 0x00000020, 0x80100020, 0x00108000, 0x00100020, 0x80008020, 0x00000000, 0x80000000, 0x00008000, 0x00108020, 0x80100000, 0x00100020, 0x80000020, 0x00000000, 0x00108000, 0x00008020, 0x80108000, 0x80100000, 0x00008020, 0x00000000, 0x00108020, 0x80100020, 0x00100000, 0x80008020, 0x80100000, 0x80108000, 0x00008000, 0x80100000, 0x80008000, 0x00000020, 0x80108020, 0x00108020, 0x00000020, 0x00008000, 0x80000000, 0x00008020, 0x80108000, 0x00100000, 0x80000020, 0x00100020, 0x80008020, 0x80000020, 0x00100020, 0x00108000, 0x00000000, 0x80008000, 0x00008020, 0x80000000, 0x80100020, 0x80108020, 0x00108000 }; static const unsigned long SB3[64] = { 0x00000208, 0x08020200, 0x00000000, 0x08020008, 0x08000200, 0x00000000, 0x00020208, 0x08000200, 0x00020008, 0x08000008, 0x08000008, 0x00020000, 0x08020208, 0x00020008, 0x08020000, 0x00000208, 0x08000000, 0x00000008, 0x08020200, 0x00000200, 0x00020200, 0x08020000, 0x08020008, 0x00020208, 0x08000208, 0x00020200, 0x00020000, 0x08000208, 0x00000008, 0x08020208, 0x00000200, 0x08000000, 0x08020200, 0x08000000, 0x00020008, 0x00000208, 0x00020000, 0x08020200, 0x08000200, 0x00000000, 0x00000200, 0x00020008, 0x08020208, 0x08000200, 0x08000008, 0x00000200, 0x00000000, 0x08020008, 0x08000208, 0x00020000, 0x08000000, 0x08020208, 0x00000008, 0x00020208, 0x00020200, 0x08000008, 0x08020000, 0x08000208, 0x00000208, 0x08020000, 0x00020208, 0x00000008, 0x08020008, 0x00020200 }; static const unsigned long SB4[64] = { 0x00802001, 0x00002081, 0x00002081, 0x00000080, 0x00802080, 0x00800081, 0x00800001, 0x00002001, 0x00000000, 0x00802000, 0x00802000, 0x00802081, 0x00000081, 0x00000000, 0x00800080, 0x00800001, 0x00000001, 0x00002000, 0x00800000, 0x00802001, 0x00000080, 0x00800000, 0x00002001, 0x00002080, 0x00800081, 0x00000001, 0x00002080, 0x00800080, 0x00002000, 0x00802080, 0x00802081, 0x00000081, 0x00800080, 0x00800001, 0x00802000, 0x00802081, 0x00000081, 0x00000000, 0x00000000, 0x00802000, 0x00002080, 0x00800080, 0x00800081, 0x00000001, 0x00802001, 0x00002081, 0x00002081, 0x00000080, 0x00802081, 0x00000081, 0x00000001, 0x00002000, 0x00800001, 0x00002001, 0x00802080, 0x00800081, 0x00002001, 0x00002080, 0x00800000, 0x00802001, 0x00000080, 0x00800000, 0x00002000, 0x00802080 }; static const unsigned long SB5[64] = { 0x00000100, 0x02080100, 0x02080000, 0x42000100, 0x00080000, 0x00000100, 0x40000000, 0x02080000, 0x40080100, 0x00080000, 0x02000100, 0x40080100, 0x42000100, 0x42080000, 0x00080100, 0x40000000, 0x02000000, 0x40080000, 0x40080000, 0x00000000, 0x40000100, 0x42080100, 0x42080100, 0x02000100, 0x42080000, 0x40000100, 0x00000000, 0x42000000, 0x02080100, 0x02000000, 0x42000000, 0x00080100, 0x00080000, 0x42000100, 0x00000100, 0x02000000, 0x40000000, 0x02080000, 0x42000100, 0x40080100, 0x02000100, 0x40000000, 0x42080000, 0x02080100, 0x40080100, 0x00000100, 0x02000000, 0x42080000, 0x42080100, 0x00080100, 0x42000000, 0x42080100, 0x02080000, 0x00000000, 0x40080000, 0x42000000, 0x00080100, 0x02000100, 0x40000100, 0x00080000, 0x00000000, 0x40080000, 0x02080100, 0x40000100 }; static const unsigned long SB6[64] = { 0x20000010, 0x20400000, 0x00004000, 0x20404010, 0x20400000, 0x00000010, 0x20404010, 0x00400000, 0x20004000, 0x00404010, 0x00400000, 0x20000010, 0x00400010, 0x20004000, 0x20000000, 0x00004010, 0x00000000, 0x00400010, 0x20004010, 0x00004000, 0x00404000, 0x20004010, 0x00000010, 0x20400010, 0x20400010, 0x00000000, 0x00404010, 0x20404000, 0x00004010, 0x00404000, 0x20404000, 0x20000000, 0x20004000, 0x00000010, 0x20400010, 0x00404000, 0x20404010, 0x00400000, 0x00004010, 0x20000010, 0x00400000, 0x20004000, 0x20000000, 0x00004010, 0x20000010, 0x20404010, 0x00404000, 0x20400000, 0x00404010, 0x20404000, 0x00000000, 0x20400010, 0x00000010, 0x00004000, 0x20400000, 0x00404010, 0x00004000, 0x00400010, 0x20004010, 0x00000000, 0x20404000, 0x20000000, 0x00400010, 0x20004010 }; static const unsigned long SB7[64] = { 0x00200000, 0x04200002, 0x04000802, 0x00000000, 0x00000800, 0x04000802, 0x00200802, 0x04200800, 0x04200802, 0x00200000, 0x00000000, 0x04000002, 0x00000002, 0x04000000, 0x04200002, 0x00000802, 0x04000800, 0x00200802, 0x00200002, 0x04000800, 0x04000002, 0x04200000, 0x04200800, 0x00200002, 0x04200000, 0x00000800, 0x00000802, 0x04200802, 0x00200800, 0x00000002, 0x04000000, 0x00200800, 0x04000000, 0x00200800, 0x00200000, 0x04000802, 0x04000802, 0x04200002, 0x04200002, 0x00000002, 0x00200002, 0x04000000, 0x04000800, 0x00200000, 0x04200800, 0x00000802, 0x00200802, 0x04200800, 0x00000802, 0x04000002, 0x04200802, 0x04200000, 0x00200800, 0x00000000, 0x00000002, 0x04200802, 0x00000000, 0x00200802, 0x04200000, 0x00000800, 0x04000002, 0x04000800, 0x00000800, 0x00200002 }; static const unsigned long SB8[64] = { 0x10001040, 0x00001000, 0x00040000, 0x10041040, 0x10000000, 0x10001040, 0x00000040, 0x10000000, 0x00040040, 0x10040000, 0x10041040, 0x00041000, 0x10041000, 0x00041040, 0x00001000, 0x00000040, 0x10040000, 0x10000040, 0x10001000, 0x00001040, 0x00041000, 0x00040040, 0x10040040, 0x10041000, 0x00001040, 0x00000000, 0x00000000, 0x10040040, 0x10000040, 0x10001000, 0x00041040, 0x00040000, 0x00041040, 0x00040000, 0x10041000, 0x00001000, 0x00000040, 0x10040040, 0x00001000, 0x00041040, 0x10001000, 0x00000040, 0x10000040, 0x10040000, 0x10040040, 0x10000000, 0x00040000, 0x10001040, 0x00000000, 0x10041040, 0x00040040, 0x10000040, 0x10040000, 0x10001000, 0x10001040, 0x00000000, 0x10041040, 0x00041000, 0x00041000, 0x00001040, 0x00001040, 0x00040040, 0x10000000, 0x10041000 }; /* * PC1: left and right halves bit-swap */ static const unsigned long LHs[16] = { 0x00000000, 0x00000001, 0x00000100, 0x00000101, 0x00010000, 0x00010001, 0x00010100, 0x00010101, 0x01000000, 0x01000001, 0x01000100, 0x01000101, 0x01010000, 0x01010001, 0x01010100, 0x01010101 }; static const unsigned long RHs[16] = { 0x00000000, 0x01000000, 0x00010000, 0x01010000, 0x00000100, 0x01000100, 0x00010100, 0x01010100, 0x00000001, 0x01000001, 0x00010001, 0x01010001, 0x00000101, 0x01000101, 0x00010101, 0x01010101, }; /* * Initial Permutation macro */ #define DES_IP(X,Y) \ { \ T = ((X >> 4) ^ Y) & 0x0F0F0F0F; Y ^= T; X ^= (T << 4); \ T = ((X >> 16) ^ Y) & 0x0000FFFF; Y ^= T; X ^= (T << 16); \ T = ((Y >> 2) ^ X) & 0x33333333; X ^= T; Y ^= (T << 2); \ T = ((Y >> 8) ^ X) & 0x00FF00FF; X ^= T; Y ^= (T << 8); \ Y = ((Y << 1) | (Y >> 31)) & 0xFFFFFFFF; \ T = (X ^ Y) & 0xAAAAAAAA; Y ^= T; X ^= T; \ X = ((X << 1) | (X >> 31)) & 0xFFFFFFFF; \ } /* * Final Permutation macro */ #define DES_FP(X,Y) \ { \ X = ((X << 31) | (X >> 1)) & 0xFFFFFFFF; \ T = (X ^ Y) & 0xAAAAAAAA; X ^= T; Y ^= T; \ Y = ((Y << 31) | (Y >> 1)) & 0xFFFFFFFF; \ T = ((Y >> 8) ^ X) & 0x00FF00FF; X ^= T; Y ^= (T << 8); \ T = ((Y >> 2) ^ X) & 0x33333333; X ^= T; Y ^= (T << 2); \ T = ((X >> 16) ^ Y) & 0x0000FFFF; Y ^= T; X ^= (T << 16); \ T = ((X >> 4) ^ Y) & 0x0F0F0F0F; Y ^= T; X ^= (T << 4); \ } /* * DES round macro */ #define DES_ROUND(X,Y) \ { \ T = *SK++ ^ X; \ Y ^= SB8[ (T ) & 0x3F ] ^ \ SB6[ (T >> 8) & 0x3F ] ^ \ SB4[ (T >> 16) & 0x3F ] ^ \ SB2[ (T >> 24) & 0x3F ]; \ \ T = *SK++ ^ ((X << 28) | (X >> 4)); \ Y ^= SB7[ (T ) & 0x3F ] ^ \ SB5[ (T >> 8) & 0x3F ] ^ \ SB3[ (T >> 16) & 0x3F ] ^ \ SB1[ (T >> 24) & 0x3F ]; \ } #define SWAP(a,b) { unsigned long t = a; a = b; b = t; t = 0; } static void des_setkey( unsigned long SK[32], unsigned char key[8] ) { int i; unsigned long X, Y, T; GET_ULONG_BE( X, key, 0 ); GET_ULONG_BE( Y, key, 4 ); /* * Permuted Choice 1 */ T = ((Y >> 4) ^ X) & 0x0F0F0F0F; X ^= T; Y ^= (T << 4); T = ((Y ) ^ X) & 0x10101010; X ^= T; Y ^= (T ); X = (LHs[ (X ) & 0xF] << 3) | (LHs[ (X >> 8) & 0xF ] << 2) | (LHs[ (X >> 16) & 0xF] << 1) | (LHs[ (X >> 24) & 0xF ] ) | (LHs[ (X >> 5) & 0xF] << 7) | (LHs[ (X >> 13) & 0xF ] << 6) | (LHs[ (X >> 21) & 0xF] << 5) | (LHs[ (X >> 29) & 0xF ] << 4); Y = (RHs[ (Y >> 1) & 0xF] << 3) | (RHs[ (Y >> 9) & 0xF ] << 2) | (RHs[ (Y >> 17) & 0xF] << 1) | (RHs[ (Y >> 25) & 0xF ] ) | (RHs[ (Y >> 4) & 0xF] << 7) | (RHs[ (Y >> 12) & 0xF ] << 6) | (RHs[ (Y >> 20) & 0xF] << 5) | (RHs[ (Y >> 28) & 0xF ] << 4); X &= 0x0FFFFFFF; Y &= 0x0FFFFFFF; /* * calculate subkeys */ for( i = 0; i < 16; i++ ) { if( i < 2 || i == 8 || i == 15 ) { X = ((X << 1) | (X >> 27)) & 0x0FFFFFFF; Y = ((Y << 1) | (Y >> 27)) & 0x0FFFFFFF; } else { X = ((X << 2) | (X >> 26)) & 0x0FFFFFFF; Y = ((Y << 2) | (Y >> 26)) & 0x0FFFFFFF; } *SK++ = ((X << 4) & 0x24000000) | ((X << 28) & 0x10000000) | ((X << 14) & 0x08000000) | ((X << 18) & 0x02080000) | ((X << 6) & 0x01000000) | ((X << 9) & 0x00200000) | ((X >> 1) & 0x00100000) | ((X << 10) & 0x00040000) | ((X << 2) & 0x00020000) | ((X >> 10) & 0x00010000) | ((Y >> 13) & 0x00002000) | ((Y >> 4) & 0x00001000) | ((Y << 6) & 0x00000800) | ((Y >> 1) & 0x00000400) | ((Y >> 14) & 0x00000200) | ((Y ) & 0x00000100) | ((Y >> 5) & 0x00000020) | ((Y >> 10) & 0x00000010) | ((Y >> 3) & 0x00000008) | ((Y >> 18) & 0x00000004) | ((Y >> 26) & 0x00000002) | ((Y >> 24) & 0x00000001); *SK++ = ((X << 15) & 0x20000000) | ((X << 17) & 0x10000000) | ((X << 10) & 0x08000000) | ((X << 22) & 0x04000000) | ((X >> 2) & 0x02000000) | ((X << 1) & 0x01000000) | ((X << 16) & 0x00200000) | ((X << 11) & 0x00100000) | ((X << 3) & 0x00080000) | ((X >> 6) & 0x00040000) | ((X << 15) & 0x00020000) | ((X >> 4) & 0x00010000) | ((Y >> 2) & 0x00002000) | ((Y << 8) & 0x00001000) | ((Y >> 14) & 0x00000808) | ((Y >> 9) & 0x00000400) | ((Y ) & 0x00000200) | ((Y << 7) & 0x00000100) | ((Y >> 7) & 0x00000020) | ((Y >> 3) & 0x00000011) | ((Y << 2) & 0x00000004) | ((Y >> 21) & 0x00000002); } } /* * DES key schedule (56-bit, encryption) */ void des_setkey_enc( des_context *ctx, unsigned char key[8] ) { des_setkey( ctx->sk, key ); } /* * DES key schedule (56-bit, decryption) */ void des_setkey_dec( des_context *ctx, unsigned char key[8] ) { int i; des_setkey( ctx->sk, key ); for( i = 0; i < 16; i += 2 ) { SWAP( ctx->sk[i ], ctx->sk[30 - i] ); SWAP( ctx->sk[i + 1], ctx->sk[31 - i] ); } } /* * DES-ECB block encryption/decryption */ void des_crypt_ecb( des_context *ctx, unsigned char input[8], unsigned char output[8] ) { int i; unsigned long X, Y, T, *SK; SK = ctx->sk; GET_ULONG_BE( X, input, 0 ); GET_ULONG_BE( Y, input, 4 ); DES_IP( X, Y ); for( i = 0; i < 8; i++ ) { DES_ROUND( Y, X ); DES_ROUND( X, Y ); } DES_FP( Y, X ); PUT_ULONG_BE( Y, output, 0 ); PUT_ULONG_BE( X, output, 4 ); } #endif /* LWIP_INCLUDED_POLARSSL_DES */ ocproxy-1.60/lwip/src/netif/ppp/polarssl/md4.c000066400000000000000000000175631303453231400213120ustar00rootroot00000000000000/* * RFC 1186/1320 compliant MD4 implementation * * Based on XySSL: Copyright (C) 2006-2008 Christophe Devine * * Copyright (C) 2009 Paul Bakker * * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the names of PolarSSL or XySSL nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * The MD4 algorithm was designed by Ron Rivest in 1990. * * http://www.ietf.org/rfc/rfc1186.txt * http://www.ietf.org/rfc/rfc1320.txt */ #include "lwip/opt.h" #if LWIP_INCLUDED_POLARSSL_MD4 #include "netif/ppp/polarssl/md4.h" /* * 32-bit integer manipulation macros (little endian) */ #ifndef GET_ULONG_LE #define GET_ULONG_LE(n,b,i) \ { \ (n) = ( (unsigned long) (b)[(i) ] ) \ | ( (unsigned long) (b)[(i) + 1] << 8 ) \ | ( (unsigned long) (b)[(i) + 2] << 16 ) \ | ( (unsigned long) (b)[(i) + 3] << 24 ); \ } #endif #ifndef PUT_ULONG_LE #define PUT_ULONG_LE(n,b,i) \ { \ (b)[(i) ] = (unsigned char) ( (n) ); \ (b)[(i) + 1] = (unsigned char) ( (n) >> 8 ); \ (b)[(i) + 2] = (unsigned char) ( (n) >> 16 ); \ (b)[(i) + 3] = (unsigned char) ( (n) >> 24 ); \ } #endif /* * MD4 context setup */ void md4_starts( md4_context *ctx ) { ctx->total[0] = 0; ctx->total[1] = 0; ctx->state[0] = 0x67452301; ctx->state[1] = 0xEFCDAB89; ctx->state[2] = 0x98BADCFE; ctx->state[3] = 0x10325476; } static void md4_process( md4_context *ctx, unsigned char data[64] ) { unsigned long X[16], A, B, C, D; GET_ULONG_LE( X[ 0], data, 0 ); GET_ULONG_LE( X[ 1], data, 4 ); GET_ULONG_LE( X[ 2], data, 8 ); GET_ULONG_LE( X[ 3], data, 12 ); GET_ULONG_LE( X[ 4], data, 16 ); GET_ULONG_LE( X[ 5], data, 20 ); GET_ULONG_LE( X[ 6], data, 24 ); GET_ULONG_LE( X[ 7], data, 28 ); GET_ULONG_LE( X[ 8], data, 32 ); GET_ULONG_LE( X[ 9], data, 36 ); GET_ULONG_LE( X[10], data, 40 ); GET_ULONG_LE( X[11], data, 44 ); GET_ULONG_LE( X[12], data, 48 ); GET_ULONG_LE( X[13], data, 52 ); GET_ULONG_LE( X[14], data, 56 ); GET_ULONG_LE( X[15], data, 60 ); #define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n))) A = ctx->state[0]; B = ctx->state[1]; C = ctx->state[2]; D = ctx->state[3]; #define F(x, y, z) ((x & y) | ((~x) & z)) #define P(a,b,c,d,x,s) { a += F(b,c,d) + x; a = S(a,s); } P( A, B, C, D, X[ 0], 3 ); P( D, A, B, C, X[ 1], 7 ); P( C, D, A, B, X[ 2], 11 ); P( B, C, D, A, X[ 3], 19 ); P( A, B, C, D, X[ 4], 3 ); P( D, A, B, C, X[ 5], 7 ); P( C, D, A, B, X[ 6], 11 ); P( B, C, D, A, X[ 7], 19 ); P( A, B, C, D, X[ 8], 3 ); P( D, A, B, C, X[ 9], 7 ); P( C, D, A, B, X[10], 11 ); P( B, C, D, A, X[11], 19 ); P( A, B, C, D, X[12], 3 ); P( D, A, B, C, X[13], 7 ); P( C, D, A, B, X[14], 11 ); P( B, C, D, A, X[15], 19 ); #undef P #undef F #define F(x,y,z) ((x & y) | (x & z) | (y & z)) #define P(a,b,c,d,x,s) { a += F(b,c,d) + x + 0x5A827999; a = S(a,s); } P( A, B, C, D, X[ 0], 3 ); P( D, A, B, C, X[ 4], 5 ); P( C, D, A, B, X[ 8], 9 ); P( B, C, D, A, X[12], 13 ); P( A, B, C, D, X[ 1], 3 ); P( D, A, B, C, X[ 5], 5 ); P( C, D, A, B, X[ 9], 9 ); P( B, C, D, A, X[13], 13 ); P( A, B, C, D, X[ 2], 3 ); P( D, A, B, C, X[ 6], 5 ); P( C, D, A, B, X[10], 9 ); P( B, C, D, A, X[14], 13 ); P( A, B, C, D, X[ 3], 3 ); P( D, A, B, C, X[ 7], 5 ); P( C, D, A, B, X[11], 9 ); P( B, C, D, A, X[15], 13 ); #undef P #undef F #define F(x,y,z) (x ^ y ^ z) #define P(a,b,c,d,x,s) { a += F(b,c,d) + x + 0x6ED9EBA1; a = S(a,s); } P( A, B, C, D, X[ 0], 3 ); P( D, A, B, C, X[ 8], 9 ); P( C, D, A, B, X[ 4], 11 ); P( B, C, D, A, X[12], 15 ); P( A, B, C, D, X[ 2], 3 ); P( D, A, B, C, X[10], 9 ); P( C, D, A, B, X[ 6], 11 ); P( B, C, D, A, X[14], 15 ); P( A, B, C, D, X[ 1], 3 ); P( D, A, B, C, X[ 9], 9 ); P( C, D, A, B, X[ 5], 11 ); P( B, C, D, A, X[13], 15 ); P( A, B, C, D, X[ 3], 3 ); P( D, A, B, C, X[11], 9 ); P( C, D, A, B, X[ 7], 11 ); P( B, C, D, A, X[15], 15 ); #undef F #undef P ctx->state[0] += A; ctx->state[1] += B; ctx->state[2] += C; ctx->state[3] += D; } /* * MD4 process buffer */ void md4_update( md4_context *ctx, unsigned char *input, int ilen ) { int fill; unsigned long left; if( ilen <= 0 ) return; left = ctx->total[0] & 0x3F; fill = 64 - left; ctx->total[0] += ilen; ctx->total[0] &= 0xFFFFFFFF; if( ctx->total[0] < (unsigned long) ilen ) ctx->total[1]++; if( left && ilen >= fill ) { MEMCPY( (void *) (ctx->buffer + left), (void *) input, fill ); md4_process( ctx, ctx->buffer ); input += fill; ilen -= fill; left = 0; } while( ilen >= 64 ) { md4_process( ctx, input ); input += 64; ilen -= 64; } if( ilen > 0 ) { MEMCPY( (void *) (ctx->buffer + left), (void *) input, ilen ); } } static const unsigned char md4_padding[64] = { 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; /* * MD4 final digest */ void md4_finish( md4_context *ctx, unsigned char output[16] ) { unsigned long last, padn; unsigned long high, low; unsigned char msglen[8]; high = ( ctx->total[0] >> 29 ) | ( ctx->total[1] << 3 ); low = ( ctx->total[0] << 3 ); PUT_ULONG_LE( low, msglen, 0 ); PUT_ULONG_LE( high, msglen, 4 ); last = ctx->total[0] & 0x3F; padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last ); md4_update( ctx, (unsigned char *) md4_padding, padn ); md4_update( ctx, msglen, 8 ); PUT_ULONG_LE( ctx->state[0], output, 0 ); PUT_ULONG_LE( ctx->state[1], output, 4 ); PUT_ULONG_LE( ctx->state[2], output, 8 ); PUT_ULONG_LE( ctx->state[3], output, 12 ); } /* * output = MD4( input buffer ) */ void md4( unsigned char *input, int ilen, unsigned char output[16] ) { md4_context ctx; md4_starts( &ctx ); md4_update( &ctx, input, ilen ); md4_finish( &ctx, output ); } #endif /* LWIP_INCLUDED_POLARSSL_MD4 */ ocproxy-1.60/lwip/src/netif/ppp/polarssl/md5.c000066400000000000000000000215651303453231400213100ustar00rootroot00000000000000/* * RFC 1321 compliant MD5 implementation * * Based on XySSL: Copyright (C) 2006-2008 Christophe Devine * * Copyright (C) 2009 Paul Bakker * * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the names of PolarSSL or XySSL nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * The MD5 algorithm was designed by Ron Rivest in 1991. * * http://www.ietf.org/rfc/rfc1321.txt */ #include "lwip/opt.h" #if LWIP_INCLUDED_POLARSSL_MD5 #include "netif/ppp/polarssl/md5.h" /* * 32-bit integer manipulation macros (little endian) */ #ifndef GET_ULONG_LE #define GET_ULONG_LE(n,b,i) \ { \ (n) = ( (unsigned long) (b)[(i) ] ) \ | ( (unsigned long) (b)[(i) + 1] << 8 ) \ | ( (unsigned long) (b)[(i) + 2] << 16 ) \ | ( (unsigned long) (b)[(i) + 3] << 24 ); \ } #endif #ifndef PUT_ULONG_LE #define PUT_ULONG_LE(n,b,i) \ { \ (b)[(i) ] = (unsigned char) ( (n) ); \ (b)[(i) + 1] = (unsigned char) ( (n) >> 8 ); \ (b)[(i) + 2] = (unsigned char) ( (n) >> 16 ); \ (b)[(i) + 3] = (unsigned char) ( (n) >> 24 ); \ } #endif /* * MD5 context setup */ void md5_starts( md5_context *ctx ) { ctx->total[0] = 0; ctx->total[1] = 0; ctx->state[0] = 0x67452301; ctx->state[1] = 0xEFCDAB89; ctx->state[2] = 0x98BADCFE; ctx->state[3] = 0x10325476; } static void md5_process( md5_context *ctx, unsigned char data[64] ) { unsigned long X[16], A, B, C, D; GET_ULONG_LE( X[ 0], data, 0 ); GET_ULONG_LE( X[ 1], data, 4 ); GET_ULONG_LE( X[ 2], data, 8 ); GET_ULONG_LE( X[ 3], data, 12 ); GET_ULONG_LE( X[ 4], data, 16 ); GET_ULONG_LE( X[ 5], data, 20 ); GET_ULONG_LE( X[ 6], data, 24 ); GET_ULONG_LE( X[ 7], data, 28 ); GET_ULONG_LE( X[ 8], data, 32 ); GET_ULONG_LE( X[ 9], data, 36 ); GET_ULONG_LE( X[10], data, 40 ); GET_ULONG_LE( X[11], data, 44 ); GET_ULONG_LE( X[12], data, 48 ); GET_ULONG_LE( X[13], data, 52 ); GET_ULONG_LE( X[14], data, 56 ); GET_ULONG_LE( X[15], data, 60 ); #define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n))) #define P(a,b,c,d,k,s,t) \ { \ a += F(b,c,d) + X[k] + t; a = S(a,s) + b; \ } A = ctx->state[0]; B = ctx->state[1]; C = ctx->state[2]; D = ctx->state[3]; #define F(x,y,z) (z ^ (x & (y ^ z))) P( A, B, C, D, 0, 7, 0xD76AA478 ); P( D, A, B, C, 1, 12, 0xE8C7B756 ); P( C, D, A, B, 2, 17, 0x242070DB ); P( B, C, D, A, 3, 22, 0xC1BDCEEE ); P( A, B, C, D, 4, 7, 0xF57C0FAF ); P( D, A, B, C, 5, 12, 0x4787C62A ); P( C, D, A, B, 6, 17, 0xA8304613 ); P( B, C, D, A, 7, 22, 0xFD469501 ); P( A, B, C, D, 8, 7, 0x698098D8 ); P( D, A, B, C, 9, 12, 0x8B44F7AF ); P( C, D, A, B, 10, 17, 0xFFFF5BB1 ); P( B, C, D, A, 11, 22, 0x895CD7BE ); P( A, B, C, D, 12, 7, 0x6B901122 ); P( D, A, B, C, 13, 12, 0xFD987193 ); P( C, D, A, B, 14, 17, 0xA679438E ); P( B, C, D, A, 15, 22, 0x49B40821 ); #undef F #define F(x,y,z) (y ^ (z & (x ^ y))) P( A, B, C, D, 1, 5, 0xF61E2562 ); P( D, A, B, C, 6, 9, 0xC040B340 ); P( C, D, A, B, 11, 14, 0x265E5A51 ); P( B, C, D, A, 0, 20, 0xE9B6C7AA ); P( A, B, C, D, 5, 5, 0xD62F105D ); P( D, A, B, C, 10, 9, 0x02441453 ); P( C, D, A, B, 15, 14, 0xD8A1E681 ); P( B, C, D, A, 4, 20, 0xE7D3FBC8 ); P( A, B, C, D, 9, 5, 0x21E1CDE6 ); P( D, A, B, C, 14, 9, 0xC33707D6 ); P( C, D, A, B, 3, 14, 0xF4D50D87 ); P( B, C, D, A, 8, 20, 0x455A14ED ); P( A, B, C, D, 13, 5, 0xA9E3E905 ); P( D, A, B, C, 2, 9, 0xFCEFA3F8 ); P( C, D, A, B, 7, 14, 0x676F02D9 ); P( B, C, D, A, 12, 20, 0x8D2A4C8A ); #undef F #define F(x,y,z) (x ^ y ^ z) P( A, B, C, D, 5, 4, 0xFFFA3942 ); P( D, A, B, C, 8, 11, 0x8771F681 ); P( C, D, A, B, 11, 16, 0x6D9D6122 ); P( B, C, D, A, 14, 23, 0xFDE5380C ); P( A, B, C, D, 1, 4, 0xA4BEEA44 ); P( D, A, B, C, 4, 11, 0x4BDECFA9 ); P( C, D, A, B, 7, 16, 0xF6BB4B60 ); P( B, C, D, A, 10, 23, 0xBEBFBC70 ); P( A, B, C, D, 13, 4, 0x289B7EC6 ); P( D, A, B, C, 0, 11, 0xEAA127FA ); P( C, D, A, B, 3, 16, 0xD4EF3085 ); P( B, C, D, A, 6, 23, 0x04881D05 ); P( A, B, C, D, 9, 4, 0xD9D4D039 ); P( D, A, B, C, 12, 11, 0xE6DB99E5 ); P( C, D, A, B, 15, 16, 0x1FA27CF8 ); P( B, C, D, A, 2, 23, 0xC4AC5665 ); #undef F #define F(x,y,z) (y ^ (x | ~z)) P( A, B, C, D, 0, 6, 0xF4292244 ); P( D, A, B, C, 7, 10, 0x432AFF97 ); P( C, D, A, B, 14, 15, 0xAB9423A7 ); P( B, C, D, A, 5, 21, 0xFC93A039 ); P( A, B, C, D, 12, 6, 0x655B59C3 ); P( D, A, B, C, 3, 10, 0x8F0CCC92 ); P( C, D, A, B, 10, 15, 0xFFEFF47D ); P( B, C, D, A, 1, 21, 0x85845DD1 ); P( A, B, C, D, 8, 6, 0x6FA87E4F ); P( D, A, B, C, 15, 10, 0xFE2CE6E0 ); P( C, D, A, B, 6, 15, 0xA3014314 ); P( B, C, D, A, 13, 21, 0x4E0811A1 ); P( A, B, C, D, 4, 6, 0xF7537E82 ); P( D, A, B, C, 11, 10, 0xBD3AF235 ); P( C, D, A, B, 2, 15, 0x2AD7D2BB ); P( B, C, D, A, 9, 21, 0xEB86D391 ); #undef F ctx->state[0] += A; ctx->state[1] += B; ctx->state[2] += C; ctx->state[3] += D; } /* * MD5 process buffer */ void md5_update( md5_context *ctx, unsigned char *input, int ilen ) { int fill; unsigned long left; if( ilen <= 0 ) return; left = ctx->total[0] & 0x3F; fill = 64 - left; ctx->total[0] += ilen; ctx->total[0] &= 0xFFFFFFFF; if( ctx->total[0] < (unsigned long) ilen ) ctx->total[1]++; if( left && ilen >= fill ) { MEMCPY( (void *) (ctx->buffer + left), (void *) input, fill ); md5_process( ctx, ctx->buffer ); input += fill; ilen -= fill; left = 0; } while( ilen >= 64 ) { md5_process( ctx, input ); input += 64; ilen -= 64; } if( ilen > 0 ) { MEMCPY( (void *) (ctx->buffer + left), (void *) input, ilen ); } } static const unsigned char md5_padding[64] = { 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; /* * MD5 final digest */ void md5_finish( md5_context *ctx, unsigned char output[16] ) { unsigned long last, padn; unsigned long high, low; unsigned char msglen[8]; high = ( ctx->total[0] >> 29 ) | ( ctx->total[1] << 3 ); low = ( ctx->total[0] << 3 ); PUT_ULONG_LE( low, msglen, 0 ); PUT_ULONG_LE( high, msglen, 4 ); last = ctx->total[0] & 0x3F; padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last ); md5_update( ctx, (unsigned char *) md5_padding, padn ); md5_update( ctx, msglen, 8 ); PUT_ULONG_LE( ctx->state[0], output, 0 ); PUT_ULONG_LE( ctx->state[1], output, 4 ); PUT_ULONG_LE( ctx->state[2], output, 8 ); PUT_ULONG_LE( ctx->state[3], output, 12 ); } /* * output = MD5( input buffer ) */ void md5( unsigned char *input, int ilen, unsigned char output[16] ) { md5_context ctx; md5_starts( &ctx ); md5_update( &ctx, input, ilen ); md5_finish( &ctx, output ); } #endif /* LWIP_INCLUDED_POLARSSL_MD5 */ ocproxy-1.60/lwip/src/netif/ppp/polarssl/sha1.c000066400000000000000000000224551303453231400214560ustar00rootroot00000000000000/* * FIPS-180-1 compliant SHA-1 implementation * * Based on XySSL: Copyright (C) 2006-2008 Christophe Devine * * Copyright (C) 2009 Paul Bakker * * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the names of PolarSSL or XySSL nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * The SHA-1 standard was published by NIST in 1993. * * http://www.itl.nist.gov/fipspubs/fip180-1.htm */ #include "lwip/opt.h" #if LWIP_INCLUDED_POLARSSL_SHA1 #include "netif/ppp/polarssl/sha1.h" /* * 32-bit integer manipulation macros (big endian) */ #ifndef GET_ULONG_BE #define GET_ULONG_BE(n,b,i) \ { \ (n) = ( (unsigned long) (b)[(i) ] << 24 ) \ | ( (unsigned long) (b)[(i) + 1] << 16 ) \ | ( (unsigned long) (b)[(i) + 2] << 8 ) \ | ( (unsigned long) (b)[(i) + 3] ); \ } #endif #ifndef PUT_ULONG_BE #define PUT_ULONG_BE(n,b,i) \ { \ (b)[(i) ] = (unsigned char) ( (n) >> 24 ); \ (b)[(i) + 1] = (unsigned char) ( (n) >> 16 ); \ (b)[(i) + 2] = (unsigned char) ( (n) >> 8 ); \ (b)[(i) + 3] = (unsigned char) ( (n) ); \ } #endif /* * SHA-1 context setup */ void sha1_starts( sha1_context *ctx ) { ctx->total[0] = 0; ctx->total[1] = 0; ctx->state[0] = 0x67452301; ctx->state[1] = 0xEFCDAB89; ctx->state[2] = 0x98BADCFE; ctx->state[3] = 0x10325476; ctx->state[4] = 0xC3D2E1F0; } static void sha1_process( sha1_context *ctx, unsigned char data[64] ) { unsigned long temp, W[16], A, B, C, D, E; GET_ULONG_BE( W[ 0], data, 0 ); GET_ULONG_BE( W[ 1], data, 4 ); GET_ULONG_BE( W[ 2], data, 8 ); GET_ULONG_BE( W[ 3], data, 12 ); GET_ULONG_BE( W[ 4], data, 16 ); GET_ULONG_BE( W[ 5], data, 20 ); GET_ULONG_BE( W[ 6], data, 24 ); GET_ULONG_BE( W[ 7], data, 28 ); GET_ULONG_BE( W[ 8], data, 32 ); GET_ULONG_BE( W[ 9], data, 36 ); GET_ULONG_BE( W[10], data, 40 ); GET_ULONG_BE( W[11], data, 44 ); GET_ULONG_BE( W[12], data, 48 ); GET_ULONG_BE( W[13], data, 52 ); GET_ULONG_BE( W[14], data, 56 ); GET_ULONG_BE( W[15], data, 60 ); #define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n))) #define R(t) \ ( \ temp = W[(t - 3) & 0x0F] ^ W[(t - 8) & 0x0F] ^ \ W[(t - 14) & 0x0F] ^ W[ t & 0x0F], \ ( W[t & 0x0F] = S(temp,1) ) \ ) #define P(a,b,c,d,e,x) \ { \ e += S(a,5) + F(b,c,d) + K + x; b = S(b,30); \ } A = ctx->state[0]; B = ctx->state[1]; C = ctx->state[2]; D = ctx->state[3]; E = ctx->state[4]; #define F(x,y,z) (z ^ (x & (y ^ z))) #define K 0x5A827999 P( A, B, C, D, E, W[0] ); P( E, A, B, C, D, W[1] ); P( D, E, A, B, C, W[2] ); P( C, D, E, A, B, W[3] ); P( B, C, D, E, A, W[4] ); P( A, B, C, D, E, W[5] ); P( E, A, B, C, D, W[6] ); P( D, E, A, B, C, W[7] ); P( C, D, E, A, B, W[8] ); P( B, C, D, E, A, W[9] ); P( A, B, C, D, E, W[10] ); P( E, A, B, C, D, W[11] ); P( D, E, A, B, C, W[12] ); P( C, D, E, A, B, W[13] ); P( B, C, D, E, A, W[14] ); P( A, B, C, D, E, W[15] ); P( E, A, B, C, D, R(16) ); P( D, E, A, B, C, R(17) ); P( C, D, E, A, B, R(18) ); P( B, C, D, E, A, R(19) ); #undef K #undef F #define F(x,y,z) (x ^ y ^ z) #define K 0x6ED9EBA1 P( A, B, C, D, E, R(20) ); P( E, A, B, C, D, R(21) ); P( D, E, A, B, C, R(22) ); P( C, D, E, A, B, R(23) ); P( B, C, D, E, A, R(24) ); P( A, B, C, D, E, R(25) ); P( E, A, B, C, D, R(26) ); P( D, E, A, B, C, R(27) ); P( C, D, E, A, B, R(28) ); P( B, C, D, E, A, R(29) ); P( A, B, C, D, E, R(30) ); P( E, A, B, C, D, R(31) ); P( D, E, A, B, C, R(32) ); P( C, D, E, A, B, R(33) ); P( B, C, D, E, A, R(34) ); P( A, B, C, D, E, R(35) ); P( E, A, B, C, D, R(36) ); P( D, E, A, B, C, R(37) ); P( C, D, E, A, B, R(38) ); P( B, C, D, E, A, R(39) ); #undef K #undef F #define F(x,y,z) ((x & y) | (z & (x | y))) #define K 0x8F1BBCDC P( A, B, C, D, E, R(40) ); P( E, A, B, C, D, R(41) ); P( D, E, A, B, C, R(42) ); P( C, D, E, A, B, R(43) ); P( B, C, D, E, A, R(44) ); P( A, B, C, D, E, R(45) ); P( E, A, B, C, D, R(46) ); P( D, E, A, B, C, R(47) ); P( C, D, E, A, B, R(48) ); P( B, C, D, E, A, R(49) ); P( A, B, C, D, E, R(50) ); P( E, A, B, C, D, R(51) ); P( D, E, A, B, C, R(52) ); P( C, D, E, A, B, R(53) ); P( B, C, D, E, A, R(54) ); P( A, B, C, D, E, R(55) ); P( E, A, B, C, D, R(56) ); P( D, E, A, B, C, R(57) ); P( C, D, E, A, B, R(58) ); P( B, C, D, E, A, R(59) ); #undef K #undef F #define F(x,y,z) (x ^ y ^ z) #define K 0xCA62C1D6 P( A, B, C, D, E, R(60) ); P( E, A, B, C, D, R(61) ); P( D, E, A, B, C, R(62) ); P( C, D, E, A, B, R(63) ); P( B, C, D, E, A, R(64) ); P( A, B, C, D, E, R(65) ); P( E, A, B, C, D, R(66) ); P( D, E, A, B, C, R(67) ); P( C, D, E, A, B, R(68) ); P( B, C, D, E, A, R(69) ); P( A, B, C, D, E, R(70) ); P( E, A, B, C, D, R(71) ); P( D, E, A, B, C, R(72) ); P( C, D, E, A, B, R(73) ); P( B, C, D, E, A, R(74) ); P( A, B, C, D, E, R(75) ); P( E, A, B, C, D, R(76) ); P( D, E, A, B, C, R(77) ); P( C, D, E, A, B, R(78) ); P( B, C, D, E, A, R(79) ); #undef K #undef F ctx->state[0] += A; ctx->state[1] += B; ctx->state[2] += C; ctx->state[3] += D; ctx->state[4] += E; } /* * SHA-1 process buffer */ void sha1_update( sha1_context *ctx, unsigned char *input, int ilen ) { int fill; unsigned long left; if( ilen <= 0 ) return; left = ctx->total[0] & 0x3F; fill = 64 - left; ctx->total[0] += ilen; ctx->total[0] &= 0xFFFFFFFF; if( ctx->total[0] < (unsigned long) ilen ) ctx->total[1]++; if( left && ilen >= fill ) { MEMCPY( (void *) (ctx->buffer + left), (void *) input, fill ); sha1_process( ctx, ctx->buffer ); input += fill; ilen -= fill; left = 0; } while( ilen >= 64 ) { sha1_process( ctx, input ); input += 64; ilen -= 64; } if( ilen > 0 ) { MEMCPY( (void *) (ctx->buffer + left), (void *) input, ilen ); } } static const unsigned char sha1_padding[64] = { 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; /* * SHA-1 final digest */ void sha1_finish( sha1_context *ctx, unsigned char output[20] ) { unsigned long last, padn; unsigned long high, low; unsigned char msglen[8]; high = ( ctx->total[0] >> 29 ) | ( ctx->total[1] << 3 ); low = ( ctx->total[0] << 3 ); PUT_ULONG_BE( high, msglen, 0 ); PUT_ULONG_BE( low, msglen, 4 ); last = ctx->total[0] & 0x3F; padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last ); sha1_update( ctx, (unsigned char *) sha1_padding, padn ); sha1_update( ctx, msglen, 8 ); PUT_ULONG_BE( ctx->state[0], output, 0 ); PUT_ULONG_BE( ctx->state[1], output, 4 ); PUT_ULONG_BE( ctx->state[2], output, 8 ); PUT_ULONG_BE( ctx->state[3], output, 12 ); PUT_ULONG_BE( ctx->state[4], output, 16 ); } /* * output = SHA-1( input buffer ) */ void sha1( unsigned char *input, int ilen, unsigned char output[20] ) { sha1_context ctx; sha1_starts( &ctx ); sha1_update( &ctx, input, ilen ); sha1_finish( &ctx, output ); } #endif /* LWIP_INCLUDED_POLARSSL_SHA1 */ ocproxy-1.60/lwip/src/netif/ppp/ppp.c000066400000000000000000002245171303453231400175650ustar00rootroot00000000000000/***************************************************************************** * ppp.c - Network Point to Point Protocol program file. * * Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc. * portions Copyright (c) 1997 by Global Election Systems Inc. * * The authors hereby grant permission to use, copy, modify, distribute, * and license this software and its documentation for any purpose, provided * that existing copyright notices are retained in all copies and that this * notice and the following disclaimer are included verbatim in any * distributions. No written agreement, license, or royalty fee is required * for any of the authorized uses. * * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ****************************************************************************** * REVISION HISTORY * * 03-01-01 Marc Boucher * Ported to lwIP. * 97-11-05 Guy Lancaster , Global Election Systems Inc. * Original. *****************************************************************************/ /* * ppp_defs.h - PPP definitions. * * if_pppvar.h - private structures and declarations for PPP. * * Copyright (c) 1994 The Australian National University. * All rights reserved. * * Permission to use, copy, modify, and distribute this software and its * documentation is hereby granted, provided that the above copyright * notice appears in all copies. This software is provided without any * warranty, express or implied. The Australian National University * makes no representations about the suitability of this software for * any purpose. * * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, * OR MODIFICATIONS. */ /* * if_ppp.h - Point-to-Point Protocol definitions. * * Copyright (c) 1989 Carnegie Mellon University. * All rights reserved. * * Redistribution and use in source and binary forms are permitted * provided that the above copyright notice and this paragraph are * duplicated in all such forms and that any documentation, * advertising materials, and other materials related to such * distribution and use acknowledge that the software was developed * by Carnegie Mellon University. The name of the * University may not be used to endorse or promote products derived * from this software without specific prior written permission. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ #include "lwip/opt.h" #if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */ #include "lwip/pbuf.h" #include "lwip/stats.h" #include "lwip/sys.h" #include "lwip/tcpip.h" #include "lwip/api.h" #include "lwip/snmp.h" #include "lwip/sio.h" #include "lwip/sys.h" #include "lwip/ip.h" /* for ip_input() */ #include "netif/ppp/ppp_impl.h" #include "netif/ppp/fsm.h" #include "netif/ppp/lcp.h" #include "netif/ppp/ipcp.h" #include "netif/ppp/magic.h" #if PAP_SUPPORT #include "netif/ppp/upap.h" #endif /* PAP_SUPPORT */ #if CHAP_SUPPORT #include "netif/ppp/chap-new.h" #endif /* CHAP_SUPPORT */ #if EAP_SUPPORT #include "netif/ppp/eap.h" #endif /* EAP_SUPPORT */ #if CCP_SUPPORT #include "netif/ppp/ccp.h" #endif /* EAP_SUPPORT */ #if ECP_SUPPORT #include "netif/ppp/ecp.h" #endif /* EAP_SUPPORT */ #if VJ_SUPPORT #include "netif/ppp/vj.h" #endif /* VJ_SUPPORT */ #if PPP_IPV6_SUPPORT #include "netif/ppp/ipv6cp.h" #endif /* PPP_IPV6_SUPPORT */ #if PPPOE_SUPPORT #include "netif/ppp/pppoe.h" #endif /* PPPOE_SUPPORT */ #if PPPOL2TP_SUPPORT #include "netif/ppp/pppol2tp.h" #endif /* PPPOL2TP_SUPPORT */ /* Global variables */ #if PPP_DEBUG u8_t ppp_num; /* PPP Interface counter, used for debugging messages */ #endif /* PPP_DEBUG */ /*************************/ /*** LOCAL DEFINITIONS ***/ /*************************/ /* FIXME: add stats per PPP session */ #if PPP_STATS_SUPPORT static struct timeval start_time; /* Time when link was started. */ static struct pppd_stats old_link_stats; struct pppd_stats link_stats; unsigned link_connect_time; int link_stats_valid; #endif /* PPP_STATS_SUPPORT */ /* * PPP Data Link Layer "protocol" table. * One entry per supported protocol. * The last entry must be NULL. */ const struct protent* const protocols[] = { &lcp_protent, #if PAP_SUPPORT &pap_protent, #endif /* PAP_SUPPORT */ #if CHAP_SUPPORT &chap_protent, #endif /* CHAP_SUPPORT */ #if CBCP_SUPPORT &cbcp_protent, #endif &ipcp_protent, #if PPP_IPV6_SUPPORT &ipv6cp_protent, #endif #if CCP_SUPPORT &ccp_protent, #endif /* CCP_SUPPORT */ #if ECP_SUPPORT &ecp_protent, #endif /* ECP_SUPPORT */ #ifdef AT_CHANGE &atcp_protent, #endif #if EAP_SUPPORT &eap_protent, #endif /* EAP_SUPPORT */ NULL }; /* Prototypes for procedures local to this file. */ static void ppp_clear(ppp_pcb *pcb); static void ppp_do_open(void *arg); static void ppp_start(ppp_pcb *pcb); /** Initiate LCP open request */ static void ppp_stop(ppp_pcb *pcb); static void ppp_hup(ppp_pcb *pcb); static err_t ppp_netif_init_cb(struct netif *netif); static err_t ppp_netif_output_ip4(struct netif *netif, struct pbuf *pb, ip_addr_t *ipaddr); #if PPP_IPV6_SUPPORT static err_t ppp_netif_output_ip6(struct netif *netif, struct pbuf *pb, ip6_addr_t *ipaddr); #endif /* PPP_IPV6_SUPPORT */ static err_t ppp_netif_output(struct netif *netif, struct pbuf *pb, u_short protocol); #if PPPOS_SUPPORT #define ESCAPE_P(accm, c) ((accm)[(c) >> 3] & ppp_accm_mask[c & 0x07]) static void ppp_over_serial_open(ppp_pcb *pcb); static err_t ppp_netif_output_over_serial(ppp_pcb *pcb, struct pbuf *pb, u_short protocol); static int ppp_write_over_serial(ppp_pcb *pcb, struct pbuf *p); static void ppp_drop(ppp_pcb_rx *pcrx); #if PPP_INPROC_MULTITHREADED static void pppos_input_callback(void *arg); #endif /* PPP_INPROC_MULTITHREADED */ static void ppp_free_current_input_packet(ppp_pcb_rx *pcrx); #endif /* PPPOS_SUPPORT */ #if PPPOE_SUPPORT static void ppp_over_ethernet_open(ppp_pcb *pcb); static err_t ppp_netif_output_over_ethernet(ppp_pcb *pcb, struct pbuf *p, u_short protocol); static int ppp_write_over_ethernet(ppp_pcb *pcb, struct pbuf *p); #endif /* PPPOE_SUPPORT */ #if PPPOL2TP_SUPPORT static void ppp_over_l2tp_open(ppp_pcb *pcb); static err_t ppp_netif_output_over_l2tp(ppp_pcb *pcb, struct pbuf *p, u_short protocol); static int ppp_write_over_l2tp(ppp_pcb *pcb, struct pbuf *p); #endif /* PPPOL2TP_SUPPORT */ /***********************************/ /*** PUBLIC FUNCTION DEFINITIONS ***/ /***********************************/ /* Initialize the PPP subsystem. */ int ppp_init(void) { /* * Initialize magic number generator now so that protocols may * use magic numbers in initialization. */ magic_init(); return 0; } /* Create a new PPP session. */ ppp_pcb *ppp_new(void) { ppp_pcb *pcb; pcb = (ppp_pcb*)memp_malloc(MEMP_PPP_PCB); if (pcb == NULL) { return NULL; } memset(pcb, 0, sizeof(ppp_pcb)); #if PPP_DEBUG pcb->num = ppp_num++; #endif /* PPP_DEBUG */ /* default configuration */ pcb->settings.usepeerdns = 1; #if PAP_SUPPORT pcb->settings.pap_timeout_time = UPAP_DEFTIMEOUT; pcb->settings.pap_max_transmits = UPAP_DEFTRANSMITS; #if PPP_SERVER pcb->settings.pap_req_timeout = UPAP_DEFREQTIME; #endif /* PPP_SERVER */ #endif /* PAP_SUPPORT */ #if CHAP_SUPPORT pcb->settings.chap_timeout_time = CHAP_DEFTIMEOUT; pcb->settings.chap_max_transmits = CHAP_DEFTRANSMITS; #if PPP_SERVER pcb->settings.chap_rechallenge_time = CHAP_DEFREQTIME; #endif /* PPP_SERVER */ #endif /* CHAP_SUPPPORT */ #if EAP_SUPPORT pcb->settings.eap_req_time = EAP_DEFREQTIME; pcb->settings.eap_allow_req = EAP_DEFALLOWREQ; #if PPP_SERVER pcb->settings.eap_timeout_time = EAP_DEFTIMEOUT; pcb->settings.eap_max_transmits = EAP_DEFTRANSMITS; #endif /* PPP_SERVER */ #endif /* EAP_SUPPORT */ pcb->settings.lcp_loopbackfail = LCP_DEFLOOPBACKFAIL; pcb->settings.lcp_echo_interval = LCP_ECHOINTERVAL; pcb->settings.lcp_echo_fails = LCP_MAXECHOFAILS; pcb->settings.fsm_timeout_time = FSM_DEFTIMEOUT; pcb->settings.fsm_max_conf_req_transmits = FSM_DEFMAXCONFREQS; pcb->settings.fsm_max_term_transmits = FSM_DEFMAXTERMREQS; pcb->settings.fsm_max_nak_loops = FSM_DEFMAXNAKLOOPS; if (!netif_add(&pcb->netif, &pcb->addrs.our_ipaddr, &pcb->addrs.netmask, &pcb->addrs.his_ipaddr, (void *)pcb, ppp_netif_init_cb, NULL)) { memp_free(MEMP_PPP_PCB, pcb); PPPDEBUG(LOG_ERR, ("ppp_new[%d]: netif_add failed\n", pcb->num)); return NULL; } new_phase(pcb, PPP_PHASE_DEAD); return pcb; } void ppp_set_default(ppp_pcb *pcb) { netif_set_default(&pcb->netif); } void ppp_set_auth(ppp_pcb *pcb, u8_t authtype, char *user, char *passwd) { #if PAP_SUPPORT if (authtype & PPPAUTHTYPE_PAP) { pcb->settings.refuse_pap = 0; } else { pcb->settings.refuse_pap = 1; } #endif /* PAP_SUPPORT */ #if CHAP_SUPPORT if (authtype & PPPAUTHTYPE_CHAP) { pcb->settings.refuse_chap = 0; } else { pcb->settings.refuse_chap = 1; } #if MSCHAP_SUPPORT if (authtype & PPPAUTHTYPE_MSCHAP) { pcb->settings.refuse_mschap = 0; pcb->settings.refuse_mschap_v2 = 0; } else { pcb->settings.refuse_mschap = 1; pcb->settings.refuse_mschap_v2 = 1; } #endif /* MSCHAP_SUPPORT */ #endif /* CHAP_SUPPORT */ #if EAP_SUPPORT if (authtype & PPPAUTHTYPE_EAP) { pcb->settings.refuse_eap = 0; } else { pcb->settings.refuse_eap = 1; } #endif /* EAP_SUPPORT */ if (user) { pcb->settings.user = user; } if (passwd) { pcb->settings.passwd = passwd; } } #if PPP_NOTIFY_PHASE void ppp_set_notify_phase_callback(ppp_pcb *pcb, ppp_notify_phase_cb_fn notify_phase_cb) { pcb->notify_phase_cb = notify_phase_cb; notify_phase_cb(pcb, pcb->phase, pcb->ctx_cb); } #endif /* PPP_NOTIFY_PHASE */ #if PPPOS_SUPPORT int ppp_over_serial_create(ppp_pcb *pcb, sio_fd_t fd, ppp_link_status_cb_fn link_status_cb, void *ctx_cb) { /* PPP is single-threaded: without a callback, * there is no way to know when the link is up. */ if (link_status_cb == NULL) { return PPPERR_PARAM; } pcb->fd = fd; pcb->link_status_cb = link_status_cb; pcb->ctx_cb = ctx_cb; return PPPERR_NONE; } /* * ppp_set_xaccm - set the extended transmit ACCM for the interface. */ void ppp_set_xaccm(ppp_pcb *pcb, ext_accm *accm) { SMEMCPY(pcb->out_accm, accm, sizeof(ext_accm)); PPPDEBUG(LOG_INFO, ("ppp_set_xaccm[%d]: out_accm=%X %X %X %X\n", pcb->num, pcb->out_accm[0], pcb->out_accm[1], pcb->out_accm[2], pcb->out_accm[3])); } #endif /* PPPOS_SUPPORT */ #if PPPOE_SUPPORT static void ppp_over_ethernet_link_status_cb(ppp_pcb *pcb, int state); int ppp_over_ethernet_create(ppp_pcb *pcb, struct netif *ethif, const char *service_name, const char *concentrator_name, ppp_link_status_cb_fn link_status_cb, void *ctx_cb) { LWIP_UNUSED_ARG(service_name); LWIP_UNUSED_ARG(concentrator_name); /* PPP is single-threaded: without a callback, * there is no way to know when the link is up. */ if (link_status_cb == NULL) { return PPPERR_PARAM; } pcb->link_status_cb = link_status_cb; pcb->ctx_cb = ctx_cb; if (pppoe_create(ethif, pcb, ppp_over_ethernet_link_status_cb, &pcb->pppoe_sc) != ERR_OK) { return PPPERR_OPEN; } return PPPERR_NONE; } #endif /* PPPOE_SUPPORT */ #if PPPOL2TP_SUPPORT static void ppp_over_l2tp_link_status_cb(ppp_pcb *pcb, int state); int ppp_over_l2tp_create(ppp_pcb *pcb, struct netif *netif, ip_addr_t *ipaddr, u16_t port, u8_t *secret, u8_t secret_len, ppp_link_status_cb_fn link_status_cb, void *ctx_cb) { /* PPP is single-threaded: without a callback, * there is no way to know when the link is up. */ if (link_status_cb == NULL) { return PPPERR_PARAM; } pcb->link_status_cb = link_status_cb; pcb->ctx_cb = ctx_cb; if (pppol2tp_create(pcb, ppp_over_l2tp_link_status_cb, &pcb->l2tp_pcb, netif, ipaddr, port, secret, secret_len) != ERR_OK) { return PPPERR_OPEN; } return PPPERR_NONE; } #endif /* PPPOL2TP_SUPPORT */ /* * Open a PPP connection. * * This can only be called if PPP is in the dead phase. * * Holdoff is the time to wait (in seconds) before initiating * the connection. */ int ppp_open(ppp_pcb *pcb, u16_t holdoff) { if (pcb->phase != PPP_PHASE_DEAD) { return PPPERR_PARAM; } PPPDEBUG(LOG_DEBUG, ("ppp_open() called, holdoff=%d\n", holdoff)); if (holdoff == 0) { ppp_do_open(pcb); return PPPERR_NONE; } new_phase(pcb, PPP_PHASE_HOLDOFF); sys_timeout((u32_t)(holdoff*1000), ppp_do_open, pcb); return PPPERR_NONE; } /* * Initiate the end of a PPP connection. * Any outstanding packets in the queues are dropped. * Return 0 on success, an error code on failure. */ int ppp_close(ppp_pcb *pcb) { int st = 0; pcb->err_code = PPPERR_USER; /* dead phase, nothing to do, call the status callback to be consistent */ if (pcb->phase == PPP_PHASE_DEAD) { pcb->link_status_cb(pcb, pcb->err_code, pcb->ctx_cb); return PPPERR_NONE; } /* holdoff phase, cancel the reconnection and call the status callback */ if (pcb->phase == PPP_PHASE_HOLDOFF) { sys_untimeout(ppp_do_open, pcb); pcb->link_status_cb(pcb, pcb->err_code, pcb->ctx_cb); return PPPERR_NONE; } PPPDEBUG(LOG_DEBUG, ("ppp_close() called\n")); /* Disconnect */ #if PPPOE_SUPPORT if (pcb->pppoe_sc) { PPPDEBUG(LOG_DEBUG, ("ppp_close: unit %d kill_link -> ppp_stop\n", pcb->num)); /* This will leave us at PPP_PHASE_DEAD. */ ppp_stop(pcb); } else #endif /* PPPOE_SUPPORT */ #if PPPOL2TP_SUPPORT if (pcb->l2tp_pcb) { PPPDEBUG(LOG_DEBUG, ("ppp_close: unit %d kill_link -> ppp_stop\n", pcb->num)); /* This will leave us at PPP_PHASE_DEAD. */ ppp_stop(pcb); } else #endif /* PPPOL2TP_SUPPORT */ { #if PPPOS_SUPPORT PPPDEBUG(LOG_DEBUG, ("ppp_close: unit %d kill_link -> ppp_stop\n", pcb->num)); /* This will leave us at PPP_PHASE_DEAD. */ ppp_stop(pcb); #endif /* PPPOS_SUPPORT */ } return st; } /* This function is called when carrier is lost on the PPP channel. */ void ppp_sighup(ppp_pcb *pcb) { PPPDEBUG(LOG_DEBUG, ("ppp_sighup: unit %d sig_hup -> ppp_hup\n", pcb->num)); ppp_hup(pcb); } /* * Free the control block, clean everything except the PPP PCB itself * and the netif, it allows you to change the underlying PPP protocol * (eg. from PPPoE to PPPoS to switch from DSL to GPRS) without losing * your PPP and netif handlers. * * This can only be called if PPP is in the dead phase. * * You must use ppp_close() before if you wish to terminate * an established PPP session. * * Return 0 on success, an error code on failure. */ int ppp_free(ppp_pcb *pcb) { if (pcb->phase != PPP_PHASE_DEAD) { return PPPERR_PARAM; } PPPDEBUG(LOG_DEBUG, ("ppp_free: unit %d\n", pcb->num)); #if PPPOE_SUPPORT if (pcb->pppoe_sc) { pppoe_destroy(pcb->pppoe_sc); pcb->pppoe_sc = NULL; } #endif /* PPPOE_SUPPORT */ #if PPPOL2TP_SUPPORT if (pcb->l2tp_pcb) { pppol2tp_destroy(pcb->l2tp_pcb); pcb->l2tp_pcb = NULL; } #endif /* PPPOL2TP_SUPPORT */ #if PPPOS_SUPPORT /* input pbuf left ? */ ppp_free_current_input_packet(&pcb->rx); #endif /* PPPOS_SUPPORT */ return 0; } /* * Release the control block. * * This can only be called if PPP is in the dead phase. * * You must use ppp_close() before if you wish to terminate * an established PPP session. * * Return 0 on success, an error code on failure. */ int ppp_delete(ppp_pcb *pcb) { int err; if (pcb->phase != PPP_PHASE_DEAD) { return PPPERR_PARAM; } PPPDEBUG(LOG_DEBUG, ("ppp_delete: unit %d\n", pcb->num)); netif_remove(&pcb->netif); if( (err = ppp_free(pcb)) != PPPERR_NONE) { return err; } memp_free(MEMP_PPP_PCB, pcb); return 0; } /************************************/ /*** PRIVATE FUNCTION DEFINITIONS ***/ /************************************/ /* Set a PPP PCB to its initial state */ static void ppp_clear(ppp_pcb *pcb) { const struct protent *protp; int i; LWIP_ASSERT("pcb->phase == PPP_PHASE_DEAD || pcb->phase == PPP_PHASE_HOLDOFF", pcb->phase == PPP_PHASE_DEAD || pcb->phase == PPP_PHASE_HOLDOFF); #if PPP_STATS_SUPPORTs link_stats_valid = 0; #endif /* PPP_STATS_SUPPORT */ memset(&pcb->phase, 0, sizeof(ppp_pcb) - ( (char*)&((ppp_pcb*)0)->phase - (char*)0 ) ); IP4_ADDR(&pcb->addrs.netmask, 255,255,255,255); /* * Initialize each protocol. */ for (i = 0; (protp = protocols[i]) != NULL; ++i) { (*protp->init)(pcb); } new_phase(pcb, PPP_PHASE_INITIALIZE); } static void ppp_do_open(void *arg) { ppp_pcb *pcb = (ppp_pcb*)arg; LWIP_ASSERT("pcb->phase == PPP_PHASE_DEAD || pcb->phase == PPP_PHASE_HOLDOFF", pcb->phase == PPP_PHASE_DEAD || pcb->phase == PPP_PHASE_HOLDOFF); #if PPPOE_SUPPORT if (pcb->pppoe_sc) { ppp_over_ethernet_open(pcb); return; } #endif /* PPPOE_SUPPORT */ #if PPPOL2TP_SUPPORT if (pcb->l2tp_pcb) { ppp_over_l2tp_open(pcb); return; } #endif /* PPPOL2TP_SUPPORT */ #if PPPOS_SUPPORT ppp_over_serial_open(pcb); #endif /* PPPOS_SUPPORT */ } /** Initiate LCP open request */ static void ppp_start(ppp_pcb *pcb) { PPPDEBUG(LOG_DEBUG, ("ppp_start: unit %d\n", pcb->num)); lcp_open(pcb); /* Start protocol */ lcp_lowerup(pcb); PPPDEBUG(LOG_DEBUG, ("ppp_start: finished\n")); } /** LCP close request */ static void ppp_stop(ppp_pcb *pcb) { PPPDEBUG(LOG_DEBUG, ("ppp_stop: unit %d\n", pcb->num)); lcp_close(pcb, "User request"); } /** Called when carrier/link is lost */ static void ppp_hup(ppp_pcb *pcb) { PPPDEBUG(LOG_DEBUG, ("ppp_hup: unit %d\n", pcb->num)); lcp_lowerdown(pcb); link_terminated(pcb); } /* * Pass the processed input packet to the appropriate handler. * This function and all handlers run in the context of the tcpip_thread */ void ppp_input(ppp_pcb *pcb, struct pbuf *pb) { u16_t protocol; protocol = (((u8_t *)pb->payload)[0] << 8) | ((u8_t*)pb->payload)[1]; #if PRINTPKT_SUPPORT ppp_dump_packet("rcvd", pb->payload, pb->len); #endif /* PRINTPKT_SUPPORT */ if(pbuf_header(pb, -(s16_t)sizeof(protocol))) { LWIP_ASSERT("pbuf_header failed\n", 0); goto drop; } LINK_STATS_INC(link.recv); snmp_inc_ifinucastpkts(&pcb->netif); snmp_add_ifinoctets(&pcb->netif, pb->tot_len); /* * Toss all non-LCP packets unless LCP is OPEN. */ if (protocol != PPP_LCP && pcb->lcp_fsm.state != PPP_FSM_OPENED) { ppp_dbglog("Discarded non-LCP packet when LCP not open"); goto drop; } /* * Until we get past the authentication phase, toss all packets * except LCP, LQR and authentication packets. */ if (pcb->phase <= PPP_PHASE_AUTHENTICATE && !(protocol == PPP_LCP #if LQR_SUPPORT || protocol == PPP_LQR #endif /* LQR_SUPPORT */ #if PAP_SUPPORT || protocol == PPP_PAP #endif /* PAP_SUPPORT */ #if CHAP_SUPPORT || protocol == PPP_CHAP #endif /* CHAP_SUPPORT */ #if EAP_SUPPORT || protocol == PPP_EAP #endif /* EAP_SUPPORT */ )) { ppp_dbglog("discarding proto 0x%x in phase %d", protocol, pcb->phase); goto drop; } /* FIXME: should we write protent to do that ? */ switch(protocol) { #if VJ_SUPPORT case PPP_VJC_COMP: /* VJ compressed TCP */ PPPDEBUG(LOG_INFO, ("ppp_input[%d]: vj_comp in pbuf len=%d\n", pcb->num, pb->len)); /* * Clip off the VJ header and prepend the rebuilt TCP/IP header and * pass the result to IP. */ if (vj_uncompress_tcp(&pb, &pcb->vj_comp) >= 0) { ip_input(pb, &pcb->netif); return; } /* Something's wrong so drop it. */ PPPDEBUG(LOG_WARNING, ("ppp_input[%d]: Dropping VJ compressed\n", pcb->num)); break; case PPP_VJC_UNCOMP: /* VJ uncompressed TCP */ PPPDEBUG(LOG_INFO, ("ppp_input[%d]: vj_un in pbuf len=%d\n", pcb->num, pb->len)); /* * Process the TCP/IP header for VJ header compression and then pass * the packet to IP. */ if (vj_uncompress_uncomp(pb, &pcb->vj_comp) >= 0) { ip_input(pb, &pcb->netif); return; } /* Something's wrong so drop it. */ PPPDEBUG(LOG_WARNING, ("ppp_input[%d]: Dropping VJ uncompressed\n", pcb->num)); break; #endif /* VJ_SUPPORT */ case PPP_IP: /* Internet Protocol */ PPPDEBUG(LOG_INFO, ("ppp_input[%d]: ip in pbuf len=%d\n", pcb->num, pb->len)); ip_input(pb, &pcb->netif); return; #if PPP_IPV6_SUPPORT case PPP_IPV6: /* Internet Protocol Version 6 */ PPPDEBUG(LOG_INFO, ("ppp_input[%d]: ip6 in pbuf len=%d\n", pcb->num, pb->len)); ip6_input(pb, &pcb->netif); return; #endif /* PPP_IPV6_SUPPORT */ default: { int i; const struct protent *protp; /* * Upcall the proper protocol input routine. */ for (i = 0; (protp = protocols[i]) != NULL; ++i) { if (protp->protocol == protocol && protp->enabled_flag) { pb = ppp_singlebuf(pb); (*protp->input)(pcb, pb->payload, pb->len); goto out; } #if 0 /* UNUSED * * This is actually a (hacked?) way for the PPP kernel implementation to pass a * data packet to the PPP daemon. The PPP daemon normally only do signaling * (LCP, PAP, CHAP, IPCP, ...) and does not handle any data packet at all. * * This is only used by CCP, which we cannot support until we have a CCP data * implementation. */ if (protocol == (protp->protocol & ~0x8000) && protp->enabled_flag && protp->datainput != NULL) { (*protp->datainput)(pcb, pb->payload, pb->len); goto out; } #endif /* UNUSED */ } #if PPP_DEBUG #if PPP_PROTOCOLNAME const char *pname = protocol_name(protocol); if (pname != NULL) { ppp_warn("Unsupported protocol '%s' (0x%x) received", pname, protocol); } else #endif /* PPP_PROTOCOLNAME */ ppp_warn("Unsupported protocol 0x%x received", protocol); #endif /* PPP_DEBUG */ if (pbuf_header(pb, (s16_t)sizeof(protocol))) { LWIP_ASSERT("pbuf_header failed\n", 0); goto drop; } lcp_sprotrej(pcb, pb->payload, pb->len); } break; } drop: LINK_STATS_INC(link.drop); snmp_inc_ifindiscards(&pcb->netif); out: pbuf_free(pb); magic_randomize(); return; } #if PPPOS_SUPPORT #if PPP_FCS_TABLE /* * FCS lookup table as calculated by genfcstab. */ static const u_short fcstab[256] = { 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7, 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e, 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876, 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c, 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974, 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb, 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3, 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a, 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72, 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9, 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1, 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70, 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7, 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff, 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036, 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e, 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5, 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd, 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134, 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3, 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb, 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232, 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a, 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1, 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9, 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78 }; #else /* PPP_FCS_TABLE */ /* The HDLC polynomial: X**0 + X**5 + X**12 + X**16 (0x8408) */ #define PPP_FCS_POLYNOMIAL 0x8408 u16_t ppp_get_fcs(u8_t byte) { unsigned int octet; int bit; octet = byte; for (bit = 8; bit-- > 0; ) { octet = (octet & 0x01) ? ((octet >> 1) ^ PPP_FCS_POLYNOMIAL) : (octet >> 1); } return octet & 0xffff; } #endif /* PPP_FCS_TABLE */ /* PPP's Asynchronous-Control-Character-Map. The mask array is used * to select the specific bit for a character. */ static u_char ppp_accm_mask[] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 }; #endif /* PPPOS_SUPPORT */ /* * ppp_netif_init_cb - netif init callback */ static err_t ppp_netif_init_cb(struct netif *netif) { netif->name[0] = 'p'; netif->name[1] = 'p'; netif->output = ppp_netif_output_ip4; #if PPP_IPV6_SUPPORT netif->output_ip6 = ppp_netif_output_ip6; #endif /* PPP_IPV6_SUPPORT */ netif->flags = NETIF_FLAG_POINTTOPOINT | NETIF_FLAG_LINK_UP; #if LWIP_NETIF_HOSTNAME /* @todo: Initialize interface hostname */ /* netif_set_hostname(netif, "lwip"); */ #endif /* LWIP_NETIF_HOSTNAME */ return ERR_OK; } /**********************************/ /*** LOCAL FUNCTION DEFINITIONS ***/ /**********************************/ #if PPPOS_SUPPORT static void ppp_over_serial_open(ppp_pcb *pcb) { /* input pbuf left over from last session? */ ppp_free_current_input_packet(&pcb->rx); ppp_clear(pcb); pcb->rx.pcb = pcb; pcb->rx.fd = pcb->fd; #if VJ_SUPPORT vj_compress_init(&pcb->vj_comp); #endif /* VJ_SUPPORT */ /* * Default the in and out accm so that escape and flag characters * are always escaped. */ pcb->rx.in_accm[15] = 0x60; /* no need to protect since RX is not running */ pcb->out_accm[15] = 0x60; /* * Start the connection and handle incoming events (packet or timeout). */ PPPDEBUG(LOG_INFO, ("ppp_over_serial_open: unit %d: connecting\n", pcb->num)); ppp_start(pcb); } static void pppos_put(ppp_pcb *pcb, struct pbuf *nb) { struct pbuf *b; int c; for(b = nb; b != NULL; b = b->next) { c = sio_write(pcb->fd, b->payload, b->len); if(c != b->len) { PPPDEBUG(LOG_WARNING, ("PPP pppos_put: incomplete sio_write(fd:%"SZT_F", len:%d, c: 0x%"X8_F") c = %d\n", (size_t)pcb->fd, b->len, c, c)); LINK_STATS_INC(link.err); pcb->last_xmit = 0; /* prepend PPP_FLAG to next packet */ snmp_inc_ifoutdiscards(&pcb->netif); pbuf_free(nb); return; } } snmp_add_ifoutoctets(&pcb->netif, nb->tot_len); snmp_inc_ifoutucastpkts(&pcb->netif); pbuf_free(nb); LINK_STATS_INC(link.xmit); } /* * ppp_append - append given character to end of given pbuf. If out_accm * is not NULL and the character needs to be escaped, do so. * If pbuf is full, append another. * Return the current pbuf. */ static struct pbuf * ppp_append(u_char c, struct pbuf *nb, ext_accm *out_accm) { struct pbuf *tb = nb; /* Make sure there is room for the character and an escape code. * Sure we don't quite fill the buffer if the character doesn't * get escaped but is one character worth complicating this? */ /* Note: We assume no packet header. */ if (nb && (PBUF_POOL_BUFSIZE - nb->len) < 2) { tb = pbuf_alloc(PBUF_RAW, 0, PBUF_POOL); if (tb) { nb->next = tb; } else { LINK_STATS_INC(link.memerr); } nb = tb; } if (nb) { if (out_accm && ESCAPE_P(*out_accm, c)) { *((u_char*)nb->payload + nb->len++) = PPP_ESCAPE; *((u_char*)nb->payload + nb->len++) = c ^ PPP_TRANS; } else { *((u_char*)nb->payload + nb->len++) = c; } } return tb; } #endif /* PPPOS_SUPPORT */ /* Send a IPv4 packet on the given connection. */ static err_t ppp_netif_output_ip4(struct netif *netif, struct pbuf *pb, ip_addr_t *ipaddr) { LWIP_UNUSED_ARG(ipaddr); return ppp_netif_output(netif, pb, PPP_IP); } #if PPP_IPV6_SUPPORT /* Send a IPv6 packet on the given connection. */ static err_t ppp_netif_output_ip6(struct netif *netif, struct pbuf *pb, ip6_addr_t *ipaddr) { LWIP_UNUSED_ARG(ipaddr); return ppp_netif_output(netif, pb, PPP_IPV6); } #endif /* PPP_IPV6_SUPPORT */ /* Send a packet on the given connection. * * This is the low level function that send the PPP packet, * only for IPv4 and IPv6 packets coming from lwIP. */ static err_t ppp_netif_output(struct netif *netif, struct pbuf *pb, u_short protocol) { ppp_pcb *pcb = (ppp_pcb*)netif->state; /* Validate parameters. */ /* We let any protocol value go through - it can't hurt us * and the peer will just drop it if it's not accepting it. */ if (!pcb || !pb) { PPPDEBUG(LOG_WARNING, ("ppp_netif_output[%d]: bad params prot=%d pb=%p\n", pcb->num, PPP_IP, (void*)pb)); LINK_STATS_INC(link.opterr); LINK_STATS_INC(link.drop); snmp_inc_ifoutdiscards(netif); return ERR_ARG; } /* Check that the link is up. */ if (!pcb->if_up) { PPPDEBUG(LOG_ERR, ("ppp_netif_output[%d]: link not up\n", pcb->num)); LINK_STATS_INC(link.rterr); LINK_STATS_INC(link.drop); snmp_inc_ifoutdiscards(netif); return ERR_RTE; } #if PPPOE_SUPPORT if(pcb->pppoe_sc) { return ppp_netif_output_over_ethernet(pcb, pb, protocol); } #endif /* PPPOE_SUPPORT */ #if PPPOL2TP_SUPPORT if(pcb->l2tp_pcb) { return ppp_netif_output_over_l2tp(pcb, pb, protocol); } #endif /* PPPOL2TP_SUPPORT */ #if PPPOS_SUPPORT return ppp_netif_output_over_serial(pcb, pb, protocol); #endif /* PPPOS_SUPPORT */ #if !PPPOS_SUPPORT return ERR_OK; #endif } #if PPPOS_SUPPORT static err_t ppp_netif_output_over_serial(ppp_pcb *pcb, struct pbuf *pb, u_short protocol) { u_int fcs_out = PPP_INITFCS; struct pbuf *head = NULL, *tail = NULL, *p; u_char c; /* Grab an output buffer. */ head = pbuf_alloc(PBUF_RAW, 0, PBUF_POOL); if (head == NULL) { PPPDEBUG(LOG_WARNING, ("ppp_netif_output[%d]: first alloc fail\n", pcb->num)); LINK_STATS_INC(link.memerr); LINK_STATS_INC(link.drop); snmp_inc_ifoutdiscards(&pcb->netif); return ERR_MEM; } #if VJ_SUPPORT /* * Attempt Van Jacobson header compression if VJ is configured and * this is an IP packet. */ if (protocol == PPP_IP && pcb->vj_enabled) { switch (vj_compress_tcp(&pcb->vj_comp, pb)) { case TYPE_IP: /* No change... protocol = PPP_IP_PROTOCOL; */ break; case TYPE_COMPRESSED_TCP: protocol = PPP_VJC_COMP; break; case TYPE_UNCOMPRESSED_TCP: protocol = PPP_VJC_UNCOMP; break; default: PPPDEBUG(LOG_WARNING, ("ppp_netif_output[%d]: bad IP packet\n", pcb->num)); LINK_STATS_INC(link.proterr); LINK_STATS_INC(link.drop); snmp_inc_ifoutdiscards(&pcb->netif); pbuf_free(head); return ERR_VAL; } } #endif /* VJ_SUPPORT */ tail = head; /* Build the PPP header. */ if ((sys_jiffies() - pcb->last_xmit) >= PPP_MAXIDLEFLAG) { tail = ppp_append(PPP_FLAG, tail, NULL); } pcb->last_xmit = sys_jiffies(); if (!pcb->accomp) { fcs_out = PPP_FCS(fcs_out, PPP_ALLSTATIONS); tail = ppp_append(PPP_ALLSTATIONS, tail, &pcb->out_accm); fcs_out = PPP_FCS(fcs_out, PPP_UI); tail = ppp_append(PPP_UI, tail, &pcb->out_accm); } if (!pcb->pcomp || protocol > 0xFF) { c = (protocol >> 8) & 0xFF; fcs_out = PPP_FCS(fcs_out, c); tail = ppp_append(c, tail, &pcb->out_accm); } c = protocol & 0xFF; fcs_out = PPP_FCS(fcs_out, c); tail = ppp_append(c, tail, &pcb->out_accm); /* Load packet. */ for(p = pb; p; p = p->next) { int n; u_char *sPtr; sPtr = (u_char*)p->payload; n = p->len; while (n-- > 0) { c = *sPtr++; /* Update FCS before checking for special characters. */ fcs_out = PPP_FCS(fcs_out, c); /* Copy to output buffer escaping special characters. */ tail = ppp_append(c, tail, &pcb->out_accm); } } /* Add FCS and trailing flag. */ c = ~fcs_out & 0xFF; tail = ppp_append(c, tail, &pcb->out_accm); c = (~fcs_out >> 8) & 0xFF; tail = ppp_append(c, tail, &pcb->out_accm); tail = ppp_append(PPP_FLAG, tail, NULL); /* If we failed to complete the packet, throw it away. */ if (!tail) { PPPDEBUG(LOG_WARNING, ("ppp_netif_output[%d]: Alloc err - dropping proto=%d\n", pcb->num, protocol)); pbuf_free(head); LINK_STATS_INC(link.memerr); LINK_STATS_INC(link.drop); snmp_inc_ifoutdiscards(&pcb->netif); return ERR_MEM; } /* Send it. */ PPPDEBUG(LOG_INFO, ("ppp_netif_output[%d]: proto=0x%"X16_F"\n", pcb->num, protocol)); pppos_put(pcb, head); return ERR_OK; } #endif /* PPPOS_SUPPORT */ #if PPPOE_SUPPORT static err_t ppp_netif_output_over_ethernet(ppp_pcb *pcb, struct pbuf *p, u_short protocol) { struct pbuf *pb; int i=0; u16_t tot_len; err_t err; /* @todo: try to use pbuf_header() here! */ pb = pbuf_alloc(PBUF_LINK, PPPOE_HEADERLEN + sizeof(protocol), PBUF_RAM); if(!pb) { LINK_STATS_INC(link.memerr); LINK_STATS_INC(link.proterr); snmp_inc_ifoutdiscards(&pcb->netif); return ERR_MEM; } pbuf_header(pb, -(s16_t)PPPOE_HEADERLEN); pcb->last_xmit = sys_jiffies(); if (!pcb->pcomp || protocol > 0xFF) { *((u_char*)pb->payload + i++) = (protocol >> 8) & 0xFF; } *((u_char*)pb->payload + i) = protocol & 0xFF; pbuf_chain(pb, p); tot_len = pb->tot_len; if( (err = pppoe_xmit(pcb->pppoe_sc, pb)) != ERR_OK) { LINK_STATS_INC(link.err); snmp_inc_ifoutdiscards(&pcb->netif); return err; } snmp_add_ifoutoctets(&pcb->netif, tot_len); snmp_inc_ifoutucastpkts(&pcb->netif); LINK_STATS_INC(link.xmit); return ERR_OK; } #endif /* PPPOE_SUPPORT */ #if PPPOL2TP_SUPPORT static err_t ppp_netif_output_over_l2tp(ppp_pcb *pcb, struct pbuf *p, u_short protocol) { struct pbuf *pb; int i=0; u16_t tot_len; err_t err; /* @todo: try to use pbuf_header() here! */ pb = pbuf_alloc(PBUF_TRANSPORT, PPPOL2TP_OUTPUT_DATA_HEADER_LEN + sizeof(protocol), PBUF_RAM); if(!pb) { LINK_STATS_INC(link.memerr); LINK_STATS_INC(link.proterr); snmp_inc_ifoutdiscards(&pcb->netif); return ERR_MEM; } pbuf_header(pb, -(s16_t)PPPOL2TP_OUTPUT_DATA_HEADER_LEN); pcb->last_xmit = sys_jiffies(); if (!pcb->pcomp || protocol > 0xFF) { *((u_char*)pb->payload + i++) = (protocol >> 8) & 0xFF; } *((u_char*)pb->payload + i) = protocol & 0xFF; pbuf_chain(pb, p); tot_len = pb->tot_len; if( (err = pppol2tp_xmit(pcb->l2tp_pcb, pb)) != ERR_OK) { LINK_STATS_INC(link.err); snmp_inc_ifoutdiscards(&pcb->netif); return err; } snmp_add_ifoutoctets(&pcb->netif, tot_len); snmp_inc_ifoutucastpkts(&pcb->netif); LINK_STATS_INC(link.xmit); return ERR_OK; } #endif /* PPPOL2TP_SUPPORT */ /* Get and set parameters for the given connection. * Return 0 on success, an error code on failure. */ int ppp_ioctl(ppp_pcb *pcb, int cmd, void *arg) { if(NULL == pcb) return PPPERR_PARAM; switch(cmd) { case PPPCTLG_UPSTATUS: /* Get the PPP up status. */ if (arg) { *(int *)arg = (int)(pcb->if_up); return PPPERR_NONE; } return PPPERR_PARAM; break; case PPPCTLS_ERRCODE: /* Set the PPP error code. */ if (arg) { pcb->err_code = (u8_t)(*(int *)arg); return PPPERR_NONE; } return PPPERR_PARAM; break; case PPPCTLG_ERRCODE: /* Get the PPP error code. */ if (arg) { *(int *)arg = (int)(pcb->err_code); return PPPERR_NONE; } return PPPERR_PARAM; break; #if PPPOS_SUPPORT case PPPCTLG_FD: /* Get the fd associated with the ppp */ if (arg) { *(sio_fd_t *)arg = pcb->fd; return PPPERR_NONE; } return PPPERR_PARAM; break; #endif /* PPPOS_SUPPORT */ } return PPPERR_PARAM; } /* * Write a pbuf to a ppp link, only used from PPP functions * to send PPP packets. * * IPv4 and IPv6 packets from lwIP are sent, respectively, * with ppp_netif_output_ip4() and ppp_netif_output_ip6() * functions (which are callbacks of the netif PPP interface). * * RETURN: >= 0 Number of characters written * -1 Failed to write to device */ int ppp_write(ppp_pcb *pcb, struct pbuf *p) { #if PRINTPKT_SUPPORT ppp_dump_packet("sent", (unsigned char *)p->payload+2, p->len-2); #endif /* PRINTPKT_SUPPORT */ #if PPPOE_SUPPORT if(pcb->pppoe_sc) { return ppp_write_over_ethernet(pcb, p); } #endif /* PPPOE_SUPPORT */ #if PPPOL2TP_SUPPORT if(pcb->l2tp_pcb) { return ppp_write_over_l2tp(pcb, p); } #endif /* PPPOL2TP_SUPPORT */ #if PPPOS_SUPPORT return ppp_write_over_serial(pcb, p); #endif /* PPPOS_SUPPORT */ #if !PPPOS_SUPPORT pbuf_free(p); return PPPERR_NONE; #endif } #if PPPOS_SUPPORT static int ppp_write_over_serial(ppp_pcb *pcb, struct pbuf *p) { u_char *s = p->payload; int n = p->len; u_char c; u_int fcs_out; struct pbuf *head, *tail; head = pbuf_alloc(PBUF_RAW, 0, PBUF_POOL); if (head == NULL) { LINK_STATS_INC(link.memerr); LINK_STATS_INC(link.proterr); snmp_inc_ifoutdiscards(&pcb->netif); pbuf_free(p); return PPPERR_ALLOC; } tail = head; /* If the link has been idle, we'll send a fresh flag character to * flush any noise. */ if ((sys_jiffies() - pcb->last_xmit) >= PPP_MAXIDLEFLAG) { tail = ppp_append(PPP_FLAG, tail, NULL); } pcb->last_xmit = sys_jiffies(); fcs_out = PPP_INITFCS; /* Load output buffer. */ while (n-- > 0) { c = *s++; /* Update FCS before checking for special characters. */ fcs_out = PPP_FCS(fcs_out, c); /* Copy to output buffer escaping special characters. */ tail = ppp_append(c, tail, &pcb->out_accm); } /* Add FCS and trailing flag. */ c = ~fcs_out & 0xFF; tail = ppp_append(c, tail, &pcb->out_accm); c = (~fcs_out >> 8) & 0xFF; tail = ppp_append(c, tail, &pcb->out_accm); tail = ppp_append(PPP_FLAG, tail, NULL); /* If we failed to complete the packet, throw it away. * Otherwise send it. */ if (!tail) { PPPDEBUG(LOG_WARNING, ("ppp_write[%d]: Alloc err - dropping pbuf len=%d\n", pcb->num, head->len)); /*"ppp_write[%d]: Alloc err - dropping %d:%.*H", pd, head->len, LWIP_MIN(head->len * 2, 40), head->payload)); */ pbuf_free(head); LINK_STATS_INC(link.memerr); LINK_STATS_INC(link.proterr); snmp_inc_ifoutdiscards(&pcb->netif); pbuf_free(p); return PPPERR_ALLOC; } PPPDEBUG(LOG_INFO, ("ppp_write[%d]: len=%d\n", pcb->num, head->len)); /* "ppp_write[%d]: %d:%.*H", pd, head->len, LWIP_MIN(head->len * 2, 40), head->payload)); */ pppos_put(pcb, head); pbuf_free(p); return PPPERR_NONE; } #endif /* PPPOS_SUPPORT */ #if PPPOE_SUPPORT static int ppp_write_over_ethernet(ppp_pcb *pcb, struct pbuf *p) { struct pbuf *ph; /* Ethernet + PPPoE header */ u16_t tot_len; /* skip address & flags */ pbuf_header(p, -(s16_t)2); ph = pbuf_alloc(PBUF_LINK, (u16_t)(PPPOE_HEADERLEN), PBUF_RAM); if(!ph) { LINK_STATS_INC(link.memerr); LINK_STATS_INC(link.proterr); snmp_inc_ifoutdiscards(&pcb->netif); pbuf_free(p); return PPPERR_ALLOC; } pbuf_header(ph, -(s16_t)PPPOE_HEADERLEN); /* hide PPPoE header */ pbuf_cat(ph, p); tot_len = ph->tot_len; pcb->last_xmit = sys_jiffies(); if(pppoe_xmit(pcb->pppoe_sc, ph) != ERR_OK) { LINK_STATS_INC(link.err); snmp_inc_ifoutdiscards(&pcb->netif); return PPPERR_DEVICE; } snmp_add_ifoutoctets(&pcb->netif, (u16_t)tot_len); snmp_inc_ifoutucastpkts(&pcb->netif); LINK_STATS_INC(link.xmit); return PPPERR_NONE; } #endif /* PPPOE_SUPPORT */ #if PPPOL2TP_SUPPORT static int ppp_write_over_l2tp(ppp_pcb *pcb, struct pbuf *p) { struct pbuf *ph; /* UDP + L2TP header */ u16_t tot_len; ph = pbuf_alloc(PBUF_TRANSPORT, (u16_t)(PPPOL2TP_OUTPUT_DATA_HEADER_LEN), PBUF_RAM); if(!ph) { LINK_STATS_INC(link.memerr); LINK_STATS_INC(link.proterr); snmp_inc_ifoutdiscards(&pcb->netif); pbuf_free(p); return PPPERR_ALLOC; } pbuf_header(ph, -(s16_t)PPPOL2TP_OUTPUT_DATA_HEADER_LEN); /* hide L2TP header */ pbuf_cat(ph, p); tot_len = ph->tot_len; pcb->last_xmit = sys_jiffies(); if(pppol2tp_xmit(pcb->l2tp_pcb, ph) != ERR_OK) { LINK_STATS_INC(link.err); snmp_inc_ifoutdiscards(&pcb->netif); return PPPERR_DEVICE; } snmp_add_ifoutoctets(&pcb->netif, (u16_t)tot_len); snmp_inc_ifoutucastpkts(&pcb->netif); LINK_STATS_INC(link.xmit); return PPPERR_NONE; } #endif /* PPPOL2TP_SUPPORT */ #if PPPOS_SUPPORT /* * Drop the input packet. */ static void ppp_free_current_input_packet(ppp_pcb_rx *pcrx) { if (pcrx->in_head != NULL) { if (pcrx->in_tail && (pcrx->in_tail != pcrx->in_head)) { pbuf_free(pcrx->in_tail); } pbuf_free(pcrx->in_head); pcrx->in_head = NULL; } pcrx->in_tail = NULL; } /* * Drop the input packet and increase error counters. */ static void ppp_drop(ppp_pcb_rx *pcrx) { #if LWIP_SNMP || VJ_SUPPORT ppp_pcb *pcb = (ppp_pcb*)pcrx->pcb; #endif /* LWIP_SNMP || VJ_SUPPORT */ if (pcrx->in_head != NULL) { #if 0 PPPDEBUG(LOG_INFO, ("ppp_drop: %d:%.*H\n", pcrx->in_head->len, min(60, pcrx->in_head->len * 2), pcrx->in_head->payload)); #endif PPPDEBUG(LOG_INFO, ("ppp_drop: pbuf len=%d, addr %p\n", pcrx->in_head->len, (void*)pcrx->in_head)); } ppp_free_current_input_packet(pcrx); #if VJ_SUPPORT vj_uncompress_err(&pcb->vj_comp); #endif /* VJ_SUPPORT */ LINK_STATS_INC(link.drop); snmp_inc_ifindiscards(&pcb->netif); } /** PPPoS input helper struct, must be packed since it is stored * to pbuf->payload, which might be unaligned. */ #if PPP_INPROC_MULTITHREADED #ifdef PACK_STRUCT_USE_INCLUDES # include "arch/bpstruct.h" #endif PACK_STRUCT_BEGIN struct pppos_input_header { PACK_STRUCT_FIELD(ppp_pcb *pcb); } PACK_STRUCT_STRUCT; PACK_STRUCT_END #ifdef PACK_STRUCT_USE_INCLUDES # include "arch/epstruct.h" #endif #endif /* PPP_INPROC_MULTITHREADED */ /** Pass received raw characters to PPPoS to be decoded. This function is * thread-safe and can be called from a dedicated RX-thread or from a main-loop. * * @param pcb PPP descriptor index, returned by ppp_new() * @param data received data * @param len length of received data */ void pppos_input(ppp_pcb *pcb, u_char *s, int l) { ppp_pcb_rx *pcrx = &pcb->rx; struct pbuf *next_pbuf; u_char cur_char; u_char escaped; SYS_ARCH_DECL_PROTECT(lev); PPPDEBUG(LOG_DEBUG, ("pppos_input[%d]: got %d bytes\n", pcb->num, l)); while (l-- > 0) { cur_char = *s++; SYS_ARCH_PROTECT(lev); escaped = ESCAPE_P(pcrx->in_accm, cur_char); SYS_ARCH_UNPROTECT(lev); /* Handle special characters. */ if (escaped) { /* Check for escape sequences. */ /* XXX Note that this does not handle an escaped 0x5d character which * would appear as an escape character. Since this is an ASCII ']' * and there is no reason that I know of to escape it, I won't complicate * the code to handle this case. GLL */ if (cur_char == PPP_ESCAPE) { pcrx->in_escaped = 1; /* Check for the flag character. */ } else if (cur_char == PPP_FLAG) { /* If this is just an extra flag character, ignore it. */ if (pcrx->in_state <= PDADDRESS) { /* ignore it */; /* If we haven't received the packet header, drop what has come in. */ } else if (pcrx->in_state < PDDATA) { PPPDEBUG(LOG_WARNING, ("pppos_input[%d]: Dropping incomplete packet %d\n", pcb->num, pcrx->in_state)); LINK_STATS_INC(link.lenerr); ppp_drop(pcrx); /* If the fcs is invalid, drop the packet. */ } else if (pcrx->in_fcs != PPP_GOODFCS) { PPPDEBUG(LOG_INFO, ("pppos_input[%d]: Dropping bad fcs 0x%"X16_F" proto=0x%"X16_F"\n", pcb->num, pcrx->in_fcs, pcrx->in_protocol)); /* Note: If you get lots of these, check for UART frame errors or try different baud rate */ LINK_STATS_INC(link.chkerr); ppp_drop(pcrx); /* Otherwise it's a good packet so pass it on. */ } else { struct pbuf *inp; /* Trim off the checksum. */ if(pcrx->in_tail->len > 2) { pcrx->in_tail->len -= 2; pcrx->in_tail->tot_len = pcrx->in_tail->len; if (pcrx->in_tail != pcrx->in_head) { pbuf_cat(pcrx->in_head, pcrx->in_tail); } } else { pcrx->in_tail->tot_len = pcrx->in_tail->len; if (pcrx->in_tail != pcrx->in_head) { pbuf_cat(pcrx->in_head, pcrx->in_tail); } pbuf_realloc(pcrx->in_head, pcrx->in_head->tot_len - 2); } /* Dispatch the packet thereby consuming it. */ inp = pcrx->in_head; /* Packet consumed, release our references. */ pcrx->in_head = NULL; pcrx->in_tail = NULL; #if PPP_INPROC_MULTITHREADED if(tcpip_callback_with_block(pppos_input_callback, inp, 0) != ERR_OK) { PPPDEBUG(LOG_ERR, ("pppos_input[%d]: tcpip_callback() failed, dropping packet\n", pcb->num)); pbuf_free(inp); LINK_STATS_INC(link.drop); snmp_inc_ifindiscards(&pcb->netif); } #else /* PPP_INPROC_MULTITHREADED */ ppp_input(pcb, inp); #endif /* PPP_INPROC_MULTITHREADED */ } /* Prepare for a new packet. */ pcrx->in_fcs = PPP_INITFCS; pcrx->in_state = PDADDRESS; pcrx->in_escaped = 0; /* Other characters are usually control characters that may have * been inserted by the physical layer so here we just drop them. */ } else { PPPDEBUG(LOG_WARNING, ("pppos_input[%d]: Dropping ACCM char <%d>\n", pcb->num, cur_char)); } /* Process other characters. */ } else { /* Unencode escaped characters. */ if (pcrx->in_escaped) { pcrx->in_escaped = 0; cur_char ^= PPP_TRANS; } /* Process character relative to current state. */ switch(pcrx->in_state) { case PDIDLE: /* Idle state - waiting. */ /* Drop the character if it's not 0xff * we would have processed a flag character above. */ if (cur_char != PPP_ALLSTATIONS) { break; } /* no break */ /* Fall through */ case PDSTART: /* Process start flag. */ /* Prepare for a new packet. */ pcrx->in_fcs = PPP_INITFCS; /* no break */ /* Fall through */ case PDADDRESS: /* Process address field. */ if (cur_char == PPP_ALLSTATIONS) { pcrx->in_state = PDCONTROL; break; } /* no break */ /* Else assume compressed address and control fields so * fall through to get the protocol... */ case PDCONTROL: /* Process control field. */ /* If we don't get a valid control code, restart. */ if (cur_char == PPP_UI) { pcrx->in_state = PDPROTOCOL1; break; } /* no break */ #if 0 else { PPPDEBUG(LOG_WARNING, ("pppos_input[%d]: Invalid control <%d>\n", pcb->num, cur_char)); pcrx->in_state = PDSTART; } #endif case PDPROTOCOL1: /* Process protocol field 1. */ /* If the lower bit is set, this is the end of the protocol * field. */ if (cur_char & 1) { pcrx->in_protocol = cur_char; pcrx->in_state = PDDATA; } else { pcrx->in_protocol = (u_int)cur_char << 8; pcrx->in_state = PDPROTOCOL2; } break; case PDPROTOCOL2: /* Process protocol field 2. */ pcrx->in_protocol |= cur_char; pcrx->in_state = PDDATA; break; case PDDATA: /* Process data byte. */ /* Make space to receive processed data. */ if (pcrx->in_tail == NULL || pcrx->in_tail->len == PBUF_POOL_BUFSIZE) { if (pcrx->in_tail != NULL) { pcrx->in_tail->tot_len = pcrx->in_tail->len; if (pcrx->in_tail != pcrx->in_head) { pbuf_cat(pcrx->in_head, pcrx->in_tail); /* give up the in_tail reference now */ pcrx->in_tail = NULL; } } /* If we haven't started a packet, we need a packet header. */ #if IP_FORWARD || LWIP_IPV6_FORWARD /* If IP forwarding is enabled we are using a PBUF_LINK packet type so * the packet is being allocated with enough header space to be * forwarded (to Ethernet for example). */ next_pbuf = pbuf_alloc(PBUF_LINK, 0, PBUF_POOL); #else /* IP_FORWARD || LWIP_IPV6_FORWARD */ next_pbuf = pbuf_alloc(PBUF_RAW, 0, PBUF_POOL); #endif /* IP_FORWARD || LWIP_IPV6_FORWARD */ if (next_pbuf == NULL) { /* No free buffers. Drop the input packet and let the * higher layers deal with it. Continue processing * the received pbuf chain in case a new packet starts. */ PPPDEBUG(LOG_ERR, ("pppos_input[%d]: NO FREE MBUFS!\n", pcb->num)); LINK_STATS_INC(link.memerr); ppp_drop(pcrx); pcrx->in_state = PDSTART; /* Wait for flag sequence. */ break; } if (pcrx->in_head == NULL) { u8_t *payload; /* pbuf_header() used below is only trying to put PPP headers * before the current payload pointer if there is enough space * in the pbuf to do so. Therefore we don't care if it fails, * but if it fail we have to set len to the size used by PPP headers. */ #if PPP_INPROC_MULTITHREADED if (pbuf_header(next_pbuf, +sizeof(struct pppos_input_header) +sizeof(pcrx->in_protocol))) { next_pbuf->len += sizeof(struct pppos_input_header) + sizeof(pcrx->in_protocol); } payload = next_pbuf->payload; ((struct pppos_input_header*)payload)->pcb = pcb; payload += sizeof(struct pppos_input_header); #else /* PPP_INPROC_MULTITHREADED */ if (pbuf_header(next_pbuf, +sizeof(pcrx->in_protocol))) { next_pbuf->len += sizeof(pcrx->in_protocol); } payload = next_pbuf->payload; #endif /* PPP_INPROC_MULTITHREADED */ *(payload++) = pcrx->in_protocol >> 8; *(payload) = pcrx->in_protocol & 0xFF; pcrx->in_head = next_pbuf; } pcrx->in_tail = next_pbuf; } /* Load character into buffer. */ ((u_char*)pcrx->in_tail->payload)[pcrx->in_tail->len++] = cur_char; break; } /* update the frame check sequence number. */ pcrx->in_fcs = PPP_FCS(pcrx->in_fcs, cur_char); } } /* while (l-- > 0), all bytes processed */ magic_randomize(); } #if PPP_INPROC_MULTITHREADED /* PPPoS input callback using one input pointer */ static void pppos_input_callback(void *arg) { struct pbuf *pb = (struct pbuf*)arg; ppp_pcb *pcb; pcb = ((struct pppos_input_header*)pb->payload)->pcb; if(pbuf_header(pb, -(s16_t)sizeof(struct pppos_input_header))) { LWIP_ASSERT("pbuf_header failed\n", 0); goto drop; } /* Dispatch the packet thereby consuming it. */ ppp_input(pcb, pb); return; drop: LINK_STATS_INC(link.drop); snmp_inc_ifindiscards(&pcb->netif); pbuf_free(pb); } #endif /* PPP_INPROC_MULTITHREADED */ #endif /* PPPOS_SUPPORT */ /* merge a pbuf chain into one pbuf */ struct pbuf * ppp_singlebuf(struct pbuf *p) { struct pbuf *q, *b; u_char *pl; if(p->tot_len == p->len) { return p; } q = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM); if(!q) { PPPDEBUG(LOG_ERR, ("ppp_singlebuf: unable to alloc new buf (%d)\n", p->tot_len)); return p; /* live dangerously */ } for(b = p, pl = q->payload; b != NULL; b = b->next) { MEMCPY(pl, b->payload, b->len); pl += b->len; } pbuf_free(p); return q; } #if PPPOE_SUPPORT static void ppp_over_ethernet_link_status_cb(ppp_pcb *pcb, int state) { int pppoe_err_code = PPPERR_NONE; switch(state) { /* PPPoE link is established, starting PPP negotiation */ case PPPOE_CB_STATE_UP: PPPDEBUG(LOG_INFO, ("ppp_over_ethernet_link_status_cb: unit %d: UP, connecting\n", pcb->num)); ppp_start(pcb); return; /* PPPoE link normally down (i.e. asked to do so) */ case PPPOE_CB_STATE_DOWN: PPPDEBUG(LOG_INFO, ("ppp_over_ethernet_link_status_cb: unit %d: DOWN, disconnected\n", pcb->num)); pppoe_err_code = PPPERR_CONNECT; break; /* PPPoE link failed to setup (i.e. PADI/PADO timeout) */ case PPPOE_CB_STATE_FAILED: PPPDEBUG(LOG_INFO, ("ppp_over_ethernet_link_status_cb: unit %d: FAILED, aborting\n", pcb->num)); pppoe_err_code = PPPERR_OPEN; new_phase(pcb, PPP_PHASE_DEAD); break; } pcb->link_status_cb(pcb, pcb->err_code ? pcb->err_code : pppoe_err_code, pcb->ctx_cb); } static void ppp_over_ethernet_open(ppp_pcb *pcb) { lcp_options *wo = &pcb->lcp_wantoptions; lcp_options *ao = &pcb->lcp_allowoptions; ppp_clear(pcb); wo->mru = pcb->pppoe_sc->sc_ethif->mtu-PPPOE_HEADERLEN-2; /* two byte PPP protocol discriminator, then IP data */ wo->neg_asyncmap = 0; wo->neg_pcompression = 0; wo->neg_accompression = 0; ao->mru = pcb->pppoe_sc->sc_ethif->mtu-PPPOE_HEADERLEN-2; /* two byte PPP protocol discriminator, then IP data */ ao->neg_asyncmap = 0; ao->neg_pcompression = 0; ao->neg_accompression = 0; pppoe_connect(pcb->pppoe_sc); } #endif /* PPPOE_SUPPORT */ #if PPPOL2TP_SUPPORT static void ppp_over_l2tp_link_status_cb(ppp_pcb *pcb, int state) { int pppol2tp_err_code = PPPERR_NONE; switch(state) { /* PPPoL2TP link is established, starting PPP negotiation */ case PPPOL2TP_CB_STATE_UP: PPPDEBUG(LOG_INFO, ("ppp_over_l2tp_link_status_cb: unit %d: UP, connecting\n", pcb->num)); ppp_start(pcb); return; /* PPPoL2TP link normally down (i.e. asked to do so) */ case PPPOL2TP_CB_STATE_DOWN: PPPDEBUG(LOG_INFO, ("ppp_over_l2tp_link_status_cb: unit %d: DOWN, disconnected\n", pcb->num)); pppol2tp_err_code = PPPERR_CONNECT; break; /* PPPoL2TP link failed to setup (i.e. L2TP timeout) */ case PPPOL2TP_CB_STATE_FAILED: PPPDEBUG(LOG_INFO, ("ppp_over_l2tp_link_status_cb: unit %d: FAILED, aborting\n", pcb->num)); pppol2tp_err_code = PPPERR_OPEN; new_phase(pcb, PPP_PHASE_DEAD); break; } pcb->link_status_cb(pcb, pcb->err_code ? pcb->err_code : pppol2tp_err_code, pcb->ctx_cb); } static void ppp_over_l2tp_open(ppp_pcb *pcb) { lcp_options *wo = &pcb->lcp_wantoptions; lcp_options *ao = &pcb->lcp_allowoptions; ppp_clear(pcb); wo->mru = 1500; /* FIXME: MTU depends if we support IP fragmentation or not */ wo->neg_asyncmap = 0; wo->neg_pcompression = 0; wo->neg_accompression = 0; ao->mru = 1500; /* FIXME: MTU depends if we support IP fragmentation or not */ ao->neg_asyncmap = 0; ao->neg_pcompression = 0; ao->neg_accompression = 0; pppol2tp_connect(pcb->l2tp_pcb); } #endif /* PPPOL2TP_SUPPORT */ void ppp_link_down(ppp_pcb *pcb) { PPPDEBUG(LOG_DEBUG, ("ppp_link_down: unit %d\n", pcb->num)); } void ppp_link_terminated(ppp_pcb *pcb) { PPPDEBUG(LOG_DEBUG, ("ppp_link_terminated: unit %d\n", pcb->num)); #if PPPOE_SUPPORT if (pcb->pppoe_sc) { pppoe_disconnect(pcb->pppoe_sc); } else #endif /* PPPOE_SUPPORT */ #if PPPOL2TP_SUPPORT if (pcb->l2tp_pcb) { pppol2tp_disconnect(pcb->l2tp_pcb); } else #endif /* PPPOL2TP_SUPPORT */ { #if PPPOS_SUPPORT /* We cannot call ppp_free_current_input_packet() here because * rx thread might still call pppos_input() */ PPPDEBUG(LOG_DEBUG, ("ppp_link_terminated: unit %d: link_status_cb=%p err_code=%d\n", pcb->num, pcb->link_status_cb, pcb->err_code)); pcb->link_status_cb(pcb, pcb->err_code ? pcb->err_code : PPPERR_PROTOCOL, pcb->ctx_cb); #endif /* PPPOS_SUPPORT */ } PPPDEBUG(LOG_DEBUG, ("ppp_link_terminated: finished.\n")); } #if LWIP_NETIF_STATUS_CALLBACK /** Set the status callback of a PPP's netif * * @param pcb The PPP descriptor returned by ppp_new() * @param status_callback pointer to the status callback function * * @see netif_set_status_callback */ void ppp_set_netif_statuscallback(ppp_pcb *pcb, netif_status_callback_fn status_callback) { netif_set_status_callback(&pcb->netif, status_callback); } #endif /* LWIP_NETIF_STATUS_CALLBACK */ #if LWIP_NETIF_LINK_CALLBACK /** Set the link callback of a PPP's netif * * @param pcb The PPP descriptor returned by ppp_new() * @param link_callback pointer to the link callback function * * @see netif_set_link_callback */ void ppp_set_netif_linkcallback(ppp_pcb *pcb, netif_status_callback_fn link_callback) { netif_set_link_callback(&pcb->netif, link_callback); } #endif /* LWIP_NETIF_LINK_CALLBACK */ /************************************************************************ * Functions called by various PPP subsystems to configure * the PPP interface or change the PPP phase. */ /* * new_phase - signal the start of a new phase of pppd's operation. */ void new_phase(ppp_pcb *pcb, int p) { pcb->phase = p; PPPDEBUG(LOG_DEBUG, ("ppp phase changed: unit %d: phase=%d\n", pcb->num, pcb->phase)); #if PPP_NOTIFY_PHASE if(NULL != pcb->notify_phase_cb) { pcb->notify_phase_cb(pcb, p, pcb->ctx_cb); } #endif /* PPP_NOTIFY_PHASE */ } /* * ppp_send_config - configure the transmit-side characteristics of * the ppp interface. */ int ppp_send_config(ppp_pcb *pcb, int mtu, u32_t accm, int pcomp, int accomp) { #if PPPOS_SUPPORT int i; #endif /* PPPOS_SUPPORT */ /* pcb->mtu = mtu; -- set correctly with netif_set_mtu */ pcb->pcomp = pcomp; pcb->accomp = accomp; #if PPPOS_SUPPORT /* Load the ACCM bits for the 32 control codes. */ for (i = 0; i < 32/8; i++) { pcb->out_accm[i] = (u_char)((accm >> (8 * i)) & 0xFF); } #else LWIP_UNUSED_ARG(accm); #endif /* PPPOS_SUPPORT */ #if PPPOS_SUPPORT PPPDEBUG(LOG_INFO, ("ppp_send_config[%d]: out_accm=%X %X %X %X\n", pcb->num, pcb->out_accm[0], pcb->out_accm[1], pcb->out_accm[2], pcb->out_accm[3])); #else PPPDEBUG(LOG_INFO, ("ppp_send_config[%d]\n", pcb->num) ); #endif /* PPPOS_SUPPORT */ return 0; } /* * ppp_recv_config - configure the receive-side characteristics of * the ppp interface. */ int ppp_recv_config(ppp_pcb *pcb, int mru, u32_t accm, int pcomp, int accomp) { #if PPPOS_SUPPORT int i; SYS_ARCH_DECL_PROTECT(lev); #endif /* PPPOS_SUPPORT */ LWIP_UNUSED_ARG(accomp); LWIP_UNUSED_ARG(pcomp); LWIP_UNUSED_ARG(mru); /* Load the ACCM bits for the 32 control codes. */ #if PPPOS_SUPPORT SYS_ARCH_PROTECT(lev); for (i = 0; i < 32 / 8; i++) { /* @todo: does this work? ext_accm has been modified from pppd! */ pcb->rx.in_accm[i] = (u_char)(accm >> (i * 8)); } SYS_ARCH_UNPROTECT(lev); #else LWIP_UNUSED_ARG(accm); #endif /* PPPOS_SUPPORT */ #if PPPOS_SUPPORT PPPDEBUG(LOG_INFO, ("ppp_recv_config[%d]: in_accm=%X %X %X %X\n", pcb->num, pcb->rx.in_accm[0], pcb->rx.in_accm[1], pcb->rx.in_accm[2], pcb->rx.in_accm[3])); #else PPPDEBUG(LOG_INFO, ("ppp_recv_config[%d]\n", pcb->num) ); #endif /* PPPOS_SUPPORT */ return 0; } /* * sifaddr - Config the interface IP addresses and netmask. */ int sifaddr(ppp_pcb *pcb, u32_t our_adr, u32_t his_adr, u32_t net_mask) { SMEMCPY(&pcb->addrs.our_ipaddr, &our_adr, sizeof(our_adr)); SMEMCPY(&pcb->addrs.his_ipaddr, &his_adr, sizeof(his_adr)); SMEMCPY(&pcb->addrs.netmask, &net_mask, sizeof(net_mask)); return 1; } /******************************************************************** * * cifaddr - Clear the interface IP addresses, and delete routes * through the interface if possible. */ int cifaddr(ppp_pcb *pcb, u32_t our_adr, u32_t his_adr) { LWIP_UNUSED_ARG(our_adr); LWIP_UNUSED_ARG(his_adr); IP4_ADDR(&pcb->addrs.our_ipaddr, 0,0,0,0); IP4_ADDR(&pcb->addrs.his_ipaddr, 0,0,0,0); IP4_ADDR(&pcb->addrs.netmask, 255,255,255,255); return 1; } #if PPP_IPV6_SUPPORT #define IN6_LLADDR_FROM_EUI64(ip6, eui64) do { \ memset(&ip6.addr, 0, sizeof(ip6_addr_t)); \ ip6.addr[0] = PP_HTONL(0xfe800000); \ eui64_copy(eui64, ip6.addr[2]); \ } while (0) /******************************************************************** * * sif6addr - Config the interface with an IPv6 link-local address */ int sif6addr(ppp_pcb *pcb, eui64_t our_eui64, eui64_t his_eui64) { IN6_LLADDR_FROM_EUI64(pcb->addrs.our6_ipaddr, our_eui64); IN6_LLADDR_FROM_EUI64(pcb->addrs.his6_ipaddr, his_eui64); return 1; } /******************************************************************** * * cif6addr - Remove IPv6 address from interface */ int cif6addr(ppp_pcb *pcb, eui64_t our_eui64, eui64_t his_eui64) { LWIP_UNUSED_ARG(our_eui64); LWIP_UNUSED_ARG(his_eui64); IP6_ADDR(&pcb->addrs.our6_ipaddr, 0, 0,0,0,0); IP6_ADDR(&pcb->addrs.his6_ipaddr, 0, 0,0,0,0); return 1; } #endif /* PPP_IPV6_SUPPORT */ /* * sdns - Config the DNS servers */ int sdns(ppp_pcb *pcb, u32_t ns1, u32_t ns2) { SMEMCPY(&pcb->addrs.dns1, &ns1, sizeof(ns1)); SMEMCPY(&pcb->addrs.dns2, &ns2, sizeof(ns2)); return 1; } /******************************************************************** * * cdns - Clear the DNS servers */ int cdns(ppp_pcb *pcb, u32_t ns1, u32_t ns2) { LWIP_UNUSED_ARG(ns1); LWIP_UNUSED_ARG(ns2); IP4_ADDR(&pcb->addrs.dns1, 0,0,0,0); IP4_ADDR(&pcb->addrs.dns2, 0,0,0,0); return 1; } /* * sifup - Config the interface up and enable IP packets to pass. */ int sifup(ppp_pcb *pcb) { netif_set_addr(&pcb->netif, &pcb->addrs.our_ipaddr, &pcb->addrs.netmask, &pcb->addrs.his_ipaddr); #if PPP_IPV6_SUPPORT ip6_addr_copy(pcb->netif.ip6_addr[0], pcb->addrs.our6_ipaddr); netif_ip6_addr_set_state(&pcb->netif, 0, IP6_ADDR_PREFERRED); #endif /* PPP_IPV6_SUPPORT */ netif_set_up(&pcb->netif); pcb->if_up = 1; pcb->err_code = PPPERR_NONE; PPPDEBUG(LOG_DEBUG, ("sifup: unit %d: err_code=%d\n", pcb->num, pcb->err_code)); pcb->link_status_cb(pcb, pcb->err_code, pcb->ctx_cb); return 1; } /******************************************************************** * * sifdown - Disable the indicated protocol and config the interface * down if there are no remaining protocols. */ int sifdown(ppp_pcb *pcb) { if(!pcb->if_up) return 1; pcb->if_up = 0; /* make sure the netif status callback is called */ netif_set_down(&pcb->netif); PPPDEBUG(LOG_DEBUG, ("sifdown: unit %d: err_code=%d\n", pcb->num, pcb->err_code)); return 1; } /* * sifnpmode - Set the mode for handling packets for a given NP. */ int sifnpmode(ppp_pcb *pcb, int proto, enum NPmode mode) { LWIP_UNUSED_ARG(pcb); LWIP_UNUSED_ARG(proto); LWIP_UNUSED_ARG(mode); return 0; } /* * netif_set_mtu - set the MTU on the PPP network interface. */ void netif_set_mtu(ppp_pcb *pcb, int mtu) { pcb->netif.mtu = mtu; } /* * netif_get_mtu - get PPP interface MTU */ int netif_get_mtu(ppp_pcb *pcb) { return pcb->netif.mtu; } /******************************************************************** * * sifproxyarp - Make a proxy ARP entry for the peer. */ int sifproxyarp(ppp_pcb *pcb, u32_t his_adr) { LWIP_UNUSED_ARG(pcb); LWIP_UNUSED_ARG(his_adr); /* FIXME: do we really need that in IPCP ? */ return 0; } /******************************************************************** * * cifproxyarp - Delete the proxy ARP entry for the peer. */ int cifproxyarp(ppp_pcb *pcb, u32_t his_adr) { LWIP_UNUSED_ARG(pcb); LWIP_UNUSED_ARG(his_adr); /* FIXME: do we really need that in IPCP ? */ return 0; } /******************************************************************** * * sifvjcomp - config tcp header compression */ int sifvjcomp(ppp_pcb *pcb, int vjcomp, int cidcomp, int maxcid) { #if PPPOS_SUPPORT && VJ_SUPPORT pcb->vj_enabled = vjcomp; pcb->vj_comp.compressSlot = cidcomp; pcb->vj_comp.maxSlotIndex = maxcid; PPPDEBUG(LOG_INFO, ("sifvjcomp: VJ compress enable=%d slot=%d max slot=%d\n", vjcomp, cidcomp, maxcid)); #else /* PPPOS_SUPPORT && VJ_SUPPORT */ LWIP_UNUSED_ARG(pcb); LWIP_UNUSED_ARG(vjcomp); LWIP_UNUSED_ARG(cidcomp); LWIP_UNUSED_ARG(maxcid); #endif /* PPPOS_SUPPORT && VJ_SUPPORT */ return 0; } #if PPP_IDLETIMELIMIT /******************************************************************** * * get_idle_time - return how long the link has been idle. */ int get_idle_time(ppp_pcb *pcb, struct ppp_idle *ip) { /* FIXME: add idle time support and make it optional */ LWIP_UNUSED_ARG(pcb); LWIP_UNUSED_ARG(ip); return 1; } #endif /* PPP_IDLETIMELIMIT */ /******************************************************************** * * get_loop_output - get outgoing packets from the ppp device, * and detect when we want to bring the real link up. * Return value is 1 if we need to bring up the link, 0 otherwise. */ int get_loop_output(void) { /* FIXME: necessary for "demand", do we really need to support on-demand ? */ return 0; } /******************************************************************** * * Return user specified netmask, modified by any mask we might determine * for address `addr' (in network byte order). * Here we scan through the system's list of interfaces, looking for * any non-point-to-point interfaces which might appear to be on the same * network as `addr'. If we find any, we OR in their netmask to the * user-specified netmask. */ u32_t get_mask(u32_t addr) { #if 0 u32_t mask, nmask; addr = htonl(addr); if (IP_CLASSA(addr)) { /* determine network mask for address class */ nmask = IP_CLASSA_NET; } else if (IP_CLASSB(addr)) { nmask = IP_CLASSB_NET; } else { nmask = IP_CLASSC_NET; } /* class D nets are disallowed by bad_ip_adrs */ mask = PP_HTONL(0xffffff00UL) | htonl(nmask); /* XXX * Scan through the system's network interfaces. * Get each netmask and OR them into our mask. */ /* return mask; */ return mask; #endif LWIP_UNUSED_ARG(addr); return 0xFFFFFFFF; } #if PPP_PROTOCOLNAME /* List of protocol names, to make our messages a little more informative. */ struct protocol_list { u_short proto; const char *name; } protocol_list[] = { { 0x21, "IP" }, { 0x23, "OSI Network Layer" }, { 0x25, "Xerox NS IDP" }, { 0x27, "DECnet Phase IV" }, { 0x29, "Appletalk" }, { 0x2b, "Novell IPX" }, { 0x2d, "VJ compressed TCP/IP" }, { 0x2f, "VJ uncompressed TCP/IP" }, { 0x31, "Bridging PDU" }, { 0x33, "Stream Protocol ST-II" }, { 0x35, "Banyan Vines" }, { 0x39, "AppleTalk EDDP" }, { 0x3b, "AppleTalk SmartBuffered" }, { 0x3d, "Multi-Link" }, { 0x3f, "NETBIOS Framing" }, { 0x41, "Cisco Systems" }, { 0x43, "Ascom Timeplex" }, { 0x45, "Fujitsu Link Backup and Load Balancing (LBLB)" }, { 0x47, "DCA Remote Lan" }, { 0x49, "Serial Data Transport Protocol (PPP-SDTP)" }, { 0x4b, "SNA over 802.2" }, { 0x4d, "SNA" }, { 0x4f, "IP6 Header Compression" }, { 0x51, "KNX Bridging Data" }, { 0x53, "Encryption" }, { 0x55, "Individual Link Encryption" }, { 0x57, "IPv6" }, { 0x59, "PPP Muxing" }, { 0x5b, "Vendor-Specific Network Protocol" }, { 0x61, "RTP IPHC Full Header" }, { 0x63, "RTP IPHC Compressed TCP" }, { 0x65, "RTP IPHC Compressed non-TCP" }, { 0x67, "RTP IPHC Compressed UDP 8" }, { 0x69, "RTP IPHC Compressed RTP 8" }, { 0x6f, "Stampede Bridging" }, { 0x73, "MP+" }, { 0xc1, "NTCITS IPI" }, { 0xfb, "single-link compression" }, { 0xfd, "Compressed Datagram" }, { 0x0201, "802.1d Hello Packets" }, { 0x0203, "IBM Source Routing BPDU" }, { 0x0205, "DEC LANBridge100 Spanning Tree" }, { 0x0207, "Cisco Discovery Protocol" }, { 0x0209, "Netcs Twin Routing" }, { 0x020b, "STP - Scheduled Transfer Protocol" }, { 0x020d, "EDP - Extreme Discovery Protocol" }, { 0x0211, "Optical Supervisory Channel Protocol" }, { 0x0213, "Optical Supervisory Channel Protocol" }, { 0x0231, "Luxcom" }, { 0x0233, "Sigma Network Systems" }, { 0x0235, "Apple Client Server Protocol" }, { 0x0281, "MPLS Unicast" }, { 0x0283, "MPLS Multicast" }, { 0x0285, "IEEE p1284.4 standard - data packets" }, { 0x0287, "ETSI TETRA Network Protocol Type 1" }, { 0x0289, "Multichannel Flow Treatment Protocol" }, { 0x2063, "RTP IPHC Compressed TCP No Delta" }, { 0x2065, "RTP IPHC Context State" }, { 0x2067, "RTP IPHC Compressed UDP 16" }, { 0x2069, "RTP IPHC Compressed RTP 16" }, { 0x4001, "Cray Communications Control Protocol" }, { 0x4003, "CDPD Mobile Network Registration Protocol" }, { 0x4005, "Expand accelerator protocol" }, { 0x4007, "ODSICP NCP" }, { 0x4009, "DOCSIS DLL" }, { 0x400B, "Cetacean Network Detection Protocol" }, { 0x4021, "Stacker LZS" }, { 0x4023, "RefTek Protocol" }, { 0x4025, "Fibre Channel" }, { 0x4027, "EMIT Protocols" }, { 0x405b, "Vendor-Specific Protocol (VSP)" }, { 0x8021, "Internet Protocol Control Protocol" }, { 0x8023, "OSI Network Layer Control Protocol" }, { 0x8025, "Xerox NS IDP Control Protocol" }, { 0x8027, "DECnet Phase IV Control Protocol" }, { 0x8029, "Appletalk Control Protocol" }, { 0x802b, "Novell IPX Control Protocol" }, { 0x8031, "Bridging NCP" }, { 0x8033, "Stream Protocol Control Protocol" }, { 0x8035, "Banyan Vines Control Protocol" }, { 0x803d, "Multi-Link Control Protocol" }, { 0x803f, "NETBIOS Framing Control Protocol" }, { 0x8041, "Cisco Systems Control Protocol" }, { 0x8043, "Ascom Timeplex" }, { 0x8045, "Fujitsu LBLB Control Protocol" }, { 0x8047, "DCA Remote Lan Network Control Protocol (RLNCP)" }, { 0x8049, "Serial Data Control Protocol (PPP-SDCP)" }, { 0x804b, "SNA over 802.2 Control Protocol" }, { 0x804d, "SNA Control Protocol" }, { 0x804f, "IP6 Header Compression Control Protocol" }, { 0x8051, "KNX Bridging Control Protocol" }, { 0x8053, "Encryption Control Protocol" }, { 0x8055, "Individual Link Encryption Control Protocol" }, { 0x8057, "IPv6 Control Protocol" }, { 0x8059, "PPP Muxing Control Protocol" }, { 0x805b, "Vendor-Specific Network Control Protocol (VSNCP)" }, { 0x806f, "Stampede Bridging Control Protocol" }, { 0x8073, "MP+ Control Protocol" }, { 0x80c1, "NTCITS IPI Control Protocol" }, { 0x80fb, "Single Link Compression Control Protocol" }, { 0x80fd, "Compression Control Protocol" }, { 0x8207, "Cisco Discovery Protocol Control" }, { 0x8209, "Netcs Twin Routing" }, { 0x820b, "STP - Control Protocol" }, { 0x820d, "EDPCP - Extreme Discovery Protocol Ctrl Prtcl" }, { 0x8235, "Apple Client Server Protocol Control" }, { 0x8281, "MPLSCP" }, { 0x8285, "IEEE p1284.4 standard - Protocol Control" }, { 0x8287, "ETSI TETRA TNP1 Control Protocol" }, { 0x8289, "Multichannel Flow Treatment Protocol" }, { 0xc021, "Link Control Protocol" }, { 0xc023, "Password Authentication Protocol" }, { 0xc025, "Link Quality Report" }, { 0xc027, "Shiva Password Authentication Protocol" }, { 0xc029, "CallBack Control Protocol (CBCP)" }, { 0xc02b, "BACP Bandwidth Allocation Control Protocol" }, { 0xc02d, "BAP" }, { 0xc05b, "Vendor-Specific Authentication Protocol (VSAP)" }, { 0xc081, "Container Control Protocol" }, { 0xc223, "Challenge Handshake Authentication Protocol" }, { 0xc225, "RSA Authentication Protocol" }, { 0xc227, "Extensible Authentication Protocol" }, { 0xc229, "Mitsubishi Security Info Exch Ptcl (SIEP)" }, { 0xc26f, "Stampede Bridging Authorization Protocol" }, { 0xc281, "Proprietary Authentication Protocol" }, { 0xc283, "Proprietary Authentication Protocol" }, { 0xc481, "Proprietary Node ID Authentication Protocol" }, { 0, NULL }, }; /* * protocol_name - find a name for a PPP protocol. */ const char * protocol_name(int proto) { struct protocol_list *lp; for (lp = protocol_list; lp->proto != 0; ++lp) if (proto == lp->proto) return lp->name; return NULL; } #endif /* PPP_PROTOCOLNAME */ #if PPP_STATS_SUPPORT /* ---- Note on PPP Stats support ---- * * The one willing link stats support should add the get_ppp_stats() * to fetch statistics from lwIP. */ /* * reset_link_stats - "reset" stats when link goes up. */ void reset_link_stats(int u) { if (!get_ppp_stats(u, &old_link_stats)) return; gettimeofday(&start_time, NULL); } /* * update_link_stats - get stats at link termination. */ void update_link_stats(int u) { struct timeval now; char numbuf[32]; if (!get_ppp_stats(u, &link_stats) || gettimeofday(&now, NULL) < 0) return; link_connect_time = now.tv_sec - start_time.tv_sec; link_stats_valid = 1; link_stats.bytes_in -= old_link_stats.bytes_in; link_stats.bytes_out -= old_link_stats.bytes_out; link_stats.pkts_in -= old_link_stats.pkts_in; link_stats.pkts_out -= old_link_stats.pkts_out; } void print_link_stats() { /* * Print connect time and statistics. */ if (link_stats_valid) { int t = (link_connect_time + 5) / 6; /* 1/10ths of minutes */ info("Connect time %d.%d minutes.", t/10, t%10); info("Sent %u bytes, received %u bytes.", link_stats.bytes_out, link_stats.bytes_in); link_stats_valid = 0; } } #endif /* PPP_STATS_SUPPORT */ #endif /* PPP_SUPPORT */ ocproxy-1.60/lwip/src/netif/ppp/pppcrypt.c000066400000000000000000000043771303453231400206470ustar00rootroot00000000000000/* * pppcrypt.c - PPP/DES linkage for MS-CHAP and EAP SRP-SHA1 * * Extracted from chap_ms.c by James Carlson. * * Copyright (c) 1995 Eric Rosenquist. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The name(s) of the authors of this software must not be used to * endorse or promote products derived from this software without * prior written permission. * * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "lwip/opt.h" #if PPP_SUPPORT && MSCHAP_SUPPORT /* don't build if not necessary */ #include "netif/ppp/ppp_impl.h" #include "netif/ppp/pppcrypt.h" static u_char pppcrypt_get_7bits(u_char *input, int startBit) { unsigned int word; word = (unsigned)input[startBit / 8] << 8; word |= (unsigned)input[startBit / 8 + 1]; word >>= 15 - (startBit % 8 + 7); return word & 0xFE; } /* IN 56 bit DES key missing parity bits * OUT 64 bit DES key with parity bits added */ void pppcrypt_56_to_64_bit_key(u_char *key, u_char * des_key) { des_key[0] = pppcrypt_get_7bits(key, 0); des_key[1] = pppcrypt_get_7bits(key, 7); des_key[2] = pppcrypt_get_7bits(key, 14); des_key[3] = pppcrypt_get_7bits(key, 21); des_key[4] = pppcrypt_get_7bits(key, 28); des_key[5] = pppcrypt_get_7bits(key, 35); des_key[6] = pppcrypt_get_7bits(key, 42); des_key[7] = pppcrypt_get_7bits(key, 49); } #endif /* PPP_SUPPORT && MSCHAP_SUPPORT */ ocproxy-1.60/lwip/src/netif/ppp/pppoe.c000066400000000000000000001021201303453231400200720ustar00rootroot00000000000000/***************************************************************************** * pppoe.c - PPP Over Ethernet implementation for lwIP. * * Copyright (c) 2006 by Marc Boucher, Services Informatiques (MBSI) inc. * * The authors hereby grant permission to use, copy, modify, distribute, * and license this software and its documentation for any purpose, provided * that existing copyright notices are retained in all copies and that this * notice and the following disclaimer are included verbatim in any * distributions. No written agreement, license, or royalty fee is required * for any of the authorized uses. * * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ****************************************************************************** * REVISION HISTORY * * 06-01-01 Marc Boucher * Ported to lwIP. *****************************************************************************/ /* based on NetBSD: if_pppoe.c,v 1.64 2006/01/31 23:50:15 martin Exp */ /*- * Copyright (c) 2002 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Martin Husemann . * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the NetBSD * Foundation, Inc. and its contributors. * 4. Neither the name of The NetBSD Foundation nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include "lwip/opt.h" #if PPP_SUPPORT && PPPOE_SUPPORT /* don't build if not configured for use in lwipopts.h */ #if 0 /* UNUSED */ #include #include #endif /* UNUSED */ #include "lwip/timers.h" #include "lwip/memp.h" #include "lwip/stats.h" #include "netif/ppp/ppp_impl.h" #include "netif/ppp/pppoe.h" /* Add a 16 bit unsigned value to a buffer pointed to by PTR */ #define PPPOE_ADD_16(PTR, VAL) \ *(PTR)++ = (u8_t)((VAL) / 256); \ *(PTR)++ = (u8_t)((VAL) % 256) /* Add a complete PPPoE header to the buffer pointed to by PTR */ #define PPPOE_ADD_HEADER(PTR, CODE, SESS, LEN) \ *(PTR)++ = PPPOE_VERTYPE; \ *(PTR)++ = (CODE); \ PPPOE_ADD_16(PTR, SESS); \ PPPOE_ADD_16(PTR, LEN) #define PPPOE_DISC_TIMEOUT (5*1000) /* base for quick timeout calculation */ #define PPPOE_SLOW_RETRY (60*1000) /* persistent retry interval */ #define PPPOE_DISC_MAXPADI 4 /* retry PADI four times (quickly) */ #define PPPOE_DISC_MAXPADR 2 /* retry PADR twice */ #ifdef PPPOE_SERVER #error "PPPOE_SERVER is not yet supported under lwIP!" /* from if_spppsubr.c */ #define IFF_PASSIVE IFF_LINK0 /* wait passively for connection */ #endif /* FIXME: we should probably remove that, this is only used for debug purposes */ #ifndef PPPOE_ERRORSTRING_LEN #define PPPOE_ERRORSTRING_LEN 64 #endif static char pppoe_error_tmp[PPPOE_ERRORSTRING_LEN]; /* management routines */ static void pppoe_abort_connect(struct pppoe_softc *); static void pppoe_clear_softc(struct pppoe_softc *, const char *); /* internal timeout handling */ static void pppoe_timeout(void *); /* sending actual protocol controll packets */ static err_t pppoe_send_padi(struct pppoe_softc *); static err_t pppoe_send_padr(struct pppoe_softc *); #ifdef PPPOE_SERVER static err_t pppoe_send_pado(struct pppoe_softc *); static err_t pppoe_send_pads(struct pppoe_softc *); #endif static err_t pppoe_send_padt(struct netif *, u_int, const u8_t *); /* internal helper functions */ static struct pppoe_softc* pppoe_find_softc_by_session(u_int session, struct netif *rcvif); static struct pppoe_softc* pppoe_find_softc_by_hunique(u8_t *token, size_t len, struct netif *rcvif); /** linked list of created pppoe interfaces */ static struct pppoe_softc *pppoe_softc_list; err_t pppoe_create(struct netif *ethif, ppp_pcb *pcb, void (*link_status_cb)(ppp_pcb *pcb, int up), struct pppoe_softc **scptr) { struct pppoe_softc *sc; sc = (struct pppoe_softc *)memp_malloc(MEMP_PPPOE_IF); if (sc == NULL) { *scptr = NULL; return ERR_MEM; } memset(sc, 0, sizeof(struct pppoe_softc)); /* changed to real address later */ MEMCPY(&sc->sc_dest, ethbroadcast.addr, sizeof(sc->sc_dest)); sc->pcb = pcb; sc->sc_link_status_cb = link_status_cb; sc->sc_ethif = ethif; /* put the new interface at the head of the list */ sc->next = pppoe_softc_list; pppoe_softc_list = sc; *scptr = sc; return ERR_OK; } err_t pppoe_destroy(struct pppoe_softc *sc) { struct pppoe_softc *cur, *prev = NULL; /* find previous linked list entry */ for (cur = pppoe_softc_list; cur != NULL; prev = cur, cur = cur->next) { if (sc == cur) { break; } } if (cur != sc) { return ERR_IF; } sys_untimeout(pppoe_timeout, sc); if (prev == NULL) { /* remove sc from the head of the list */ pppoe_softc_list = sc->next; } else { /* remove sc from the list */ prev->next = sc->next; } #ifdef PPPOE_TODO if (sc->sc_concentrator_name) { mem_free(sc->sc_concentrator_name); } if (sc->sc_service_name) { mem_free(sc->sc_service_name); } #endif /* PPPOE_TODO */ memp_free(MEMP_PPPOE_IF, sc); return ERR_OK; } /* * Find the interface handling the specified session. * Note: O(number of sessions open), this is a client-side only, mean * and lean implementation, so number of open sessions typically should * be 1. */ static struct pppoe_softc* pppoe_find_softc_by_session(u_int session, struct netif *rcvif) { struct pppoe_softc *sc; if (session == 0) { return NULL; } for (sc = pppoe_softc_list; sc != NULL; sc = sc->next) { if (sc->sc_state == PPPOE_STATE_SESSION && sc->sc_session == session && sc->sc_ethif == rcvif) { return sc; } } return NULL; } /* Check host unique token passed and return appropriate softc pointer, * or NULL if token is bogus. */ static struct pppoe_softc* pppoe_find_softc_by_hunique(u8_t *token, size_t len, struct netif *rcvif) { struct pppoe_softc *sc, *t; if (pppoe_softc_list == NULL) { return NULL; } if (len != sizeof sc) { return NULL; } MEMCPY(&t, token, len); for (sc = pppoe_softc_list; sc != NULL; sc = sc->next) { if (sc == t) { break; } } if (sc == NULL) { PPPDEBUG(LOG_DEBUG, ("pppoe: alien host unique tag, no session found\n")); return NULL; } /* should be safe to access *sc now */ if (sc->sc_state < PPPOE_STATE_PADI_SENT || sc->sc_state >= PPPOE_STATE_SESSION) { PPPDEBUG(LOG_DEBUG, ("%c%c%"U16_F": host unique tag found, but it belongs to a connection in state %d\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, sc->sc_state)); return NULL; } if (sc->sc_ethif != rcvif) { PPPDEBUG(LOG_DEBUG, ("%c%c%"U16_F": wrong interface, not accepting host unique\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num)); return NULL; } return sc; } static void pppoe_linkstatus_up(struct pppoe_softc *sc) { sc->sc_link_status_cb(sc->pcb, PPPOE_CB_STATE_UP); } /* analyze and handle a single received packet while not in session state */ void pppoe_disc_input(struct netif *netif, struct pbuf *pb) { u16_t tag, len; u16_t session, plen; struct pppoe_softc *sc; const char *err_msg; char devname[6]; u8_t *ac_cookie; u16_t ac_cookie_len; #ifdef PPPOE_SERVER u8_t *hunique; size_t hunique_len; #endif struct pppoehdr *ph; struct pppoetag pt; int off, err; struct eth_hdr *ethhdr; /* don't do anything if there is not a single PPPoE instance */ if (pppoe_softc_list == NULL) { pbuf_free(pb); return; } pb = ppp_singlebuf(pb); strcpy(devname, "pppoe"); /* as long as we don't know which instance */ err_msg = NULL; if (pb->len < sizeof(*ethhdr)) { goto done; } ethhdr = (struct eth_hdr *)pb->payload; off = sizeof(*ethhdr); ac_cookie = NULL; ac_cookie_len = 0; #ifdef PPPOE_SERVER hunique = NULL; hunique_len = 0; #endif session = 0; if (pb->len - off < PPPOE_HEADERLEN) { PPPDEBUG(LOG_DEBUG, ("pppoe: packet too short: %d\n", pb->len)); goto done; } ph = (struct pppoehdr *) (ethhdr + 1); if (ph->vertype != PPPOE_VERTYPE) { PPPDEBUG(LOG_DEBUG, ("pppoe: unknown version/type packet: 0x%x\n", ph->vertype)); goto done; } session = ntohs(ph->session); plen = ntohs(ph->plen); off += sizeof(*ph); if (plen + off > pb->len) { PPPDEBUG(LOG_DEBUG, ("pppoe: packet content does not fit: data available = %d, packet size = %u\n", pb->len - off, plen)); goto done; } if(pb->tot_len == pb->len) { pb->tot_len = pb->len = (u16_t)off + plen; /* ignore trailing garbage */ } tag = 0; len = 0; sc = NULL; while (off + sizeof(pt) <= pb->len) { MEMCPY(&pt, (u8_t*)pb->payload + off, sizeof(pt)); tag = ntohs(pt.tag); len = ntohs(pt.len); if (off + sizeof(pt) + len > pb->len) { PPPDEBUG(LOG_DEBUG, ("pppoe: tag 0x%x len 0x%x is too long\n", tag, len)); goto done; } switch (tag) { case PPPOE_TAG_EOL: goto breakbreak; case PPPOE_TAG_SNAME: break; /* ignored */ case PPPOE_TAG_ACNAME: break; /* ignored */ case PPPOE_TAG_HUNIQUE: if (sc != NULL) { break; } #ifdef PPPOE_SERVER hunique = (u8_t*)pb->payload + off + sizeof(pt); hunique_len = len; #endif sc = pppoe_find_softc_by_hunique((u8_t*)pb->payload + off + sizeof(pt), len, netif); if (sc != NULL) { devname[0] = sc->sc_ethif->name[0]; devname[1] = sc->sc_ethif->name[1]; devname[2] = sc->sc_ethif->num; devname[3] = '\0'; } break; case PPPOE_TAG_ACCOOKIE: if (ac_cookie == NULL) { ac_cookie = (u8_t*)pb->payload + off + sizeof(pt); ac_cookie_len = len; } break; case PPPOE_TAG_SNAME_ERR: err_msg = "SERVICE NAME ERROR"; break; case PPPOE_TAG_ACSYS_ERR: err_msg = "AC SYSTEM ERROR"; break; case PPPOE_TAG_GENERIC_ERR: err_msg = "GENERIC ERROR"; break; } if (NULL != err_msg) { if (len) { u16_t error_len = LWIP_MIN(len, sizeof(pppoe_error_tmp)-1); strncpy(pppoe_error_tmp, (char*)pb->payload + off + sizeof(pt), error_len); pppoe_error_tmp[error_len] = '\0'; PPPDEBUG(LOG_DEBUG, ("%s: %s: %s\n", devname, err_msg, pppoe_error_tmp)); } else { PPPDEBUG(LOG_DEBUG, ("%s: %s\n", devname, err_msg)); } } off += sizeof(pt) + len; } breakbreak:; switch (ph->code) { case PPPOE_CODE_PADI: #ifdef PPPOE_SERVER /* * got service name, concentrator name, and/or host unique. * ignore if we have no interfaces with IFF_PASSIVE|IFF_UP. */ if (LIST_EMPTY(&pppoe_softc_list)) { goto done; } LIST_FOREACH(sc, &pppoe_softc_list, sc_list) { if (!(sc->sc_sppp.pp_if.if_flags & IFF_UP)) { continue; } if (!(sc->sc_sppp.pp_if.if_flags & IFF_PASSIVE)) { continue; } if (sc->sc_state == PPPOE_STATE_INITIAL) { break; } } if (sc == NULL) { /* PPPDEBUG(LOG_DEBUG, ("pppoe: free passive interface is not found\n")); */ goto done; } if (hunique) { if (sc->sc_hunique) { mem_free(sc->sc_hunique); } sc->sc_hunique = mem_malloc(hunique_len); if (sc->sc_hunique == NULL) { goto done; } sc->sc_hunique_len = hunique_len; MEMCPY(sc->sc_hunique, hunique, hunique_len); } MEMCPY(&sc->sc_dest, eh->ether_shost, sizeof sc->sc_dest); sc->sc_state = PPPOE_STATE_PADO_SENT; pppoe_send_pado(sc); break; #endif /* PPPOE_SERVER */ case PPPOE_CODE_PADR: #ifdef PPPOE_SERVER /* * get sc from ac_cookie if IFF_PASSIVE */ if (ac_cookie == NULL) { /* be quiet if there is not a single pppoe instance */ PPPDEBUG(LOG_DEBUG, ("pppoe: received PADR but not includes ac_cookie\n")); goto done; } sc = pppoe_find_softc_by_hunique(ac_cookie, ac_cookie_len, netif); if (sc == NULL) { /* be quiet if there is not a single pppoe instance */ if (!LIST_EMPTY(&pppoe_softc_list)) { PPPDEBUG(LOG_DEBUG, ("pppoe: received PADR but could not find request for it\n")); } goto done; } if (sc->sc_state != PPPOE_STATE_PADO_SENT) { PPPDEBUG(LOG_DEBUG, ("%c%c%"U16_F": received unexpected PADR\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num)); goto done; } if (hunique) { if (sc->sc_hunique) { mem_free(sc->sc_hunique); } sc->sc_hunique = mem_malloc(hunique_len); if (sc->sc_hunique == NULL) { goto done; } sc->sc_hunique_len = hunique_len; MEMCPY(sc->sc_hunique, hunique, hunique_len); } pppoe_send_pads(sc); sc->sc_state = PPPOE_STATE_SESSION; pppoe_linkstatus_up(sc); /* notify upper layers */ break; #else /* ignore, we are no access concentrator */ goto done; #endif /* PPPOE_SERVER */ case PPPOE_CODE_PADO: if (sc == NULL) { /* be quiet if there is not a single pppoe instance */ if (pppoe_softc_list != NULL) { PPPDEBUG(LOG_DEBUG, ("pppoe: received PADO but could not find request for it\n")); } goto done; } if (sc->sc_state != PPPOE_STATE_PADI_SENT) { PPPDEBUG(LOG_DEBUG, ("%c%c%"U16_F": received unexpected PADO\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num)); goto done; } if (ac_cookie) { sc->sc_ac_cookie_len = ac_cookie_len; MEMCPY(sc->sc_ac_cookie, ac_cookie, ac_cookie_len); } MEMCPY(&sc->sc_dest, ethhdr->src.addr, sizeof(sc->sc_dest.addr)); sys_untimeout(pppoe_timeout, sc); sc->sc_padr_retried = 0; sc->sc_state = PPPOE_STATE_PADR_SENT; if ((err = pppoe_send_padr(sc)) != 0) { PPPDEBUG(LOG_DEBUG, ("pppoe: %c%c%"U16_F": failed to send PADR, error=%d\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, err)); } sys_timeout(PPPOE_DISC_TIMEOUT * (1 + sc->sc_padr_retried), pppoe_timeout, sc); break; case PPPOE_CODE_PADS: if (sc == NULL) { goto done; } sc->sc_session = session; sys_untimeout(pppoe_timeout, sc); PPPDEBUG(LOG_DEBUG, ("pppoe: %c%c%"U16_F": session 0x%x connected\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, session)); sc->sc_state = PPPOE_STATE_SESSION; pppoe_linkstatus_up(sc); /* notify upper layers */ break; case PPPOE_CODE_PADT: if (sc == NULL) { goto done; } pppoe_clear_softc(sc, "received PADT"); break; default: if(sc) { PPPDEBUG(LOG_DEBUG, ("%c%c%"U16_F": unknown code (0x%"X16_F") session = 0x%"X16_F"\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, (u16_t)ph->code, session)); } else { PPPDEBUG(LOG_DEBUG, ("pppoe: unknown code (0x%"X16_F") session = 0x%"X16_F"\n", (u16_t)ph->code, session)); } break; } done: pbuf_free(pb); return; } void pppoe_data_input(struct netif *netif, struct pbuf *pb) { u16_t session, plen; struct pppoe_softc *sc; struct pppoehdr *ph; #ifdef PPPOE_TERM_UNKNOWN_SESSIONS u8_t shost[ETHER_ADDR_LEN]; #endif #ifdef PPPOE_TERM_UNKNOWN_SESSIONS MEMCPY(shost, ((struct eth_hdr *)pb->payload)->src.addr, sizeof(shost)); #endif if (pbuf_header(pb, -(int)sizeof(struct eth_hdr)) != 0) { /* bail out */ PPPDEBUG(LOG_ERR, ("pppoe_data_input: pbuf_header failed\n")); LINK_STATS_INC(link.lenerr); goto drop; } pb = ppp_singlebuf (pb); if (pb->len <= PPPOE_HEADERLEN) { PPPDEBUG(LOG_DEBUG, ("pppoe (data): dropping too short packet: %d bytes\n", pb->len)); goto drop; } if (pb->len < sizeof(*ph)) { PPPDEBUG(LOG_DEBUG, ("pppoe_data_input: could not get PPPoE header\n")); goto drop; } ph = (struct pppoehdr *)pb->payload; if (ph->vertype != PPPOE_VERTYPE) { PPPDEBUG(LOG_DEBUG, ("pppoe (data): unknown version/type packet: 0x%x\n", ph->vertype)); goto drop; } if (ph->code != 0) { goto drop; } session = ntohs(ph->session); sc = pppoe_find_softc_by_session(session, netif); if (sc == NULL) { #ifdef PPPOE_TERM_UNKNOWN_SESSIONS PPPDEBUG(LOG_DEBUG, ("pppoe: input for unknown session 0x%x, sending PADT\n", session)); pppoe_send_padt(netif, session, shost); #endif goto drop; } plen = ntohs(ph->plen); if (pbuf_header(pb, -(int)(PPPOE_HEADERLEN)) != 0) { /* bail out */ PPPDEBUG(LOG_ERR, ("pppoe_data_input: pbuf_header PPPOE_HEADERLEN failed\n")); LINK_STATS_INC(link.lenerr); goto drop; } PPPDEBUG(LOG_DEBUG, ("pppoe_data_input: %c%c%"U16_F": pkthdr.len=%d, pppoe.len=%d\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, pb->len, plen)); if (pb->len < plen) { goto drop; } /* Dispatch the packet thereby consuming it. */ ppp_input(sc->pcb, pb); return; drop: pbuf_free(pb); } static err_t pppoe_output(struct pppoe_softc *sc, struct pbuf *pb) { struct eth_hdr *ethhdr; u16_t etype; err_t res; if (!sc->sc_ethif) { pbuf_free(pb); return ERR_IF; } /* make room for Ethernet header - should not fail */ if (pbuf_header(pb, (u16_t)(sizeof(struct eth_hdr))) != 0) { /* bail out */ PPPDEBUG(LOG_ERR, ("pppoe: %c%c%"U16_F": pppoe_output: could not allocate room for Ethernet header\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num)); LINK_STATS_INC(link.lenerr); pbuf_free(pb); return ERR_BUF; } ethhdr = (struct eth_hdr *)pb->payload; etype = sc->sc_state == PPPOE_STATE_SESSION ? ETHTYPE_PPPOE : ETHTYPE_PPPOEDISC; ethhdr->type = htons(etype); MEMCPY(ðhdr->dest.addr, &sc->sc_dest.addr, sizeof(ethhdr->dest.addr)); MEMCPY(ðhdr->src.addr, &sc->sc_ethif->hwaddr, sizeof(ethhdr->src.addr)); PPPDEBUG(LOG_DEBUG, ("pppoe: %c%c%"U16_F" (%x) state=%d, session=0x%x output -> %02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F", len=%d\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, etype, sc->sc_state, sc->sc_session, sc->sc_dest.addr[0], sc->sc_dest.addr[1], sc->sc_dest.addr[2], sc->sc_dest.addr[3], sc->sc_dest.addr[4], sc->sc_dest.addr[5], pb->tot_len)); res = sc->sc_ethif->linkoutput(sc->sc_ethif, pb); pbuf_free(pb); return res; } static err_t pppoe_send_padi(struct pppoe_softc *sc) { struct pbuf *pb; u8_t *p; int len; #ifdef PPPOE_TODO int l1 = 0, l2 = 0; /* XXX: gcc */ #endif /* PPPOE_TODO */ if (sc->sc_state >PPPOE_STATE_PADI_SENT) { PPPDEBUG(LOG_ERR, ("ERROR: pppoe_send_padi in state %d", sc->sc_state)); } /* calculate length of frame (excluding ethernet header + pppoe header) */ len = 2 + 2 + 2 + 2 + sizeof sc; /* service name tag is required, host unique is send too */ #ifdef PPPOE_TODO if (sc->sc_service_name != NULL) { l1 = (int)strlen(sc->sc_service_name); len += l1; } if (sc->sc_concentrator_name != NULL) { l2 = (int)strlen(sc->sc_concentrator_name); len += 2 + 2 + l2; } #endif /* PPPOE_TODO */ LWIP_ASSERT("sizeof(struct eth_hdr) + PPPOE_HEADERLEN + len <= 0xffff", sizeof(struct eth_hdr) + PPPOE_HEADERLEN + len <= 0xffff); /* allocate a buffer */ pb = pbuf_alloc(PBUF_LINK, (u16_t)(PPPOE_HEADERLEN + len), PBUF_RAM); if (!pb) { return ERR_MEM; } LWIP_ASSERT("pb->tot_len == pb->len", pb->tot_len == pb->len); p = (u8_t*)pb->payload; /* fill in pkt */ PPPOE_ADD_HEADER(p, PPPOE_CODE_PADI, 0, (u16_t)len); PPPOE_ADD_16(p, PPPOE_TAG_SNAME); #ifdef PPPOE_TODO if (sc->sc_service_name != NULL) { PPPOE_ADD_16(p, l1); MEMCPY(p, sc->sc_service_name, l1); p += l1; } else #endif /* PPPOE_TODO */ { PPPOE_ADD_16(p, 0); } #ifdef PPPOE_TODO if (sc->sc_concentrator_name != NULL) { PPPOE_ADD_16(p, PPPOE_TAG_ACNAME); PPPOE_ADD_16(p, l2); MEMCPY(p, sc->sc_concentrator_name, l2); p += l2; } #endif /* PPPOE_TODO */ PPPOE_ADD_16(p, PPPOE_TAG_HUNIQUE); PPPOE_ADD_16(p, sizeof(sc)); MEMCPY(p, &sc, sizeof sc); /* send pkt */ return pppoe_output(sc, pb); } static void pppoe_timeout(void *arg) { u32_t retry_wait; int err; struct pppoe_softc *sc = (struct pppoe_softc*)arg; PPPDEBUG(LOG_DEBUG, ("pppoe: %c%c%"U16_F": timeout\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num)); switch (sc->sc_state) { case PPPOE_STATE_PADI_SENT: /* * We have two basic ways of retrying: * - Quick retry mode: try a few times in short sequence * - Slow retry mode: we already had a connection successfully * established and will try infinitely (without user * intervention) * We only enter slow retry mode if IFF_LINK1 (aka autodial) * is not set. */ if (sc->sc_padi_retried < 0xff) { sc->sc_padi_retried++; } if (!sc->pcb->settings.persist && sc->sc_padi_retried >= PPPOE_DISC_MAXPADI) { #if 0 if ((sc->sc_sppp.pp_if.if_flags & IFF_LINK1) == 0) { /* slow retry mode */ retry_wait = PPPOE_SLOW_RETRY; } else #endif { pppoe_abort_connect(sc); return; } } /* initialize for quick retry mode */ retry_wait = LWIP_MIN(PPPOE_DISC_TIMEOUT * sc->sc_padi_retried, PPPOE_SLOW_RETRY); if ((err = pppoe_send_padi(sc)) != 0) { sc->sc_padi_retried--; PPPDEBUG(LOG_DEBUG, ("pppoe: %c%c%"U16_F": failed to transmit PADI, error=%d\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, err)); } sys_timeout(retry_wait, pppoe_timeout, sc); break; case PPPOE_STATE_PADR_SENT: sc->sc_padr_retried++; if (sc->sc_padr_retried >= PPPOE_DISC_MAXPADR) { MEMCPY(&sc->sc_dest, ethbroadcast.addr, sizeof(sc->sc_dest)); sc->sc_state = PPPOE_STATE_PADI_SENT; sc->sc_padr_retried = 0; if ((err = pppoe_send_padi(sc)) != 0) { PPPDEBUG(LOG_DEBUG, ("pppoe: %c%c%"U16_F": failed to send PADI, error=%d\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, err)); } sys_timeout(PPPOE_DISC_TIMEOUT * (1 + sc->sc_padi_retried), pppoe_timeout, sc); return; } if ((err = pppoe_send_padr(sc)) != 0) { sc->sc_padr_retried--; PPPDEBUG(LOG_DEBUG, ("pppoe: %c%c%"U16_F": failed to send PADR, error=%d\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, err)); } sys_timeout(PPPOE_DISC_TIMEOUT * (1 + sc->sc_padr_retried), pppoe_timeout, sc); break; default: return; /* all done, work in peace */ } } /* Start a connection (i.e. initiate discovery phase) */ int pppoe_connect(struct pppoe_softc *sc) { int err; if (sc->sc_state != PPPOE_STATE_INITIAL) { return EBUSY; } /* stop any timer */ sys_untimeout(pppoe_timeout, sc); sc->sc_session = 0; sc->sc_padi_retried = 0; sc->sc_padr_retried = 0; #ifdef PPPOE_SERVER /* wait PADI if IFF_PASSIVE */ if ((sc->sc_sppp.pp_if.if_flags & IFF_PASSIVE)) { return 0; } #endif /* save state, in case we fail to send PADI */ sc->sc_state = PPPOE_STATE_PADI_SENT; if ((err = pppoe_send_padi(sc)) != 0) { PPPDEBUG(LOG_DEBUG, ("pppoe: %c%c%"U16_F": failed to send PADI, error=%d\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, err)); } sys_timeout(PPPOE_DISC_TIMEOUT, pppoe_timeout, sc); return err; } /* disconnect */ void pppoe_disconnect(struct pppoe_softc *sc) { if (sc->sc_state < PPPOE_STATE_SESSION) { return; } PPPDEBUG(LOG_DEBUG, ("pppoe: %c%c%"U16_F": disconnecting\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num)); pppoe_send_padt(sc->sc_ethif, sc->sc_session, (const u8_t *)&sc->sc_dest); /* cleanup softc */ sc->sc_state = PPPOE_STATE_INITIAL; MEMCPY(&sc->sc_dest, ethbroadcast.addr, sizeof(sc->sc_dest)); sc->sc_ac_cookie_len = 0; #ifdef PPPOE_SERVER if (sc->sc_hunique) { mem_free(sc->sc_hunique); sc->sc_hunique = NULL; } sc->sc_hunique_len = 0; #endif sc->sc_session = 0; sc->sc_padi_retried = 0; sc->sc_padr_retried = 0; sc->sc_link_status_cb(sc->pcb, PPPOE_CB_STATE_DOWN); /* notify upper layers */ return; } /* Connection attempt aborted */ static void pppoe_abort_connect(struct pppoe_softc *sc) { PPPDEBUG(LOG_DEBUG, ("%c%c%"U16_F": could not establish connection\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num)); /* clear connection state */ sc->sc_state = PPPOE_STATE_INITIAL; MEMCPY(&sc->sc_dest, ethbroadcast.addr, sizeof(sc->sc_dest)); sc->sc_ac_cookie_len = 0; sc->sc_session = 0; sc->sc_padi_retried = 0; sc->sc_padr_retried = 0; sc->sc_link_status_cb(sc->pcb, PPPOE_CB_STATE_FAILED); /* notify upper layers */ } /* Send a PADR packet */ static err_t pppoe_send_padr(struct pppoe_softc *sc) { struct pbuf *pb; u8_t *p; size_t len; #ifdef PPPOE_TODO size_t l1 = 0; /* XXX: gcc */ #endif /* PPPOE_TODO */ if (sc->sc_state != PPPOE_STATE_PADR_SENT) { return ERR_CONN; } len = 2 + 2 + 2 + 2 + sizeof(sc); /* service name, host unique */ #ifdef PPPOE_TODO if (sc->sc_service_name != NULL) { /* service name tag maybe empty */ l1 = strlen(sc->sc_service_name); len += l1; } #endif /* PPPOE_TODO */ if (sc->sc_ac_cookie_len > 0) { len += 2 + 2 + sc->sc_ac_cookie_len; /* AC cookie */ } LWIP_ASSERT("sizeof(struct eth_hdr) + PPPOE_HEADERLEN + len <= 0xffff", sizeof(struct eth_hdr) + PPPOE_HEADERLEN + len <= 0xffff); pb = pbuf_alloc(PBUF_LINK, (u16_t)(PPPOE_HEADERLEN + len), PBUF_RAM); if (!pb) { return ERR_MEM; } LWIP_ASSERT("pb->tot_len == pb->len", pb->tot_len == pb->len); p = (u8_t*)pb->payload; PPPOE_ADD_HEADER(p, PPPOE_CODE_PADR, 0, len); PPPOE_ADD_16(p, PPPOE_TAG_SNAME); #ifdef PPPOE_TODO if (sc->sc_service_name != NULL) { PPPOE_ADD_16(p, l1); MEMCPY(p, sc->sc_service_name, l1); p += l1; } else #endif /* PPPOE_TODO */ { PPPOE_ADD_16(p, 0); } if (sc->sc_ac_cookie_len > 0) { PPPOE_ADD_16(p, PPPOE_TAG_ACCOOKIE); PPPOE_ADD_16(p, sc->sc_ac_cookie_len); MEMCPY(p, sc->sc_ac_cookie, sc->sc_ac_cookie_len); p += sc->sc_ac_cookie_len; } PPPOE_ADD_16(p, PPPOE_TAG_HUNIQUE); PPPOE_ADD_16(p, sizeof(sc)); MEMCPY(p, &sc, sizeof sc); return pppoe_output(sc, pb); } /* send a PADT packet */ static err_t pppoe_send_padt(struct netif *outgoing_if, u_int session, const u8_t *dest) { struct pbuf *pb; struct eth_hdr *ethhdr; err_t res; u8_t *p; pb = pbuf_alloc(PBUF_LINK, (u16_t)(PPPOE_HEADERLEN), PBUF_RAM); if (!pb) { return ERR_MEM; } LWIP_ASSERT("pb->tot_len == pb->len", pb->tot_len == pb->len); pbuf_header(pb, sizeof(struct eth_hdr)); ethhdr = (struct eth_hdr *)pb->payload; ethhdr->type = PP_HTONS(ETHTYPE_PPPOEDISC); MEMCPY(ðhdr->dest.addr, dest, sizeof(ethhdr->dest.addr)); MEMCPY(ðhdr->src.addr, &outgoing_if->hwaddr, sizeof(ethhdr->src.addr)); p = (u8_t*)(ethhdr + 1); PPPOE_ADD_HEADER(p, PPPOE_CODE_PADT, session, 0); res = outgoing_if->linkoutput(outgoing_if, pb); pbuf_free(pb); return res; } #ifdef PPPOE_SERVER static err_t pppoe_send_pado(struct pppoe_softc *sc) { struct pbuf *pb; u8_t *p; size_t len; if (sc->sc_state != PPPOE_STATE_PADO_SENT) { return ERR_CONN; } /* calc length */ len = 0; /* include ac_cookie */ len += 2 + 2 + sizeof(sc); /* include hunique */ len += 2 + 2 + sc->sc_hunique_len; pb = pbuf_alloc(PBUF_LINK, (u16_t)(PPPOE_HEADERLEN + len), PBUF_RAM); if (!pb) { return ERR_MEM; } LWIP_ASSERT("pb->tot_len == pb->len", pb->tot_len == pb->len); p = (u8_t*)pb->payload; PPPOE_ADD_HEADER(p, PPPOE_CODE_PADO, 0, len); PPPOE_ADD_16(p, PPPOE_TAG_ACCOOKIE); PPPOE_ADD_16(p, sizeof(sc)); MEMCPY(p, &sc, sizeof(sc)); p += sizeof(sc); PPPOE_ADD_16(p, PPPOE_TAG_HUNIQUE); PPPOE_ADD_16(p, sc->sc_hunique_len); MEMCPY(p, sc->sc_hunique, sc->sc_hunique_len); return pppoe_output(sc, pb); } static err_t pppoe_send_pads(struct pppoe_softc *sc) { struct pbuf *pb; u8_t *p; size_t len, l1 = 0; /* XXX: gcc */ if (sc->sc_state != PPPOE_STATE_PADO_SENT) { return ERR_CONN; } sc->sc_session = mono_time.tv_sec % 0xff + 1; /* calc length */ len = 0; /* include hunique */ len += 2 + 2 + 2 + 2 + sc->sc_hunique_len; /* service name, host unique*/ if (sc->sc_service_name != NULL) { /* service name tag maybe empty */ l1 = strlen(sc->sc_service_name); len += l1; } pb = pbuf_alloc(PBUF_LINK, (u16_t)(PPPOE_HEADERLEN + len), PBUF_RAM); if (!pb) { return ERR_MEM; } LWIP_ASSERT("pb->tot_len == pb->len", pb->tot_len == pb->len); p = (u8_t*)pb->payload; PPPOE_ADD_HEADER(p, PPPOE_CODE_PADS, sc->sc_session, len); PPPOE_ADD_16(p, PPPOE_TAG_SNAME); if (sc->sc_service_name != NULL) { PPPOE_ADD_16(p, l1); MEMCPY(p, sc->sc_service_name, l1); p += l1; } else { PPPOE_ADD_16(p, 0); } PPPOE_ADD_16(p, PPPOE_TAG_HUNIQUE); PPPOE_ADD_16(p, sc->sc_hunique_len); MEMCPY(p, sc->sc_hunique, sc->sc_hunique_len); return pppoe_output(sc, pb); } #endif err_t pppoe_xmit(struct pppoe_softc *sc, struct pbuf *pb) { u8_t *p; size_t len; /* are we ready to process data yet? */ if (sc->sc_state < PPPOE_STATE_SESSION) { /*sppp_flush(&sc->sc_sppp.pp_if);*/ pbuf_free(pb); return ERR_CONN; } len = pb->tot_len; /* make room for PPPoE header - should not fail */ if (pbuf_header(pb, (u16_t)(PPPOE_HEADERLEN)) != 0) { /* bail out */ PPPDEBUG(LOG_ERR, ("pppoe: %c%c%"U16_F": pppoe_xmit: could not allocate room for PPPoE header\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num)); LINK_STATS_INC(link.lenerr); pbuf_free(pb); return ERR_BUF; } p = (u8_t*)pb->payload; PPPOE_ADD_HEADER(p, 0, sc->sc_session, len); return pppoe_output(sc, pb); } #if 0 /*def PFIL_HOOKS*/ static int pppoe_ifattach_hook(void *arg, struct pbuf **mp, struct netif *ifp, int dir) { struct pppoe_softc *sc; int s; if (mp != (struct pbuf **)PFIL_IFNET_DETACH) { return 0; } LIST_FOREACH(sc, &pppoe_softc_list, sc_list) { if (sc->sc_ethif != ifp) { continue; } if (sc->sc_sppp.pp_if.if_flags & IFF_UP) { sc->sc_sppp.pp_if.if_flags &= ~(IFF_UP|IFF_RUNNING); PPPDEBUG(LOG_DEBUG, ("%c%c%"U16_F": ethernet interface detached, going down\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num)); } sc->sc_ethif = NULL; pppoe_clear_softc(sc, "ethernet interface detached"); } return 0; } #endif static void pppoe_clear_softc(struct pppoe_softc *sc, const char *message) { LWIP_UNUSED_ARG(message); /* stop timer */ sys_untimeout(pppoe_timeout, sc); PPPDEBUG(LOG_DEBUG, ("pppoe: %c%c%"U16_F": session 0x%x terminated, %s\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, sc->sc_session, message)); /* fix our state */ sc->sc_state = PPPOE_STATE_INITIAL; /* notify upper layers */ sc->sc_link_status_cb(sc->pcb, PPPOE_CB_STATE_DOWN); /* clean up softc */ MEMCPY(&sc->sc_dest, ethbroadcast.addr, sizeof(sc->sc_dest)); sc->sc_ac_cookie_len = 0; sc->sc_session = 0; sc->sc_padi_retried = 0; sc->sc_padr_retried = 0; } #endif /* PPP_SUPPORT && PPPOE_SUPPORT */ ocproxy-1.60/lwip/src/netif/ppp/pppol2tp.c000066400000000000000000001045471303453231400205460ustar00rootroot00000000000000/** * @file * Network Point to Point Protocol over Layer 2 Tunneling Protocol program file. * */ /* * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * */ /* * L2TP Support status: * * Supported: * - L2TPv2 (PPP over L2TP, a.k.a. UDP tunnels) * - LAC * * Not supported: * - LNS (require PPP server support) * - L2TPv3 ethernet pseudowires * - L2TPv3 VLAN pseudowire * - L2TPv3 PPP pseudowires * - L2TPv3 IP encapsulation * - L2TPv3 IP pseudowire * - L2TP tunnel switching - http://tools.ietf.org/html/draft-ietf-l2tpext-tunnel-switching-08 * - Multiple tunnels per UDP socket, as well as multiple sessions per tunnel * - Hidden AVPs */ #include "lwip/opt.h" #if PPP_SUPPORT && PPPOL2TP_SUPPORT /* don't build if not configured for use in lwipopts.h */ #include "lwip/err.h" #include "lwip/memp.h" #include "lwip/netif.h" #include "lwip/udp.h" #include "netif/ppp/ppp_impl.h" #include "netif/ppp/pppol2tp.h" #include "netif/ppp/magic.h" #if PPPOL2TP_AUTH_SUPPORT #if LWIP_INCLUDED_POLARSSL_MD5 #include "netif/ppp/polarssl/md5.h" #else #include "polarssl/md5.h" #endif #endif /* PPPOL2TP_AUTH_SUPPORT */ /* Prototypes for procedures local to this file. */ static void pppol2tp_input(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u16_t port); static void pppol2tp_dispatch_control_packet(pppol2tp_pcb *l2tp, struct ip_addr *addr, u16_t port, struct pbuf *p, u16_t len, u16_t tunnel_id, u16_t session_id, u16_t ns, u16_t nr); static void pppol2tp_timeout(void *arg); static void pppol2tp_abort_connect(pppol2tp_pcb *l2tp); static void pppol2tp_clear(pppol2tp_pcb *l2tp); static err_t pppol2tp_send_sccrq(pppol2tp_pcb *l2tp); static err_t pppol2tp_send_scccn(pppol2tp_pcb *l2tp, u16_t ns); static err_t pppol2tp_send_icrq(pppol2tp_pcb *l2tp, u16_t ns); static err_t pppol2tp_send_iccn(pppol2tp_pcb *l2tp, u16_t ns); static err_t pppol2tp_send_zlb(pppol2tp_pcb *l2tp, u16_t ns); static err_t pppol2tp_send_stopccn(pppol2tp_pcb *l2tp, u16_t ns); /* Create a new L2TP session. */ err_t pppol2tp_create(ppp_pcb *ppp, void (*link_status_cb)(ppp_pcb *pcb, int status), pppol2tp_pcb **l2tpptr, struct netif *netif, ip_addr_t *ipaddr, u16_t port, u8_t *secret, u8_t secret_len) { pppol2tp_pcb *l2tp; struct udp_pcb *udp; l2tp = (pppol2tp_pcb *)memp_malloc(MEMP_PPPOL2TP_PCB); if (l2tp == NULL) { *l2tpptr = NULL; return ERR_MEM; } udp = udp_new(); if (udp == NULL) { memp_free(MEMP_PPPOL2TP_PCB, l2tp); *l2tpptr = NULL; return ERR_MEM; } udp_recv(udp, pppol2tp_input, l2tp); memset(l2tp, 0, sizeof(pppol2tp_pcb)); l2tp->phase = PPPOL2TP_STATE_INITIAL; l2tp->ppp = ppp; l2tp->udp = udp; l2tp->link_status_cb = link_status_cb; l2tp->netif = netif; ip_addr_set(&l2tp->remote_ip, ipaddr); l2tp->remote_port = port; #if PPPOL2TP_AUTH_SUPPORT l2tp->secret = secret; l2tp->secret_len = secret_len; #endif /* PPPOL2TP_AUTH_SUPPORT */ *l2tpptr = l2tp; return ERR_OK; } /* Destroy a L2TP control block */ err_t pppol2tp_destroy(pppol2tp_pcb *l2tp) { sys_untimeout(pppol2tp_timeout, l2tp); if (l2tp->udp != NULL) { udp_remove(l2tp->udp); } memp_free(MEMP_PPPOL2TP_PCB, l2tp); return ERR_OK; } /* Be a LAC, connect to a LNS. */ err_t pppol2tp_connect(pppol2tp_pcb *l2tp) { err_t err; if (l2tp->phase != PPPOL2TP_STATE_INITIAL) { return ERR_VAL; } pppol2tp_clear(l2tp); /* Listen to a random source port, we need to do that instead of using udp_connect() * because the L2TP LNS might answer with its own random source port (!= 1701) */ udp_bind(l2tp->udp, IP_ADDR_ANY, 0); #if PPPOL2TP_AUTH_SUPPORT /* Generate random vector */ if (l2tp->secret != NULL) { random_bytes(l2tp->secret_rv, sizeof(l2tp->secret_rv)); } #endif /* PPPOL2TP_AUTH_SUPPORT */ do { l2tp->remote_tunnel_id = magic(); } while(l2tp->remote_tunnel_id == 0); /* save state, in case we fail to send SCCRQ */ l2tp->sccrq_retried = 0; l2tp->phase = PPPOL2TP_STATE_SCCRQ_SENT; if ((err = pppol2tp_send_sccrq(l2tp)) != 0) { PPPDEBUG(LOG_DEBUG, ("pppol2tp: failed to send SCCRQ, error=%d\n", err)); } sys_timeout(PPPOL2TP_CONTROL_TIMEOUT, pppol2tp_timeout, l2tp); return err; } /* Disconnect */ void pppol2tp_disconnect(pppol2tp_pcb *l2tp) { if (l2tp->phase < PPPOL2TP_STATE_DATA) { return; } l2tp->our_ns++; pppol2tp_send_stopccn(l2tp, l2tp->our_ns); pppol2tp_clear(l2tp); l2tp->link_status_cb(l2tp->ppp, PPPOL2TP_CB_STATE_DOWN); /* notify upper layers */ } /* UDP Callback for incoming L2TP frames */ static void pppol2tp_input(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u16_t port) { pppol2tp_pcb *l2tp = (pppol2tp_pcb*)arg; u16_t hflags, hlen, len=0, tunnel_id=0, session_id=0, ns=0, nr=0, offset=0; u8_t *inp; if (l2tp->phase < PPPOL2TP_STATE_SCCRQ_SENT) { goto free_and_return; } /* printf("-----------\nL2TP INPUT, %d\n", p->len); */ p = ppp_singlebuf(p); /* L2TP header */ if (p->len < sizeof(hflags) + sizeof(tunnel_id) + sizeof(session_id) ) { goto packet_too_short; } inp = p->payload; GETSHORT(hflags, inp); if (hflags & PPPOL2TP_HEADERFLAG_CONTROL) { /* check mandatory flags for a control packet */ if ( (hflags & PPPOL2TP_HEADERFLAG_CONTROL_MANDATORY) != PPPOL2TP_HEADERFLAG_CONTROL_MANDATORY ) { PPPDEBUG(LOG_DEBUG, ("pppol2tp: mandatory header flags for control packet not set\n")); goto free_and_return; } /* check forbidden flags for a control packet */ if (hflags & PPPOL2TP_HEADERFLAG_CONTROL_FORBIDDEN) { PPPDEBUG(LOG_DEBUG, ("pppol2tp: forbidden header flags for control packet found\n")); goto free_and_return; } } else { /* check mandatory flags for a data packet */ if ( (hflags & PPPOL2TP_HEADERFLAG_DATA_MANDATORY) != PPPOL2TP_HEADERFLAG_DATA_MANDATORY) { PPPDEBUG(LOG_DEBUG, ("pppol2tp: mandatory header flags for data packet not set\n")); goto free_and_return; } } /* Expected header size */ hlen = sizeof(hflags) + sizeof(tunnel_id) + sizeof(session_id); if (hflags & PPPOL2TP_HEADERFLAG_LENGTH) { hlen += sizeof(len); } if (hflags & PPPOL2TP_HEADERFLAG_SEQUENCE) { hlen += sizeof(ns) + sizeof(nr); } if (hflags & PPPOL2TP_HEADERFLAG_OFFSET) { hlen += sizeof(offset); } if (p->len < hlen) { goto packet_too_short; } if (hflags & PPPOL2TP_HEADERFLAG_LENGTH) { GETSHORT(len, inp); if (p->len < len || len < hlen) { goto packet_too_short; } } GETSHORT(tunnel_id, inp); GETSHORT(session_id, inp); if (hflags & PPPOL2TP_HEADERFLAG_SEQUENCE) { GETSHORT(ns, inp); GETSHORT(nr, inp); } if (hflags & PPPOL2TP_HEADERFLAG_OFFSET) { GETSHORT(offset, inp) if (offset > 4096) { /* don't be fooled with large offset which might overflow hlen */ PPPDEBUG(LOG_DEBUG, ("pppol2tp: strange packet received, offset=%d\n", offset)); goto free_and_return; } hlen += offset; if (p->len < hlen) { goto packet_too_short; } INCPTR(offset, inp); } /* printf("HLEN = %d\n", hlen); */ /* skip L2TP header */ if (pbuf_header(p, -hlen) != 0) { goto free_and_return; } /* printf("LEN=%d, TUNNEL_ID=%d, SESSION_ID=%d, NS=%d, NR=%d, OFFSET=%d\n", len, tunnel_id, session_id, ns, nr, offset); */ PPPDEBUG(LOG_DEBUG, ("pppol2tp: input packet, len=%"U16_F", tunnel=%"U16_F", session=%"U16_F", ns=%"U16_F", nr=%"U16_F"\n", len, tunnel_id, session_id, ns, nr)); /* Control packet */ if (hflags & PPPOL2TP_HEADERFLAG_CONTROL) { pppol2tp_dispatch_control_packet(l2tp, addr, port, p, len, tunnel_id, session_id, ns, nr); goto free_and_return; } /* Data packet */ if(l2tp->phase != PPPOL2TP_STATE_DATA) { goto free_and_return; } if(tunnel_id != l2tp->remote_tunnel_id) { PPPDEBUG(LOG_DEBUG, ("pppol2tp: tunnel ID mismatch, assigned=%d, received=%d\n", l2tp->remote_tunnel_id, tunnel_id)); goto free_and_return; } if(session_id != l2tp->remote_session_id) { PPPDEBUG(LOG_DEBUG, ("pppol2tp: session ID mismatch, assigned=%d, received=%d\n", l2tp->remote_session_id, session_id)); goto free_and_return; } /* * skip address & flags if necessary * * RFC 2661 does not specify whether the PPP frame in the L2TP payload should * have a HDLC header or not. We handle both cases for compatibility. */ GETSHORT(hflags, inp); if (hflags == 0xff03) { pbuf_header(p, -(s16_t)2); } /* Dispatch the packet thereby consuming it. */ ppp_input(l2tp->ppp, p); return; packet_too_short: PPPDEBUG(LOG_DEBUG, ("pppol2tp: packet too short: %d\n", p->len)); free_and_return: pbuf_free(p); } /* L2TP Control packet entry point */ static void pppol2tp_dispatch_control_packet(pppol2tp_pcb *l2tp, struct ip_addr *addr, u16_t port, struct pbuf *p, u16_t len, u16_t tunnel_id, u16_t session_id, u16_t ns, u16_t nr) { u8_t *inp; u16_t avplen, avpflags, vendorid, attributetype, messagetype=0; err_t err; #if PPPOL2TP_AUTH_SUPPORT md5_context md5_context; u8_t md5_hash[16]; u8_t challenge_id = 0; #endif /* PPPOL2TP_AUTH_SUPPORT */ l2tp->peer_nr = nr; l2tp->peer_ns = ns; /* printf("L2TP CTRL INPUT, ns=%d, nr=%d, len=%d\n", ns, nr, p->len); */ /* Handle the special case of the ICCN acknowledge */ if (l2tp->phase == PPPOL2TP_STATE_ICCN_SENT && l2tp->peer_nr > l2tp->our_ns) { l2tp->phase = PPPOL2TP_STATE_DATA; } /* ZLB packets */ if (p->len == 0) { return; } inp = p->payload; /* Decode AVPs */ while (p->len > 0) { if (p->len < sizeof(avpflags) + sizeof(vendorid) + sizeof(attributetype) ) { goto packet_too_short; } GETSHORT(avpflags, inp); avplen = avpflags & PPPOL2TP_AVPHEADERFLAG_LENGTHMASK; /* printf("AVPLEN = %d\n", avplen); */ if (p->len < avplen || avplen < sizeof(avpflags) + sizeof(vendorid) + sizeof(attributetype)) { goto packet_too_short; } GETSHORT(vendorid, inp); GETSHORT(attributetype, inp); avplen -= sizeof(avpflags) + sizeof(vendorid) + sizeof(attributetype); /* Message type must be the first AVP */ if (messagetype == 0) { if (attributetype != 0 || vendorid != 0 || avplen != sizeof(messagetype) ) { PPPDEBUG(LOG_DEBUG, ("pppol2tp: message type must be the first AVP\n")); return; } GETSHORT(messagetype, inp); /* printf("Message type = %d\n", messagetype); */ switch(messagetype) { /* Start Control Connection Reply */ case PPPOL2TP_MESSAGETYPE_SCCRP: /* Only accept SCCRP packet if we sent a SCCRQ */ if (l2tp->phase != PPPOL2TP_STATE_SCCRQ_SENT) { goto send_zlb; } break; /* Incoming Call Reply */ case PPPOL2TP_MESSAGETYPE_ICRP: /* Only accept ICRP packet if we sent a IRCQ */ if (l2tp->phase != PPPOL2TP_STATE_ICRQ_SENT) { goto send_zlb; } break; /* Stop Control Connection Notification */ case PPPOL2TP_MESSAGETYPE_STOPCCN: pppol2tp_send_zlb(l2tp, l2tp->our_ns); /* Ack the StopCCN before we switch to down state */ if (l2tp->phase < PPPOL2TP_STATE_DATA) { pppol2tp_abort_connect(l2tp); } else if (l2tp->phase == PPPOL2TP_STATE_DATA) { /* Don't disconnect here, we let the LCP Echo/Reply find the fact * that PPP session is down. Asking the PPP stack to end the session * require strict checking about the PPP phase to prevent endless * disconnection loops. */ } return; } goto nextavp; } /* Skip proprietary L2TP extensions */ if (vendorid != 0) { goto skipavp; } switch (messagetype) { /* Start Control Connection Reply */ case PPPOL2TP_MESSAGETYPE_SCCRP: switch (attributetype) { case PPPOL2TP_AVPTYPE_TUNNELID: if (avplen != sizeof(l2tp->source_tunnel_id) ) { PPPDEBUG(LOG_DEBUG, ("pppol2tp: AVP Assign tunnel ID length check failed\n")); return; } GETSHORT(l2tp->source_tunnel_id, inp); PPPDEBUG(LOG_DEBUG, ("pppol2tp: Assigned tunnel ID %"U16_F"\n", l2tp->source_tunnel_id)); goto nextavp; #if PPPOL2TP_AUTH_SUPPORT case PPPOL2TP_AVPTYPE_CHALLENGE: if (avplen == 0) { PPPDEBUG(LOG_DEBUG, ("pppol2tp: Challenge length check failed\n")); return; } if (l2tp->secret == NULL) { PPPDEBUG(LOG_DEBUG, ("pppol2tp: Received challenge from peer and no secret key available\n")); pppol2tp_abort_connect(l2tp); return; } /* Generate hash of ID, secret, challenge */ md5_starts(&md5_context); challenge_id = PPPOL2TP_MESSAGETYPE_SCCCN; md5_update(&md5_context, &challenge_id, 1); md5_update(&md5_context, l2tp->secret, l2tp->secret_len); md5_update(&md5_context, inp, avplen); md5_finish(&md5_context, l2tp->challenge_hash); l2tp->send_challenge = 1; goto skipavp; case PPPOL2TP_AVPTYPE_CHALLENGERESPONSE: if (avplen != PPPOL2TP_AVPTYPE_CHALLENGERESPONSE_SIZE) { PPPDEBUG(LOG_DEBUG, ("pppol2tp: AVP Challenge Response length check failed\n")); return; } /* Generate hash of ID, secret, challenge */ md5_starts(&md5_context); challenge_id = PPPOL2TP_MESSAGETYPE_SCCRP; md5_update(&md5_context, &challenge_id, 1); md5_update(&md5_context, l2tp->secret, l2tp->secret_len); md5_update(&md5_context, l2tp->secret_rv, sizeof(l2tp->secret_rv)); md5_finish(&md5_context, md5_hash); if ( memcmp(inp, md5_hash, sizeof(md5_hash)) ) { PPPDEBUG(LOG_DEBUG, ("pppol2tp: Received challenge response from peer and secret key do not match\n")); pppol2tp_abort_connect(l2tp); return; } goto skipavp; #endif /* PPPOL2TP_AUTH_SUPPORT */ } break; /* Incoming Call Reply */ case PPPOL2TP_MESSAGETYPE_ICRP: switch (attributetype) { case PPPOL2TP_AVPTYPE_SESSIONID: if (avplen != sizeof(l2tp->source_session_id) ) { PPPDEBUG(LOG_DEBUG, ("pppol2tp: AVP Assign session ID length check failed\n")); return; } GETSHORT(l2tp->source_session_id, inp); PPPDEBUG(LOG_DEBUG, ("pppol2tp: Assigned session ID %"U16_F"\n", l2tp->source_session_id)); goto nextavp; } break; } skipavp: INCPTR(avplen, inp); nextavp: /* printf("AVP Found, vendor=%d, attribute=%d, len=%d\n", vendorid, attributetype, avplen); */ /* next AVP */ if (pbuf_header(p, -avplen - sizeof(avpflags) - sizeof(vendorid) - sizeof(attributetype) ) != 0) { return; } } switch(messagetype) { /* Start Control Connection Reply */ case PPPOL2TP_MESSAGETYPE_SCCRP: do { l2tp->remote_session_id = magic(); } while(l2tp->remote_session_id == 0); l2tp->tunnel_port = port; /* LNS server might have chosen its own local port */ l2tp->icrq_retried = 0; l2tp->phase = PPPOL2TP_STATE_ICRQ_SENT; l2tp->our_ns++; if ((err = pppol2tp_send_scccn(l2tp, l2tp->our_ns)) != 0) { PPPDEBUG(LOG_DEBUG, ("pppol2tp: failed to send SCCCN, error=%d\n", err)); } l2tp->our_ns++; if ((err = pppol2tp_send_icrq(l2tp, l2tp->our_ns)) != 0) { PPPDEBUG(LOG_DEBUG, ("pppol2tp: failed to send ICRQ, error=%d\n", err)); } sys_untimeout(pppol2tp_timeout, l2tp); sys_timeout(PPPOL2TP_CONTROL_TIMEOUT, pppol2tp_timeout, l2tp); break; /* Incoming Call Reply */ case PPPOL2TP_MESSAGETYPE_ICRP: l2tp->iccn_retried = 0; l2tp->phase = PPPOL2TP_STATE_ICCN_SENT; l2tp->our_ns++; l2tp->link_status_cb(l2tp->ppp, PPPOL2TP_CB_STATE_UP); /* notify upper layers */ if ((err = pppol2tp_send_iccn(l2tp, l2tp->our_ns)) != 0) { PPPDEBUG(LOG_DEBUG, ("pppol2tp: failed to send ICCN, error=%d\n", err)); } sys_untimeout(pppol2tp_timeout, l2tp); sys_timeout(PPPOL2TP_CONTROL_TIMEOUT, pppol2tp_timeout, l2tp); break; /* Unhandled packet, send ZLB ACK */ default: goto send_zlb; } return; send_zlb: pppol2tp_send_zlb(l2tp, l2tp->our_ns); return; packet_too_short: PPPDEBUG(LOG_DEBUG, ("pppol2tp: packet too short: %d\n", p->len)); } /* L2TP Timeout handler */ static void pppol2tp_timeout(void *arg) { pppol2tp_pcb *l2tp = (pppol2tp_pcb*)arg; err_t err; u32_t retry_wait; PPPDEBUG(LOG_DEBUG, ("pppol2tp: timeout\n")); switch (l2tp->phase) { case PPPOL2TP_STATE_SCCRQ_SENT: /* backoff wait */ if (l2tp->sccrq_retried < 0xff) { l2tp->sccrq_retried++; } if (!l2tp->ppp->settings.persist && l2tp->sccrq_retried >= PPPOL2TP_MAXSCCRQ) { pppol2tp_abort_connect(l2tp); return; } retry_wait = LWIP_MIN(PPPOL2TP_CONTROL_TIMEOUT * l2tp->sccrq_retried, PPPOL2TP_SLOW_RETRY); PPPDEBUG(LOG_DEBUG, ("pppol2tp: sccrq_retried=%d\n", l2tp->sccrq_retried)); if ((err = pppol2tp_send_sccrq(l2tp)) != 0) { l2tp->sccrq_retried--; PPPDEBUG(LOG_DEBUG, ("pppol2tp: failed to send SCCRQ, error=%d\n", err)); } sys_timeout(retry_wait, pppol2tp_timeout, l2tp); break; case PPPOL2TP_STATE_ICRQ_SENT: l2tp->icrq_retried++; if (l2tp->icrq_retried >= PPPOL2TP_MAXICRQ) { pppol2tp_abort_connect(l2tp); return; } PPPDEBUG(LOG_DEBUG, ("pppol2tp: icrq_retried=%d\n", l2tp->icrq_retried)); if (l2tp->peer_nr <= l2tp->our_ns -1) { /* the SCCCN was not acknowledged */ if ((err = pppol2tp_send_scccn(l2tp, l2tp->our_ns -1)) != 0) { l2tp->icrq_retried--; PPPDEBUG(LOG_DEBUG, ("pppol2tp: failed to send SCCCN, error=%d\n", err)); sys_timeout(PPPOL2TP_CONTROL_TIMEOUT, pppol2tp_timeout, l2tp); break; } } if ((err = pppol2tp_send_icrq(l2tp, l2tp->our_ns)) != 0) { l2tp->icrq_retried--; PPPDEBUG(LOG_DEBUG, ("pppol2tp: failed to send ICRQ, error=%d\n", err)); } sys_timeout(PPPOL2TP_CONTROL_TIMEOUT, pppol2tp_timeout, l2tp); break; case PPPOL2TP_STATE_ICCN_SENT: l2tp->iccn_retried++; if (l2tp->iccn_retried >= PPPOL2TP_MAXICCN) { pppol2tp_abort_connect(l2tp); return; } PPPDEBUG(LOG_DEBUG, ("pppol2tp: iccn_retried=%d\n", l2tp->iccn_retried)); if ((err = pppol2tp_send_iccn(l2tp, l2tp->our_ns)) != 0) { l2tp->iccn_retried--; PPPDEBUG(LOG_DEBUG, ("pppol2tp: failed to send ICCN, error=%d\n", err)); } sys_timeout(PPPOL2TP_CONTROL_TIMEOUT, pppol2tp_timeout, l2tp); break; default: return; /* all done, work in peace */ } } /* Connection attempt aborted */ static void pppol2tp_abort_connect(pppol2tp_pcb *l2tp) { PPPDEBUG(LOG_DEBUG, ("pppol2tp: could not establish connection\n")); pppol2tp_clear(l2tp); l2tp->link_status_cb(l2tp->ppp, PPPOL2TP_CB_STATE_FAILED); /* notify upper layers */ } /* Reset L2TP control block to its initial state */ static void pppol2tp_clear(pppol2tp_pcb *l2tp) { /* stop any timer */ sys_untimeout(pppol2tp_timeout, l2tp); l2tp->phase = PPPOL2TP_STATE_INITIAL; l2tp->tunnel_port = l2tp->remote_port; l2tp->our_ns = 0; l2tp->peer_nr = 0; l2tp->peer_ns = 0; l2tp->source_tunnel_id = 0; l2tp->remote_tunnel_id = 0; l2tp->source_session_id = 0; l2tp->remote_session_id = 0; /* l2tp->*_retried are cleared when used */ } /* Initiate a new tunnel */ static err_t pppol2tp_send_sccrq(pppol2tp_pcb *l2tp) { struct pbuf *pb; u8_t *p; u16_t len; /* calculate UDP packet length */ len = 12 +8 +8 +10 +10 +6+sizeof(PPPOL2TP_HOSTNAME)-1 +6+sizeof(PPPOL2TP_VENDORNAME)-1 +8 +8; #if PPPOL2TP_AUTH_SUPPORT if (l2tp->secret != NULL) { len += 6 + sizeof(l2tp->secret_rv); } #endif /* PPPOL2TP_AUTH_SUPPORT */ /* allocate a buffer */ pb = pbuf_alloc(PBUF_TRANSPORT, len, PBUF_RAM); if (pb == NULL) { return ERR_MEM; } LWIP_ASSERT("pb->tot_len == pb->len", pb->tot_len == pb->len); p = (u8_t*)pb->payload; /* fill in pkt */ /* L2TP control header */ PUTSHORT(PPPOL2TP_HEADERFLAG_CONTROL_MANDATORY, p); PUTSHORT(len, p); /* Length */ PUTSHORT(0, p); /* Tunnel Id */ PUTSHORT(0, p); /* Session Id */ PUTSHORT(0, p); /* NS Sequence number - to peer */ PUTSHORT(0, p); /* NR Sequence number - expected for peer */ /* AVP - Message type */ PUTSHORT(PPPOL2TP_AVPHEADERFLAG_MANDATORY + 8, p); /* Mandatory flag + len field */ PUTSHORT(0, p); /* Vendor ID */ PUTSHORT(PPPOL2TP_AVPTYPE_MESSAGE, p); /* Attribute type: Message Type */ PUTSHORT(PPPOL2TP_MESSAGETYPE_SCCRQ, p); /* Attribute value: Message type: SCCRQ */ /* AVP - L2TP Version */ PUTSHORT(PPPOL2TP_AVPHEADERFLAG_MANDATORY + 8, p); /* Mandatory flag + len field */ PUTSHORT(0, p); /* Vendor ID */ PUTSHORT(PPPOL2TP_AVPTYPE_VERSION, p); /* Attribute type: Version */ PUTSHORT(PPPOL2TP_VERSION, p); /* Attribute value: L2TP Version */ /* AVP - Framing capabilities */ PUTSHORT(PPPOL2TP_AVPHEADERFLAG_MANDATORY + 10, p); /* Mandatory flag + len field */ PUTSHORT(0, p); /* Vendor ID */ PUTSHORT(PPPOL2TP_AVPTYPE_FRAMINGCAPABILITIES, p); /* Attribute type: Framing capabilities */ PUTLONG(PPPOL2TP_FRAMINGCAPABILITIES, p); /* Attribute value: Framing capabilities */ /* AVP - Bearer capabilities */ PUTSHORT(PPPOL2TP_AVPHEADERFLAG_MANDATORY + 10, p); /* Mandatory flag + len field */ PUTSHORT(0, p); /* Vendor ID */ PUTSHORT(PPPOL2TP_AVPTYPE_BEARERCAPABILITIES, p); /* Attribute type: Bearer capabilities */ PUTLONG(PPPOL2TP_BEARERCAPABILITIES, p); /* Attribute value: Bearer capabilities */ /* AVP - Host name */ PUTSHORT(PPPOL2TP_AVPHEADERFLAG_MANDATORY + 6+sizeof(PPPOL2TP_HOSTNAME)-1, p); /* Mandatory flag + len field */ PUTSHORT(0, p); /* Vendor ID */ PUTSHORT(PPPOL2TP_AVPTYPE_HOSTNAME, p); /* Attribute type: Hostname */ MEMCPY(p, PPPOL2TP_HOSTNAME, sizeof(PPPOL2TP_HOSTNAME)-1); /* Attribute value: Hostname */ INCPTR(sizeof(PPPOL2TP_HOSTNAME)-1, p); /* AVP - Vendor name */ PUTSHORT(6+sizeof(PPPOL2TP_VENDORNAME)-1, p); /* len field */ PUTSHORT(0, p); /* Vendor ID */ PUTSHORT(PPPOL2TP_AVPTYPE_VENDORNAME, p); /* Attribute type: Vendor name */ MEMCPY(p, PPPOL2TP_VENDORNAME, sizeof(PPPOL2TP_VENDORNAME)-1); /* Attribute value: Vendor name */ INCPTR(sizeof(PPPOL2TP_VENDORNAME)-1, p); /* AVP - Assign tunnel ID */ PUTSHORT(PPPOL2TP_AVPHEADERFLAG_MANDATORY + 8, p); /* Mandatory flag + len field */ PUTSHORT(0, p); /* Vendor ID */ PUTSHORT(PPPOL2TP_AVPTYPE_TUNNELID, p); /* Attribute type: Tunnel ID */ PUTSHORT(l2tp->remote_tunnel_id, p); /* Attribute value: Tunnel ID */ /* AVP - Receive window size */ PUTSHORT(PPPOL2TP_AVPHEADERFLAG_MANDATORY + 8, p); /* Mandatory flag + len field */ PUTSHORT(0, p); /* Vendor ID */ PUTSHORT(PPPOL2TP_AVPTYPE_RECEIVEWINDOWSIZE, p); /* Attribute type: Receive window size */ PUTSHORT(PPPOL2TP_RECEIVEWINDOWSIZE, p); /* Attribute value: Receive window size */ #if PPPOL2TP_AUTH_SUPPORT /* AVP - Challenge */ if (l2tp->secret != NULL) { PUTSHORT(PPPOL2TP_AVPHEADERFLAG_MANDATORY + 6 + sizeof(l2tp->secret_rv), p); /* Mandatory flag + len field */ PUTSHORT(0, p); /* Vendor ID */ PUTSHORT(PPPOL2TP_AVPTYPE_CHALLENGE, p); /* Attribute type: Challenge */ MEMCPY(p, l2tp->secret_rv, sizeof(l2tp->secret_rv)); /* Attribute value: Random vector */ INCPTR(sizeof(l2tp->secret_rv), p); } #endif /* PPPOL2TP_AUTH_SUPPORT */ if(l2tp->netif) { udp_sendto_if(l2tp->udp, pb, &l2tp->remote_ip, l2tp->remote_port, l2tp->netif); } else { udp_sendto(l2tp->udp, pb, &l2tp->remote_ip, l2tp->remote_port); } pbuf_free(pb); return ERR_OK; } /* Complete tunnel establishment */ static err_t pppol2tp_send_scccn(pppol2tp_pcb *l2tp, u16_t ns) { struct pbuf *pb; u8_t *p; u16_t len; /* calculate UDP packet length */ len = 12 +8; #if PPPOL2TP_AUTH_SUPPORT if (l2tp->send_challenge) { len += 6 + sizeof(l2tp->challenge_hash); } #endif /* PPPOL2TP_AUTH_SUPPORT */ /* allocate a buffer */ pb = pbuf_alloc(PBUF_TRANSPORT, len, PBUF_RAM); if (pb == NULL) { return ERR_MEM; } LWIP_ASSERT("pb->tot_len == pb->len", pb->tot_len == pb->len); p = (u8_t*)pb->payload; /* fill in pkt */ /* L2TP control header */ PUTSHORT(PPPOL2TP_HEADERFLAG_CONTROL_MANDATORY, p); PUTSHORT(len, p); /* Length */ PUTSHORT(l2tp->source_tunnel_id, p); /* Tunnel Id */ PUTSHORT(0, p); /* Session Id */ PUTSHORT(ns, p); /* NS Sequence number - to peer */ PUTSHORT(l2tp->peer_ns+1, p); /* NR Sequence number - expected for peer */ /* AVP - Message type */ PUTSHORT(PPPOL2TP_AVPHEADERFLAG_MANDATORY + 8, p); /* Mandatory flag + len field */ PUTSHORT(0, p); /* Vendor ID */ PUTSHORT(PPPOL2TP_AVPTYPE_MESSAGE, p); /* Attribute type: Message Type */ PUTSHORT(PPPOL2TP_MESSAGETYPE_SCCCN, p); /* Attribute value: Message type: SCCCN */ #if PPPOL2TP_AUTH_SUPPORT /* AVP - Challenge response */ if (l2tp->send_challenge) { PUTSHORT(PPPOL2TP_AVPHEADERFLAG_MANDATORY + 6 + sizeof(l2tp->challenge_hash), p); /* Mandatory flag + len field */ PUTSHORT(0, p); /* Vendor ID */ PUTSHORT(PPPOL2TP_AVPTYPE_CHALLENGERESPONSE, p); /* Attribute type: Challenge response */ MEMCPY(p, l2tp->challenge_hash, sizeof(l2tp->challenge_hash)); /* Attribute value: Computed challenge */ INCPTR(sizeof(l2tp->challenge_hash), p); } #endif /* PPPOL2TP_AUTH_SUPPORT */ if(l2tp->netif) { udp_sendto_if(l2tp->udp, pb, &l2tp->remote_ip, l2tp->remote_port, l2tp->netif); } else { udp_sendto(l2tp->udp, pb, &l2tp->remote_ip, l2tp->remote_port); } pbuf_free(pb); return ERR_OK; } /* Initiate a new session */ static err_t pppol2tp_send_icrq(pppol2tp_pcb *l2tp, u16_t ns) { struct pbuf *pb; u8_t *p; u16_t len; u32_t serialnumber; /* calculate UDP packet length */ len = 12 +8 +8 +10; /* allocate a buffer */ pb = pbuf_alloc(PBUF_TRANSPORT, len, PBUF_RAM); if (pb == NULL) { return ERR_MEM; } LWIP_ASSERT("pb->tot_len == pb->len", pb->tot_len == pb->len); p = (u8_t*)pb->payload; /* fill in pkt */ /* L2TP control header */ PUTSHORT(PPPOL2TP_HEADERFLAG_CONTROL_MANDATORY, p); PUTSHORT(len, p); /* Length */ PUTSHORT(l2tp->source_tunnel_id, p); /* Tunnel Id */ PUTSHORT(0, p); /* Session Id */ PUTSHORT(ns, p); /* NS Sequence number - to peer */ PUTSHORT(l2tp->peer_ns+1, p); /* NR Sequence number - expected for peer */ /* AVP - Message type */ PUTSHORT(PPPOL2TP_AVPHEADERFLAG_MANDATORY + 8, p); /* Mandatory flag + len field */ PUTSHORT(0, p); /* Vendor ID */ PUTSHORT(PPPOL2TP_AVPTYPE_MESSAGE, p); /* Attribute type: Message Type */ PUTSHORT(PPPOL2TP_MESSAGETYPE_ICRQ, p); /* Attribute value: Message type: ICRQ */ /* AVP - Assign session ID */ PUTSHORT(PPPOL2TP_AVPHEADERFLAG_MANDATORY + 8, p); /* Mandatory flag + len field */ PUTSHORT(0, p); /* Vendor ID */ PUTSHORT(PPPOL2TP_AVPTYPE_SESSIONID, p); /* Attribute type: Session ID */ PUTSHORT(l2tp->remote_session_id, p); /* Attribute value: Session ID */ /* AVP - Call Serial Number */ PUTSHORT(PPPOL2TP_AVPHEADERFLAG_MANDATORY + 10, p); /* Mandatory flag + len field */ PUTSHORT(0, p); /* Vendor ID */ PUTSHORT(PPPOL2TP_AVPTYPE_CALLSERIALNUMBER, p); /* Attribute type: Serial number */ serialnumber = magic(); PUTLONG(serialnumber, p); /* Attribute value: Serial number */ if(l2tp->netif) { udp_sendto_if(l2tp->udp, pb, &l2tp->remote_ip, l2tp->remote_port, l2tp->netif); } else { udp_sendto(l2tp->udp, pb, &l2tp->remote_ip, l2tp->remote_port); } pbuf_free(pb); return ERR_OK; } /* Complete tunnel establishment */ static err_t pppol2tp_send_iccn(pppol2tp_pcb *l2tp, u16_t ns) { struct pbuf *pb; u8_t *p; u16_t len; /* calculate UDP packet length */ len = 12 +8 +10 +10; /* allocate a buffer */ pb = pbuf_alloc(PBUF_TRANSPORT, len, PBUF_RAM); if (pb == NULL) { return ERR_MEM; } LWIP_ASSERT("pb->tot_len == pb->len", pb->tot_len == pb->len); p = (u8_t*)pb->payload; /* fill in pkt */ /* L2TP control header */ PUTSHORT(PPPOL2TP_HEADERFLAG_CONTROL_MANDATORY, p); PUTSHORT(len, p); /* Length */ PUTSHORT(l2tp->source_tunnel_id, p); /* Tunnel Id */ PUTSHORT(l2tp->source_session_id, p); /* Session Id */ PUTSHORT(ns, p); /* NS Sequence number - to peer */ PUTSHORT(l2tp->peer_ns+1, p); /* NR Sequence number - expected for peer */ /* AVP - Message type */ PUTSHORT(PPPOL2TP_AVPHEADERFLAG_MANDATORY + 8, p); /* Mandatory flag + len field */ PUTSHORT(0, p); /* Vendor ID */ PUTSHORT(PPPOL2TP_AVPTYPE_MESSAGE, p); /* Attribute type: Message Type */ PUTSHORT(PPPOL2TP_MESSAGETYPE_ICCN, p); /* Attribute value: Message type: ICCN */ /* AVP - Framing type */ PUTSHORT(PPPOL2TP_AVPHEADERFLAG_MANDATORY + 10, p); /* Mandatory flag + len field */ PUTSHORT(0, p); /* Vendor ID */ PUTSHORT(PPPOL2TP_AVPTYPE_FRAMINGTYPE, p); /* Attribute type: Framing type */ PUTLONG(PPPOL2TP_FRAMINGTYPE, p); /* Attribute value: Framing type */ /* AVP - TX Connect speed */ PUTSHORT(PPPOL2TP_AVPHEADERFLAG_MANDATORY + 10, p); /* Mandatory flag + len field */ PUTSHORT(0, p); /* Vendor ID */ PUTSHORT(PPPOL2TP_AVPTYPE_TXCONNECTSPEED, p); /* Attribute type: TX Connect speed */ PUTLONG(PPPOL2TP_TXCONNECTSPEED, p); /* Attribute value: TX Connect speed */ if(l2tp->netif) { udp_sendto_if(l2tp->udp, pb, &l2tp->remote_ip, l2tp->remote_port, l2tp->netif); } else { udp_sendto(l2tp->udp, pb, &l2tp->remote_ip, l2tp->remote_port); } pbuf_free(pb); return ERR_OK; } /* Send a ZLB ACK packet */ static err_t pppol2tp_send_zlb(pppol2tp_pcb *l2tp, u16_t ns) { struct pbuf *pb; u8_t *p; u16_t len; /* calculate UDP packet length */ len = 12; /* allocate a buffer */ pb = pbuf_alloc(PBUF_TRANSPORT, len, PBUF_RAM); if (pb == NULL) { return ERR_MEM; } LWIP_ASSERT("pb->tot_len == pb->len", pb->tot_len == pb->len); p = (u8_t*)pb->payload; /* fill in pkt */ /* L2TP control header */ PUTSHORT(PPPOL2TP_HEADERFLAG_CONTROL_MANDATORY, p); PUTSHORT(len, p); /* Length */ PUTSHORT(l2tp->source_tunnel_id, p); /* Tunnel Id */ PUTSHORT(0, p); /* Session Id */ PUTSHORT(ns, p); /* NS Sequence number - to peer */ PUTSHORT(l2tp->peer_ns+1, p); /* NR Sequence number - expected for peer */ if(l2tp->netif) { udp_sendto_if(l2tp->udp, pb, &l2tp->remote_ip, l2tp->remote_port, l2tp->netif); } else { udp_sendto(l2tp->udp, pb, &l2tp->remote_ip, l2tp->remote_port); } pbuf_free(pb); return ERR_OK; } /* Send a StopCCN packet */ static err_t pppol2tp_send_stopccn(pppol2tp_pcb *l2tp, u16_t ns) { struct pbuf *pb; u8_t *p; u16_t len; /* calculate UDP packet length */ len = 12 +8 +8 +8; /* allocate a buffer */ pb = pbuf_alloc(PBUF_TRANSPORT, len, PBUF_RAM); if (pb == NULL) { return ERR_MEM; } LWIP_ASSERT("pb->tot_len == pb->len", pb->tot_len == pb->len); p = (u8_t*)pb->payload; /* fill in pkt */ /* L2TP control header */ PUTSHORT(PPPOL2TP_HEADERFLAG_CONTROL_MANDATORY, p); PUTSHORT(len, p); /* Length */ PUTSHORT(l2tp->source_tunnel_id, p); /* Tunnel Id */ PUTSHORT(0, p); /* Session Id */ PUTSHORT(ns, p); /* NS Sequence number - to peer */ PUTSHORT(l2tp->peer_ns+1, p); /* NR Sequence number - expected for peer */ /* AVP - Message type */ PUTSHORT(PPPOL2TP_AVPHEADERFLAG_MANDATORY + 8, p); /* Mandatory flag + len field */ PUTSHORT(0, p); /* Vendor ID */ PUTSHORT(PPPOL2TP_AVPTYPE_MESSAGE, p); /* Attribute type: Message Type */ PUTSHORT(PPPOL2TP_MESSAGETYPE_STOPCCN, p); /* Attribute value: Message type: StopCCN */ /* AVP - Assign tunnel ID */ PUTSHORT(PPPOL2TP_AVPHEADERFLAG_MANDATORY + 8, p); /* Mandatory flag + len field */ PUTSHORT(0, p); /* Vendor ID */ PUTSHORT(PPPOL2TP_AVPTYPE_TUNNELID, p); /* Attribute type: Tunnel ID */ PUTSHORT(l2tp->remote_tunnel_id, p); /* Attribute value: Tunnel ID */ /* AVP - Result code */ PUTSHORT(PPPOL2TP_AVPHEADERFLAG_MANDATORY + 8, p); /* Mandatory flag + len field */ PUTSHORT(0, p); /* Vendor ID */ PUTSHORT(PPPOL2TP_AVPTYPE_RESULTCODE, p); /* Attribute type: Result code */ PUTSHORT(PPPOL2TP_RESULTCODE, p); /* Attribute value: Result code */ if(l2tp->netif) { udp_sendto_if(l2tp->udp, pb, &l2tp->remote_ip, l2tp->remote_port, l2tp->netif); } else { udp_sendto(l2tp->udp, pb, &l2tp->remote_ip, l2tp->remote_port); } pbuf_free(pb); return ERR_OK; } err_t pppol2tp_xmit(pppol2tp_pcb *l2tp, struct pbuf *pb) { u8_t *p; /* are we ready to process data yet? */ if (l2tp->phase < PPPOL2TP_STATE_DATA) { pbuf_free(pb); return ERR_CONN; } /* make room for L2TP header - should not fail */ if (pbuf_header(pb, PPPOL2TP_OUTPUT_DATA_HEADER_LEN) != 0) { /* bail out */ PPPDEBUG(LOG_ERR, ("pppol2tp: pppol2tp_pcb: could not allocate room for L2TP header\n")); LINK_STATS_INC(link.lenerr); pbuf_free(pb); return ERR_BUF; } p = pb->payload; PUTSHORT(PPPOL2TP_HEADERFLAG_DATA_MANDATORY, p); PUTSHORT(l2tp->source_tunnel_id, p); /* Tunnel Id */ PUTSHORT(l2tp->source_session_id, p); /* Session Id */ if(l2tp->netif) { udp_sendto_if(l2tp->udp, pb, &l2tp->remote_ip, l2tp->remote_port, l2tp->netif); } else { udp_sendto(l2tp->udp, pb, &l2tp->remote_ip, l2tp->remote_port); } pbuf_free(pb); return ERR_OK; } #endif /* PPP_SUPPORT && PPPOL2TP_SUPPORT */ ocproxy-1.60/lwip/src/netif/ppp/upap.c000066400000000000000000000412551303453231400177270ustar00rootroot00000000000000/* * upap.c - User/Password Authentication Protocol. * * Copyright (c) 1984-2000 Carnegie Mellon University. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The name "Carnegie Mellon University" must not be used to * endorse or promote products derived from this software without * prior written permission. For permission or any legal * details, please contact * Office of Technology Transfer * Carnegie Mellon University * 5000 Forbes Avenue * Pittsburgh, PA 15213-3890 * (412) 268-4387, fax: (412) 268-7395 * tech-transfer@andrew.cmu.edu * * 4. Redistributions of any form whatsoever must retain the following * acknowledgment: * "This product includes software developed by Computing Services * at Carnegie Mellon University (http://www.cmu.edu/computing/)." * * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "lwip/opt.h" #if PPP_SUPPORT && PAP_SUPPORT /* don't build if not configured for use in lwipopts.h */ /* * TODO: */ #if 0 /* UNUSED */ #include #include #endif /* UNUSED */ #include "netif/ppp/ppp_impl.h" #include "netif/ppp/upap.h" #if PPP_OPTIONS /* * Command-line options. */ static option_t pap_option_list[] = { { "hide-password", o_bool, &hide_password, "Don't output passwords to log", OPT_PRIO | 1 }, { "show-password", o_bool, &hide_password, "Show password string in debug log messages", OPT_PRIOSUB | 0 }, { "pap-restart", o_int, &upap[0].us_timeouttime, "Set retransmit timeout for PAP", OPT_PRIO }, { "pap-max-authreq", o_int, &upap[0].us_maxtransmits, "Set max number of transmissions for auth-reqs", OPT_PRIO }, { "pap-timeout", o_int, &upap[0].us_reqtimeout, "Set time limit for peer PAP authentication", OPT_PRIO }, { NULL } }; #endif /* PPP_OPTIONS */ /* * Protocol entry points. */ static void upap_init(ppp_pcb *pcb); static void upap_lowerup(ppp_pcb *pcb); static void upap_lowerdown(ppp_pcb *pcb); static void upap_input(ppp_pcb *pcb, u_char *inpacket, int l); static void upap_protrej(ppp_pcb *pcb); #if PRINTPKT_SUPPORT static int upap_printpkt(u_char *p, int plen, void (*printer) (void *, char *, ...), void *arg); #endif /* PRINTPKT_SUPPORT */ const struct protent pap_protent = { PPP_PAP, upap_init, upap_input, upap_protrej, upap_lowerup, upap_lowerdown, NULL, NULL, #if PRINTPKT_SUPPORT upap_printpkt, #endif /* PRINTPKT_SUPPORT */ NULL, 1, #if PRINTPKT_SUPPORT "PAP", NULL, #endif /* PRINTPKT_SUPPORT */ #if PPP_OPTIONS pap_option_list, NULL, #endif /* PPP_OPTIONS */ #if DEMAND_SUPPORT NULL, NULL #endif /* DEMAND_SUPPORT */ }; static void upap_timeout(void *arg); #if PPP_SERVER static void upap_reqtimeout(void *arg); static void upap_rauthreq(ppp_pcb *pcb, u_char *inp, int id, int len); #endif /* PPP_SERVER */ static void upap_rauthack(ppp_pcb *pcb, u_char *inp, int id, int len); static void upap_rauthnak(ppp_pcb *pcb, u_char *inp, int id, int len); static void upap_sauthreq(ppp_pcb *pcb); #if PPP_SERVER static void upap_sresp(ppp_pcb *pcb, u_char code, u_char id, char *msg, int msglen); #endif /* PPP_SERVER */ /* * upap_init - Initialize a UPAP unit. */ static void upap_init(ppp_pcb *pcb) { pcb->upap.us_user = NULL; pcb->upap.us_userlen = 0; pcb->upap.us_passwd = NULL; pcb->upap.us_passwdlen = 0; pcb->upap.us_clientstate = UPAPCS_INITIAL; #if PPP_SERVER pcb->upap.us_serverstate = UPAPSS_INITIAL; #endif /* PPP_SERVER */ pcb->upap.us_id = 0; } /* * upap_authwithpeer - Authenticate us with our peer (start client). * * Set new state and send authenticate's. */ void upap_authwithpeer(ppp_pcb *pcb, char *user, char *password) { if(!user || !password) return; /* Save the username and password we're given */ pcb->upap.us_user = user; pcb->upap.us_userlen = LWIP_MIN(strlen(user), 0xff); pcb->upap.us_passwd = password; pcb->upap.us_passwdlen = LWIP_MIN(strlen(password), 0xff); pcb->upap.us_transmits = 0; /* Lower layer up yet? */ if (pcb->upap.us_clientstate == UPAPCS_INITIAL || pcb->upap.us_clientstate == UPAPCS_PENDING) { pcb->upap.us_clientstate = UPAPCS_PENDING; return; } upap_sauthreq(pcb); /* Start protocol */ } #if PPP_SERVER /* * upap_authpeer - Authenticate our peer (start server). * * Set new state. */ void upap_authpeer(ppp_pcb *pcb) { /* Lower layer up yet? */ if (pcb->upap.us_serverstate == UPAPSS_INITIAL || pcb->upap.us_serverstate == UPAPSS_PENDING) { pcb->upap.us_serverstate = UPAPSS_PENDING; return; } pcb->upap.us_serverstate = UPAPSS_LISTEN; if (pcb->settings.pap_req_timeout > 0) TIMEOUT(upap_reqtimeout, pcb, pcb->settings.pap_req_timeout); } #endif /* PPP_SERVER */ /* * upap_timeout - Retransmission timer for sending auth-reqs expired. */ static void upap_timeout(void *arg) { ppp_pcb *pcb = (ppp_pcb*)arg; if (pcb->upap.us_clientstate != UPAPCS_AUTHREQ) return; if (pcb->upap.us_transmits >= pcb->settings.pap_max_transmits) { /* give up in disgust */ ppp_error("No response to PAP authenticate-requests"); pcb->upap.us_clientstate = UPAPCS_BADAUTH; auth_withpeer_fail(pcb, PPP_PAP); return; } upap_sauthreq(pcb); /* Send Authenticate-Request */ } #if PPP_SERVER /* * upap_reqtimeout - Give up waiting for the peer to send an auth-req. */ static void upap_reqtimeout(void *arg) { ppp_pcb *pcb = (ppp_pcb*)arg; if (pcb->upap.us_serverstate != UPAPSS_LISTEN) return; /* huh?? */ auth_peer_fail(pcb, PPP_PAP); pcb->upap.us_serverstate = UPAPSS_BADAUTH; } #endif /* PPP_SERVER */ /* * upap_lowerup - The lower layer is up. * * Start authenticating if pending. */ static void upap_lowerup(ppp_pcb *pcb) { if (pcb->upap.us_clientstate == UPAPCS_INITIAL) pcb->upap.us_clientstate = UPAPCS_CLOSED; else if (pcb->upap.us_clientstate == UPAPCS_PENDING) { upap_sauthreq(pcb); /* send an auth-request */ } #if PPP_SERVER if (pcb->upap.us_serverstate == UPAPSS_INITIAL) pcb->upap.us_serverstate = UPAPSS_CLOSED; else if (pcb->upap.us_serverstate == UPAPSS_PENDING) { pcb->upap.us_serverstate = UPAPSS_LISTEN; if (pcb->settings.pap_req_timeout > 0) TIMEOUT(upap_reqtimeout, pcb, pcb->settings.pap_req_timeout); } #endif /* PPP_SERVER */ } /* * upap_lowerdown - The lower layer is down. * * Cancel all timeouts. */ static void upap_lowerdown(ppp_pcb *pcb) { if (pcb->upap.us_clientstate == UPAPCS_AUTHREQ) /* Timeout pending? */ UNTIMEOUT(upap_timeout, pcb); /* Cancel timeout */ #if PPP_SERVER if (pcb->upap.us_serverstate == UPAPSS_LISTEN && pcb->settings.pap_req_timeout > 0) UNTIMEOUT(upap_reqtimeout, pcb); #endif /* PPP_SERVER */ pcb->upap.us_clientstate = UPAPCS_INITIAL; #if PPP_SERVER pcb->upap.us_serverstate = UPAPSS_INITIAL; #endif /* PPP_SERVER */ } /* * upap_protrej - Peer doesn't speak this protocol. * * This shouldn't happen. In any case, pretend lower layer went down. */ static void upap_protrej(ppp_pcb *pcb) { if (pcb->upap.us_clientstate == UPAPCS_AUTHREQ) { ppp_error("PAP authentication failed due to protocol-reject"); auth_withpeer_fail(pcb, PPP_PAP); } #if PPP_SERVER if (pcb->upap.us_serverstate == UPAPSS_LISTEN) { ppp_error("PAP authentication of peer failed (protocol-reject)"); auth_peer_fail(pcb, PPP_PAP); } #endif /* PPP_SERVER */ upap_lowerdown(pcb); } /* * upap_input - Input UPAP packet. */ static void upap_input(ppp_pcb *pcb, u_char *inpacket, int l) { u_char *inp; u_char code, id; int len; /* * Parse header (code, id and length). * If packet too short, drop it. */ inp = inpacket; if (l < UPAP_HEADERLEN) { UPAPDEBUG(("pap_input: rcvd short header.")); return; } GETCHAR(code, inp); GETCHAR(id, inp); GETSHORT(len, inp); if (len < UPAP_HEADERLEN) { UPAPDEBUG(("pap_input: rcvd illegal length.")); return; } if (len > l) { UPAPDEBUG(("pap_input: rcvd short packet.")); return; } len -= UPAP_HEADERLEN; /* * Action depends on code. */ switch (code) { case UPAP_AUTHREQ: #if PPP_SERVER upap_rauthreq(pcb, inp, id, len); #endif /* PPP_SERVER */ break; case UPAP_AUTHACK: upap_rauthack(pcb, inp, id, len); break; case UPAP_AUTHNAK: upap_rauthnak(pcb, inp, id, len); break; default: /* XXX Need code reject */ break; } } #if PPP_SERVER /* * upap_rauth - Receive Authenticate. */ static void upap_rauthreq(ppp_pcb *pcb, u_char *inp, int id, int len) { u_char ruserlen, rpasswdlen; char *ruser, *rpasswd; char rhostname[256]; int retcode; char *msg; int msglen; if (pcb->upap.us_serverstate < UPAPSS_LISTEN) return; /* * If we receive a duplicate authenticate-request, we are * supposed to return the same status as for the first request. */ if (pcb->upap.us_serverstate == UPAPSS_OPEN) { upap_sresp(pcb, UPAP_AUTHACK, id, "", 0); /* return auth-ack */ return; } if (pcb->upap.us_serverstate == UPAPSS_BADAUTH) { upap_sresp(pcb, UPAP_AUTHNAK, id, "", 0); /* return auth-nak */ return; } /* * Parse user/passwd. */ if (len < 1) { UPAPDEBUG(("pap_rauth: rcvd short packet.")); return; } GETCHAR(ruserlen, inp); len -= sizeof (u_char) + ruserlen + sizeof (u_char); if (len < 0) { UPAPDEBUG(("pap_rauth: rcvd short packet.")); return; } ruser = (char *) inp; INCPTR(ruserlen, inp); GETCHAR(rpasswdlen, inp); if (len < rpasswdlen) { UPAPDEBUG(("pap_rauth: rcvd short packet.")); return; } /* FIXME: we need a way to check peer secret */ rpasswd = (char *) inp; /* * Check the username and password given. */ #if 0 retcode = check_passwd(pcb->upap.us_unit, ruser, ruserlen, rpasswd, rpasswdlen, &msg); BZERO(rpasswd, rpasswdlen); /* * Check remote number authorization. A plugin may have filled in * the remote number or added an allowed number, and rather than * return an authenticate failure, is leaving it for us to verify. */ if (retcode == UPAP_AUTHACK) { if (!auth_number()) { /* We do not want to leak info about the pap result. */ retcode = UPAP_AUTHNAK; /* XXX exit value will be "wrong" */ warn("calling number %q is not authorized", remote_number); } } #endif msglen = strlen(msg); if (msglen > 255) msglen = 255; upap_sresp(pcb, retcode, id, msg, msglen); /* Null terminate and clean remote name. */ ppp_slprintf(rhostname, sizeof(rhostname), "%.*v", ruserlen, ruser); if (retcode == UPAP_AUTHACK) { pcb->upap.us_serverstate = UPAPSS_OPEN; ppp_notice("PAP peer authentication succeeded for %q", rhostname); auth_peer_success(pcb, PPP_PAP, 0, ruser, ruserlen); } else { pcb->upap.us_serverstate = UPAPSS_BADAUTH; ppp_warn("PAP peer authentication failed for %q", rhostname); auth_peer_fail(pcb, PPP_PAP); } if (pcb->settings.pap_req_timeout > 0) UNTIMEOUT(upap_reqtimeout, pcb); } #endif /* PPP_SERVER */ /* * upap_rauthack - Receive Authenticate-Ack. */ static void upap_rauthack(ppp_pcb *pcb, u_char *inp, int id, int len) { u_char msglen; char *msg; if (pcb->upap.us_clientstate != UPAPCS_AUTHREQ) /* XXX */ return; /* * Parse message. */ if (len < 1) { UPAPDEBUG(("pap_rauthack: ignoring missing msg-length.")); } else { GETCHAR(msglen, inp); if (msglen > 0) { len -= sizeof (u_char); if (len < msglen) { UPAPDEBUG(("pap_rauthack: rcvd short packet.")); return; } msg = (char *) inp; PRINTMSG(msg, msglen); } } pcb->upap.us_clientstate = UPAPCS_OPEN; auth_withpeer_success(pcb, PPP_PAP, 0); } /* * upap_rauthnak - Receive Authenticate-Nak. */ static void upap_rauthnak(ppp_pcb *pcb, u_char *inp, int id, int len) { u_char msglen; char *msg; if (pcb->upap.us_clientstate != UPAPCS_AUTHREQ) /* XXX */ return; /* * Parse message. */ if (len < 1) { UPAPDEBUG(("pap_rauthnak: ignoring missing msg-length.")); } else { GETCHAR(msglen, inp); if (msglen > 0) { len -= sizeof (u_char); if (len < msglen) { UPAPDEBUG(("pap_rauthnak: rcvd short packet.")); return; } msg = (char *) inp; PRINTMSG(msg, msglen); } } pcb->upap.us_clientstate = UPAPCS_BADAUTH; ppp_error("PAP authentication failed"); auth_withpeer_fail(pcb, PPP_PAP); } /* * upap_sauthreq - Send an Authenticate-Request. */ static void upap_sauthreq(ppp_pcb *pcb) { struct pbuf *p; u_char *outp; int outlen; outlen = UPAP_HEADERLEN + 2 * sizeof (u_char) + pcb->upap.us_userlen + pcb->upap.us_passwdlen; p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_HDRLEN +outlen), PPP_CTRL_PBUF_TYPE); if(NULL == p) return; if(p->tot_len != p->len) { pbuf_free(p); return; } outp = p->payload; MAKEHEADER(outp, PPP_PAP); PUTCHAR(UPAP_AUTHREQ, outp); PUTCHAR(++pcb->upap.us_id, outp); PUTSHORT(outlen, outp); PUTCHAR(pcb->upap.us_userlen, outp); MEMCPY(outp, pcb->upap.us_user, pcb->upap.us_userlen); INCPTR(pcb->upap.us_userlen, outp); PUTCHAR(pcb->upap.us_passwdlen, outp); MEMCPY(outp, pcb->upap.us_passwd, pcb->upap.us_passwdlen); ppp_write(pcb, p); TIMEOUT(upap_timeout, pcb, pcb->settings.pap_timeout_time); ++pcb->upap.us_transmits; pcb->upap.us_clientstate = UPAPCS_AUTHREQ; } #if PPP_SERVER /* * upap_sresp - Send a response (ack or nak). */ static void upap_sresp(ppp_pcb *pcb, u_char code, u_char id, char *msg, int msglen) { struct pbuf *p; u_char *outp; int outlen; outlen = UPAP_HEADERLEN + sizeof (u_char) + msglen; p = pbuf_alloc(PBUF_RAW, (u16_t)(PPP_HDRLEN +outlen), PPP_CTRL_PBUF_TYPE); if(NULL == p) return; if(p->tot_len != p->len) { pbuf_free(p); return; } outp = p->payload; MAKEHEADER(outp, PPP_PAP); PUTCHAR(code, outp); PUTCHAR(id, outp); PUTSHORT(outlen, outp); PUTCHAR(msglen, outp); MEMCPY(outp, msg, msglen); ppp_write(pcb, p); } #endif /* PPP_SERVER */ #if PRINTPKT_SUPPORT /* * upap_printpkt - print the contents of a PAP packet. */ static char *upap_codenames[] = { "AuthReq", "AuthAck", "AuthNak" }; static int upap_printpkt(u_char *p, int plen, void (*printer) (void *, char *, ...), void *arg) { int code, id, len; int mlen, ulen, wlen; char *user, *pwd, *msg; u_char *pstart; if (plen < UPAP_HEADERLEN) return 0; pstart = p; GETCHAR(code, p); GETCHAR(id, p); GETSHORT(len, p); if (len < UPAP_HEADERLEN || len > plen) return 0; if (code >= 1 && code <= sizeof(upap_codenames) / sizeof(char *)) printer(arg, " %s", upap_codenames[code-1]); else printer(arg, " code=0x%x", code); printer(arg, " id=0x%x", id); len -= UPAP_HEADERLEN; switch (code) { case UPAP_AUTHREQ: if (len < 1) break; ulen = p[0]; if (len < ulen + 2) break; wlen = p[ulen + 1]; if (len < ulen + wlen + 2) break; user = (char *) (p + 1); pwd = (char *) (p + ulen + 2); p += ulen + wlen + 2; len -= ulen + wlen + 2; printer(arg, " user="); ppp_print_string(user, ulen, printer, arg); printer(arg, " password="); /* FIXME: require ppp_pcb struct as printpkt() argument */ #if 0 if (!pcb->settings.hide_password) #endif ppp_print_string(pwd, wlen, printer, arg); #if 0 else printer(arg, ""); #endif break; case UPAP_AUTHACK: case UPAP_AUTHNAK: if (len < 1) break; mlen = p[0]; if (len < mlen + 1) break; msg = (char *) (p + 1); p += mlen + 1; len -= mlen + 1; printer(arg, " "); ppp_print_string(msg, mlen, printer, arg); break; } /* print the rest of the bytes in the packet */ for (; len > 0; --len) { GETCHAR(code, p); printer(arg, " %.2x", code); } return p - pstart; } #endif /* PRINTPKT_SUPPORT */ #endif /* PPP_SUPPORT && PAP_SUPPORT */ ocproxy-1.60/lwip/src/netif/ppp/utils.c000066400000000000000000000477411303453231400201300ustar00rootroot00000000000000/* * utils.c - various utility functions used in pppd. * * Copyright (c) 1999-2002 Paul Mackerras. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. The name(s) of the authors of this software must not be used to * endorse or promote products derived from this software without * prior written permission. * * 3. Redistributions of any form whatsoever must retain the following * acknowledgment: * "This product includes software developed by Paul Mackerras * ". * * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "lwip/opt.h" #if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */ #if 0 /* UNUSED */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef SVR4 #include #endif #endif /* UNUSED */ #include /* isdigit() */ #include "netif/ppp/ppp_impl.h" #include "netif/ppp/fsm.h" #include "netif/ppp/lcp.h" #if defined(SUNOS4) extern char *strerror(); #endif static void ppp_logit(int level, char *fmt, va_list args); static void ppp_log_write(int level, char *buf); #if PRINTPKT_SUPPORT static void ppp_vslp_printer(void *arg, char *fmt, ...); static void ppp_format_packet(u_char *p, int len, void (*printer) (void *, char *, ...), void *arg); struct buffer_info { char *ptr; int len; }; #endif /* PRINTPKT_SUPPORT */ /* * ppp_strlcpy - like strcpy/strncpy, doesn't overflow destination buffer, * always leaves destination null-terminated (for len > 0). */ size_t ppp_strlcpy(char *dest, const char *src, size_t len) { size_t ret = strlen(src); if (len != 0) { if (ret < len) strcpy(dest, src); else { strncpy(dest, src, len - 1); dest[len-1] = 0; } } return ret; } /* * ppp_strlcat - like strcat/strncat, doesn't overflow destination buffer, * always leaves destination null-terminated (for len > 0). */ size_t ppp_strlcat(char *dest, const char *src, size_t len) { size_t dlen = strlen(dest); return dlen + ppp_strlcpy(dest + dlen, src, (len > dlen? len - dlen: 0)); } /* * ppp_slprintf - format a message into a buffer. Like sprintf except we * also specify the length of the output buffer, and we handle * %m (error message), %v (visible string), * %q (quoted string), %t (current time) and %I (IP address) formats. * Doesn't do floating-point formats. * Returns the number of chars put into buf. */ int ppp_slprintf(char *buf, int buflen, char *fmt, ...) { va_list args; int n; va_start(args, fmt); n = ppp_vslprintf(buf, buflen, fmt, args); va_end(args); return n; } /* * ppp_vslprintf - like ppp_slprintf, takes a va_list instead of a list of args. */ #define OUTCHAR(c) (buflen > 0? (--buflen, *buf++ = (c)): 0) int ppp_vslprintf(char *buf, int buflen, char *fmt, va_list args) { int c, i, n; int width, prec, fillch; int base, len, neg, quoted; unsigned long val = 0; char *str, *f, *buf0; unsigned char *p; char num[32]; #if 0 /* need port */ time_t t; #endif /* need port */ u32_t ip; static char hexchars[] = "0123456789abcdef"; #if PRINTPKT_SUPPORT struct buffer_info bufinfo; #endif /* PRINTPKT_SUPPORT */ buf0 = buf; --buflen; while (buflen > 0) { for (f = fmt; *f != '%' && *f != 0; ++f) ; if (f > fmt) { len = f - fmt; if (len > buflen) len = buflen; memcpy(buf, fmt, len); buf += len; buflen -= len; fmt = f; } if (*fmt == 0) break; c = *++fmt; width = 0; prec = -1; fillch = ' '; if (c == '0') { fillch = '0'; c = *++fmt; } if (c == '*') { width = va_arg(args, int); c = *++fmt; } else { while (isdigit(c)) { width = width * 10 + c - '0'; c = *++fmt; } } if (c == '.') { c = *++fmt; if (c == '*') { prec = va_arg(args, int); c = *++fmt; } else { prec = 0; while (isdigit(c)) { prec = prec * 10 + c - '0'; c = *++fmt; } } } str = 0; base = 0; neg = 0; ++fmt; switch (c) { case 'l': c = *fmt++; switch (c) { case 'd': val = va_arg(args, long); if ((long)val < 0) { neg = 1; val = -val; } base = 10; break; case 'u': val = va_arg(args, unsigned long); base = 10; break; default: OUTCHAR('%'); OUTCHAR('l'); --fmt; /* so %lz outputs %lz etc. */ continue; } break; case 'd': i = va_arg(args, int); if (i < 0) { neg = 1; val = -i; } else val = i; base = 10; break; case 'u': val = va_arg(args, unsigned int); base = 10; break; case 'o': val = va_arg(args, unsigned int); base = 8; break; case 'x': case 'X': val = va_arg(args, unsigned int); base = 16; break; case 'p': val = (unsigned long) va_arg(args, void *); base = 16; neg = 2; break; case 's': str = va_arg(args, char *); break; case 'c': num[0] = va_arg(args, int); num[1] = 0; str = num; break; #if 0 /* do we always have strerror() in embedded ? */ case 'm': str = strerror(errno); break; #endif /* do we always have strerror() in embedded ? */ case 'I': ip = va_arg(args, u32_t); ip = ntohl(ip); ppp_slprintf(num, sizeof(num), "%d.%d.%d.%d", (ip >> 24) & 0xff, (ip >> 16) & 0xff, (ip >> 8) & 0xff, ip & 0xff); str = num; break; #if 0 /* need port */ case 't': time(&t); str = ctime(&t); str += 4; /* chop off the day name */ str[15] = 0; /* chop off year and newline */ break; #endif /* need port */ case 'v': /* "visible" string */ case 'q': /* quoted string */ quoted = c == 'q'; p = va_arg(args, unsigned char *); if (p == NULL) p = (unsigned char *)""; if (fillch == '0' && prec >= 0) { n = prec; } else { n = strlen((char *)p); if (prec >= 0 && n > prec) n = prec; } while (n > 0 && buflen > 0) { c = *p++; --n; if (!quoted && c >= 0x80) { OUTCHAR('M'); OUTCHAR('-'); c -= 0x80; } if (quoted && (c == '"' || c == '\\')) OUTCHAR('\\'); if (c < 0x20 || (0x7f <= c && c < 0xa0)) { if (quoted) { OUTCHAR('\\'); switch (c) { case '\t': OUTCHAR('t'); break; case '\n': OUTCHAR('n'); break; case '\b': OUTCHAR('b'); break; case '\f': OUTCHAR('f'); break; default: OUTCHAR('x'); OUTCHAR(hexchars[c >> 4]); OUTCHAR(hexchars[c & 0xf]); } } else { if (c == '\t') OUTCHAR(c); else { OUTCHAR('^'); OUTCHAR(c ^ 0x40); } } } else OUTCHAR(c); } continue; #if PRINTPKT_SUPPORT case 'P': /* print PPP packet */ bufinfo.ptr = buf; bufinfo.len = buflen + 1; p = va_arg(args, unsigned char *); n = va_arg(args, int); ppp_format_packet(p, n, ppp_vslp_printer, &bufinfo); buf = bufinfo.ptr; buflen = bufinfo.len - 1; continue; #endif /* PRINTPKT_SUPPORT */ case 'B': p = va_arg(args, unsigned char *); for (n = prec; n > 0; --n) { c = *p++; if (fillch == ' ') OUTCHAR(' '); OUTCHAR(hexchars[(c >> 4) & 0xf]); OUTCHAR(hexchars[c & 0xf]); } continue; default: *buf++ = '%'; if (c != '%') --fmt; /* so %z outputs %z etc. */ --buflen; continue; } if (base != 0) { str = num + sizeof(num); *--str = 0; while (str > num + neg) { *--str = hexchars[val % base]; val = val / base; if (--prec <= 0 && val == 0) break; } switch (neg) { case 1: *--str = '-'; break; case 2: *--str = 'x'; *--str = '0'; break; } len = num + sizeof(num) - 1 - str; } else { len = strlen(str); if (prec >= 0 && len > prec) len = prec; } if (width > 0) { if (width > buflen) width = buflen; if ((n = width - len) > 0) { buflen -= n; for (; n > 0; --n) *buf++ = fillch; } } if (len > buflen) len = buflen; memcpy(buf, str, len); buf += len; buflen -= len; } *buf = 0; return buf - buf0; } #if PRINTPKT_SUPPORT /* * vslp_printer - used in processing a %P format */ static void ppp_vslp_printer(void *arg, char *fmt, ...) { int n; va_list pvar; struct buffer_info *bi; va_start(pvar, fmt); bi = (struct buffer_info *) arg; n = ppp_vslprintf(bi->ptr, bi->len, fmt, pvar); va_end(pvar); bi->ptr += n; bi->len -= n; } #endif /* PRINTPKT_SUPPORT */ #if 0 /* UNUSED */ /* * log_packet - format a packet and log it. */ void log_packet(p, len, prefix, level) u_char *p; int len; char *prefix; int level; { init_pr_log(prefix, level); ppp_format_packet(p, len, pr_log, &level); end_pr_log(); } #endif /* UNUSED */ #if PRINTPKT_SUPPORT /* * ppp_format_packet - make a readable representation of a packet, * calling `printer(arg, format, ...)' to output it. */ static void ppp_format_packet(u_char *p, int len, void (*printer) (void *, char *, ...), void *arg) { int i, n; u_short proto; const struct protent *protp; if (len >= 2) { GETSHORT(proto, p); len -= 2; for (i = 0; (protp = protocols[i]) != NULL; ++i) if (proto == protp->protocol) break; if (protp != NULL) { printer(arg, "[%s", protp->name); n = (*protp->printpkt)(p, len, printer, arg); printer(arg, "]"); p += n; len -= n; } else { for (i = 0; (protp = protocols[i]) != NULL; ++i) if (proto == (protp->protocol & ~0x8000)) break; if (protp != 0 && protp->data_name != 0) { printer(arg, "[%s data]", protp->data_name); if (len > 8) printer(arg, "%.8B ...", p); else printer(arg, "%.*B", len, p); len = 0; } else printer(arg, "[proto=0x%x]", proto); } } if (len > 32) printer(arg, "%.32B ...", p); else printer(arg, "%.*B", len, p); } #endif /* PRINTPKT_SUPPORT */ #if 0 /* UNUSED */ /* * init_pr_log, end_pr_log - initialize and finish use of pr_log. */ static char line[256]; /* line to be logged accumulated here */ static char *linep; /* current pointer within line */ static int llevel; /* level for logging */ void init_pr_log(prefix, level) const char *prefix; int level; { linep = line; if (prefix != NULL) { ppp_strlcpy(line, prefix, sizeof(line)); linep = line + strlen(line); } llevel = level; } void end_pr_log() { if (linep != line) { *linep = 0; ppp_log_write(llevel, line); } } /* * pr_log - printer routine for outputting to log */ void pr_log (void *arg, char *fmt, ...) { int l, n; va_list pvar; char *p, *eol; char buf[256]; va_start(pvar, fmt); n = ppp_vslprintf(buf, sizeof(buf), fmt, pvar); va_end(pvar); p = buf; eol = strchr(buf, '\n'); if (linep != line) { l = (eol == NULL)? n: eol - buf; if (linep + l < line + sizeof(line)) { if (l > 0) { memcpy(linep, buf, l); linep += l; } if (eol == NULL) return; p = eol + 1; eol = strchr(p, '\n'); } *linep = 0; ppp_log_write(llevel, line); linep = line; } while (eol != NULL) { *eol = 0; ppp_log_write(llevel, p); p = eol + 1; eol = strchr(p, '\n'); } /* assumes sizeof(buf) <= sizeof(line) */ l = buf + n - p; if (l > 0) { memcpy(line, p, n); linep = line + l; } } #endif /* UNUSED */ /* * ppp_print_string - print a readable representation of a string using * printer. */ void ppp_print_string(char *p, int len, void (*printer) (void *, char *, ...), void *arg) { int c; printer(arg, "\""); for (; len > 0; --len) { c = *p++; if (' ' <= c && c <= '~') { if (c == '\\' || c == '"') printer(arg, "\\"); printer(arg, "%c", c); } else { switch (c) { case '\n': printer(arg, "\\n"); break; case '\r': printer(arg, "\\r"); break; case '\t': printer(arg, "\\t"); break; default: printer(arg, "\\%.3o", c); /* no break */ } } } printer(arg, "\""); } /* * ppp_logit - does the hard work for fatal et al. */ static void ppp_logit(int level, char *fmt, va_list args) { char buf[1024]; ppp_vslprintf(buf, sizeof(buf), fmt, args); ppp_log_write(level, buf); } static void ppp_log_write(int level, char *buf) { PPPDEBUG(level, ("%s\n", buf) ); #if 0 if (log_to_fd >= 0 && (level != LOG_DEBUG || debug)) { int n = strlen(buf); if (n > 0 && buf[n-1] == '\n') --n; if (write(log_to_fd, buf, n) != n || write(log_to_fd, "\n", 1) != 1) log_to_fd = -1; } #endif } /* * ppp_fatal - log an error message and die horribly. */ void ppp_fatal(char *fmt, ...) { va_list pvar; va_start(pvar, fmt); ppp_logit(LOG_ERR, fmt, pvar); va_end(pvar); /* FIXME: find a way to die */ #if 0 die(1); /* as promised */ #endif } /* * ppp_error - log an error message. */ void ppp_error(char *fmt, ...) { va_list pvar; va_start(pvar, fmt); ppp_logit(LOG_ERR, fmt, pvar); va_end(pvar); #if 0 /* UNUSED */ ++error_count; #endif /* UNUSED */ } /* * ppp_warn - log a warning message. */ void ppp_warn(char *fmt, ...) { va_list pvar; va_start(pvar, fmt); ppp_logit(LOG_WARNING, fmt, pvar); va_end(pvar); } /* * ppp_notice - log a notice-level message. */ void ppp_notice(char *fmt, ...) { va_list pvar; va_start(pvar, fmt); ppp_logit(LOG_NOTICE, fmt, pvar); va_end(pvar); } /* * ppp_info - log an informational message. */ void ppp_info(char *fmt, ...) { va_list pvar; va_start(pvar, fmt); ppp_logit(LOG_INFO, fmt, pvar); va_end(pvar); } /* * ppp_dbglog - log a debug message. */ void ppp_dbglog(char *fmt, ...) { va_list pvar; va_start(pvar, fmt); ppp_logit(LOG_DEBUG, fmt, pvar); va_end(pvar); } #if PRINTPKT_SUPPORT /* * ppp_dump_packet - print out a packet in readable form if it is interesting. * Assumes len >= PPP_HDRLEN. */ void ppp_dump_packet(const char *tag, unsigned char *p, int len) { int proto; /* * don't print IPv4 and IPv6 packets. */ proto = (p[0] << 8) + p[1]; if (proto == PPP_IP) return; #if PPP_IPV6_SUPPORT if (proto == PPP_IPV6) return; #endif /* * don't print LCP echo request/reply packets if the link is up. */ if (proto == PPP_LCP && len >= 2 + HEADERLEN) { unsigned char *lcp = p + 2; int l = (lcp[2] << 8) + lcp[3]; if ((lcp[0] == ECHOREQ || lcp[0] == ECHOREP) && l >= HEADERLEN && l <= len - 2) return; } ppp_dbglog("%s %P", tag, p, len); } #endif /* PRINTPKT_SUPPORT */ #if 0 /* Unused */ /* * complete_read - read a full `count' bytes from fd, * unless end-of-file or an error other than EINTR is encountered. */ ssize_t complete_read(int fd, void *buf, size_t count) { size_t done; ssize_t nb; char *ptr = buf; for (done = 0; done < count; ) { nb = read(fd, ptr, count - done); if (nb < 0) { if (errno == EINTR) continue; return -1; } if (nb == 0) break; done += nb; ptr += nb; } return done; } /* Procedures for locking the serial device using a lock file. */ #ifndef LOCK_DIR #ifdef __linux__ #define LOCK_DIR "/var/lock" #else #ifdef SVR4 #define LOCK_DIR "/var/spool/locks" #else #define LOCK_DIR "/var/spool/lock" #endif #endif #endif /* LOCK_DIR */ static char lock_file[MAXPATHLEN]; /* * lock - create a lock file for the named device */ int lock(dev) char *dev; { #ifdef LOCKLIB int result; result = mklock (dev, (void *) 0); if (result == 0) { ppp_strlcpy(lock_file, dev, sizeof(lock_file)); return 0; } if (result > 0) ppp_notice("Device %s is locked by pid %d", dev, result); else ppp_error("Can't create lock file %s", lock_file); return -1; #else /* LOCKLIB */ char lock_buffer[12]; int fd, pid, n; #ifdef SVR4 struct stat sbuf; if (stat(dev, &sbuf) < 0) { ppp_error("Can't get device number for %s: %m", dev); return -1; } if ((sbuf.st_mode & S_IFMT) != S_IFCHR) { ppp_error("Can't lock %s: not a character device", dev); return -1; } ppp_slprintf(lock_file, sizeof(lock_file), "%s/LK.%03d.%03d.%03d", LOCK_DIR, major(sbuf.st_dev), major(sbuf.st_rdev), minor(sbuf.st_rdev)); #else char *p; char lockdev[MAXPATHLEN]; if ((p = strstr(dev, "dev/")) != NULL) { dev = p + 4; strncpy(lockdev, dev, MAXPATHLEN-1); lockdev[MAXPATHLEN-1] = 0; while ((p = strrchr(lockdev, '/')) != NULL) { *p = '_'; } dev = lockdev; } else if ((p = strrchr(dev, '/')) != NULL) dev = p + 1; ppp_slprintf(lock_file, sizeof(lock_file), "%s/LCK..%s", LOCK_DIR, dev); #endif while ((fd = open(lock_file, O_EXCL | O_CREAT | O_RDWR, 0644)) < 0) { if (errno != EEXIST) { ppp_error("Can't create lock file %s: %m", lock_file); break; } /* Read the lock file to find out who has the device locked. */ fd = open(lock_file, O_RDONLY, 0); if (fd < 0) { if (errno == ENOENT) /* This is just a timing problem. */ continue; ppp_error("Can't open existing lock file %s: %m", lock_file); break; } #ifndef LOCK_BINARY n = read(fd, lock_buffer, 11); #else n = read(fd, &pid, sizeof(pid)); #endif /* LOCK_BINARY */ close(fd); fd = -1; if (n <= 0) { ppp_error("Can't read pid from lock file %s", lock_file); break; } /* See if the process still exists. */ #ifndef LOCK_BINARY lock_buffer[n] = 0; pid = atoi(lock_buffer); #endif /* LOCK_BINARY */ if (pid == getpid()) return 1; /* somebody else locked it for us */ if (pid == 0 || (kill(pid, 0) == -1 && errno == ESRCH)) { if (unlink (lock_file) == 0) { ppp_notice("Removed stale lock on %s (pid %d)", dev, pid); continue; } ppp_warn("Couldn't remove stale lock on %s", dev); } else ppp_notice("Device %s is locked by pid %d", dev, pid); break; } if (fd < 0) { lock_file[0] = 0; return -1; } pid = getpid(); #ifndef LOCK_BINARY ppp_slprintf(lock_buffer, sizeof(lock_buffer), "%10d\n", pid); write (fd, lock_buffer, 11); #else write(fd, &pid, sizeof (pid)); #endif close(fd); return 0; #endif } /* * relock - called to update our lockfile when we are about to detach, * thus changing our pid (we fork, the child carries on, and the parent dies). * Note that this is called by the parent, with pid equal to the pid * of the child. This avoids a potential race which would exist if * we had the child rewrite the lockfile (the parent might die first, * and another process could think the lock was stale if it checked * between when the parent died and the child rewrote the lockfile). */ int relock(pid) int pid; { #ifdef LOCKLIB /* XXX is there a way to do this? */ return -1; #else /* LOCKLIB */ int fd; char lock_buffer[12]; if (lock_file[0] == 0) return -1; fd = open(lock_file, O_WRONLY, 0); if (fd < 0) { ppp_error("Couldn't reopen lock file %s: %m", lock_file); lock_file[0] = 0; return -1; } #ifndef LOCK_BINARY ppp_slprintf(lock_buffer, sizeof(lock_buffer), "%10d\n", pid); write (fd, lock_buffer, 11); #else write(fd, &pid, sizeof(pid)); #endif /* LOCK_BINARY */ close(fd); return 0; #endif /* LOCKLIB */ } /* * unlock - remove our lockfile */ void unlock() { if (lock_file[0]) { #ifdef LOCKLIB (void) rmlock(lock_file, (void *) 0); #else unlink(lock_file); #endif lock_file[0] = 0; } } #endif /* Unused */ #endif /* PPP_SUPPORT */ ocproxy-1.60/lwip/src/netif/ppp/vj.c000066400000000000000000000451761303453231400174070ustar00rootroot00000000000000/* * Routines to compress and uncompess tcp packets (for transmission * over low speed serial lines. * * Copyright (c) 1989 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms are permitted * provided that the above copyright notice and this paragraph are * duplicated in all such forms and that any documentation, * advertising materials, and other materials related to such * distribution and use acknowledge that the software was developed * by the University of California, Berkeley. The name of the * University may not be used to endorse or promote products derived * from this software without specific prior written permission. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. * * Van Jacobson (van@helios.ee.lbl.gov), Dec 31, 1989: * Initial distribution. * * Modified June 1993 by Paul Mackerras, paulus@cs.anu.edu.au, * so that the entire packet being decompressed doesn't have * to be in contiguous memory (just the compressed header). * * Modified March 1998 by Guy Lancaster, glanca@gesn.com, * for a 16 bit processor. */ #include "lwip/opt.h" #if PPP_SUPPORT && VJ_SUPPORT /* don't build if not configured for use in lwipopts.h */ #include "netif/ppp/ppp_impl.h" #include "netif/ppp/pppdebug.h" #include "netif/ppp/vj.h" #include #if LINK_STATS #define INCR(counter) ++comp->stats.counter #else #define INCR(counter) #endif void vj_compress_init(struct vjcompress *comp) { register u_char i; register struct cstate *tstate = comp->tstate; #if MAX_SLOTS == 0 memset((char *)comp, 0, sizeof(*comp)); #endif comp->maxSlotIndex = MAX_SLOTS - 1; comp->compressSlot = 0; /* Disable slot ID compression by default. */ for (i = MAX_SLOTS - 1; i > 0; --i) { tstate[i].cs_id = i; tstate[i].cs_next = &tstate[i - 1]; } tstate[0].cs_next = &tstate[MAX_SLOTS - 1]; tstate[0].cs_id = 0; comp->last_cs = &tstate[0]; comp->last_recv = 255; comp->last_xmit = 255; comp->flags = VJF_TOSS; } /* ENCODE encodes a number that is known to be non-zero. ENCODEZ * checks for zero (since zero has to be encoded in the long, 3 byte * form). */ #define ENCODE(n) { \ if ((u_short)(n) >= 256) { \ *cp++ = 0; \ cp[1] = (u_char)(n); \ cp[0] = (u_char)((n) >> 8); \ cp += 2; \ } else { \ *cp++ = (u_char)(n); \ } \ } #define ENCODEZ(n) { \ if ((u_short)(n) >= 256 || (u_short)(n) == 0) { \ *cp++ = 0; \ cp[1] = (u_char)(n); \ cp[0] = (u_char)((n) >> 8); \ cp += 2; \ } else { \ *cp++ = (u_char)(n); \ } \ } #define DECODEL(f) { \ if (*cp == 0) {\ u32_t tmp = ntohl(f) + ((cp[1] << 8) | cp[2]); \ (f) = htonl(tmp); \ cp += 3; \ } else { \ u32_t tmp = ntohl(f) + (u32_t)*cp++; \ (f) = htonl(tmp); \ } \ } #define DECODES(f) { \ if (*cp == 0) {\ u_short tmp = ntohs(f) + (((u_short)cp[1] << 8) | cp[2]); \ (f) = htons(tmp); \ cp += 3; \ } else { \ u_short tmp = ntohs(f) + (u_short)*cp++; \ (f) = htons(tmp); \ } \ } #define DECODEU(f) { \ if (*cp == 0) {\ (f) = htons(((u_short)cp[1] << 8) | cp[2]); \ cp += 3; \ } else { \ (f) = htons((u_short)*cp++); \ } \ } /* * vj_compress_tcp - Attempt to do Van Jacobson header compression on a * packet. This assumes that nb and comp are not null and that the first * buffer of the chain contains a valid IP header. * Return the VJ type code indicating whether or not the packet was * compressed. */ u_int vj_compress_tcp(struct vjcompress *comp, struct pbuf *pb) { register struct ip_hdr *ip = (struct ip_hdr *)pb->payload; register struct cstate *cs = comp->last_cs->cs_next; register u_short hlen = IPH_HL(ip); register struct tcp_hdr *oth; register struct tcp_hdr *th; register u_short deltaS, deltaA = 0; register u_long deltaL; register u_int changes = 0; u_char new_seq[16]; register u_char *cp = new_seq; /* * Check that the packet is IP proto TCP. */ if (IPH_PROTO(ip) != IP_PROTO_TCP) { return (TYPE_IP); } /* * Bail if this is an IP fragment or if the TCP packet isn't * `compressible' (i.e., ACK isn't set or some other control bit is * set). */ if ((IPH_OFFSET(ip) & PP_HTONS(0x3fff)) || pb->tot_len < 40) { return (TYPE_IP); } th = (struct tcp_hdr *)&((long *)ip)[hlen]; if ((TCPH_FLAGS(th) & (TCP_SYN|TCP_FIN|TCP_RST|TCP_ACK)) != TCP_ACK) { return (TYPE_IP); } /* * Packet is compressible -- we're going to send either a * COMPRESSED_TCP or UNCOMPRESSED_TCP packet. Either way we need * to locate (or create) the connection state. Special case the * most recently used connection since it's most likely to be used * again & we don't have to do any reordering if it's used. */ INCR(vjs_packets); if (!ip_addr_cmp(&ip->src, &cs->cs_ip.src) || !ip_addr_cmp(&ip->dest, &cs->cs_ip.dest) || *(long *)th != ((long *)&cs->cs_ip)[IPH_HL(&cs->cs_ip)]) { /* * Wasn't the first -- search for it. * * States are kept in a circularly linked list with * last_cs pointing to the end of the list. The * list is kept in lru order by moving a state to the * head of the list whenever it is referenced. Since * the list is short and, empirically, the connection * we want is almost always near the front, we locate * states via linear search. If we don't find a state * for the datagram, the oldest state is (re-)used. */ register struct cstate *lcs; register struct cstate *lastcs = comp->last_cs; do { lcs = cs; cs = cs->cs_next; INCR(vjs_searches); if (ip_addr_cmp(&ip->src, &cs->cs_ip.src) && ip_addr_cmp(&ip->dest, &cs->cs_ip.dest) && *(long *)th == ((long *)&cs->cs_ip)[IPH_HL(&cs->cs_ip)]) { goto found; } } while (cs != lastcs); /* * Didn't find it -- re-use oldest cstate. Send an * uncompressed packet that tells the other side what * connection number we're using for this conversation. * Note that since the state list is circular, the oldest * state points to the newest and we only need to set * last_cs to update the lru linkage. */ INCR(vjs_misses); comp->last_cs = lcs; hlen += TCPH_HDRLEN(th); hlen <<= 2; /* Check that the IP/TCP headers are contained in the first buffer. */ if (hlen > pb->len) { return (TYPE_IP); } goto uncompressed; found: /* * Found it -- move to the front on the connection list. */ if (cs == lastcs) { comp->last_cs = lcs; } else { lcs->cs_next = cs->cs_next; cs->cs_next = lastcs->cs_next; lastcs->cs_next = cs; } } oth = (struct tcp_hdr *)&((long *)&cs->cs_ip)[hlen]; deltaS = hlen; hlen += TCPH_HDRLEN(th); hlen <<= 2; /* Check that the IP/TCP headers are contained in the first buffer. */ if (hlen > pb->len) { PPPDEBUG(LOG_INFO, ("vj_compress_tcp: header len %d spans buffers\n", hlen)); return (TYPE_IP); } /* * Make sure that only what we expect to change changed. The first * line of the `if' checks the IP protocol version, header length & * type of service. The 2nd line checks the "Don't fragment" bit. * The 3rd line checks the time-to-live and protocol (the protocol * check is unnecessary but costless). The 4th line checks the TCP * header length. The 5th line checks IP options, if any. The 6th * line checks TCP options, if any. If any of these things are * different between the previous & current datagram, we send the * current datagram `uncompressed'. */ if (((u_short *)ip)[0] != ((u_short *)&cs->cs_ip)[0] || ((u_short *)ip)[3] != ((u_short *)&cs->cs_ip)[3] || ((u_short *)ip)[4] != ((u_short *)&cs->cs_ip)[4] || TCPH_HDRLEN(th) != TCPH_HDRLEN(oth) || (deltaS > 5 && BCMP(ip + 1, &cs->cs_ip + 1, (deltaS - 5) << 2)) || (TCPH_HDRLEN(th) > 5 && BCMP(th + 1, oth + 1, (TCPH_HDRLEN(th) - 5) << 2))) { goto uncompressed; } /* * Figure out which of the changing fields changed. The * receiver expects changes in the order: urgent, window, * ack, seq (the order minimizes the number of temporaries * needed in this section of code). */ if (TCPH_FLAGS(th) & TCP_URG) { deltaS = ntohs(th->urgp); ENCODEZ(deltaS); changes |= NEW_U; } else if (th->urgp != oth->urgp) { /* argh! URG not set but urp changed -- a sensible * implementation should never do this but RFC793 * doesn't prohibit the change so we have to deal * with it. */ goto uncompressed; } if ((deltaS = (u_short)(ntohs(th->wnd) - ntohs(oth->wnd))) != 0) { ENCODE(deltaS); changes |= NEW_W; } if ((deltaL = ntohl(th->ackno) - ntohl(oth->ackno)) != 0) { if (deltaL > 0xffff) { goto uncompressed; } deltaA = (u_short)deltaL; ENCODE(deltaA); changes |= NEW_A; } if ((deltaL = ntohl(th->seqno) - ntohl(oth->seqno)) != 0) { if (deltaL > 0xffff) { goto uncompressed; } deltaS = (u_short)deltaL; ENCODE(deltaS); changes |= NEW_S; } switch(changes) { case 0: /* * Nothing changed. If this packet contains data and the * last one didn't, this is probably a data packet following * an ack (normal on an interactive connection) and we send * it compressed. Otherwise it's probably a retransmit, * retransmitted ack or window probe. Send it uncompressed * in case the other side missed the compressed version. */ if (IPH_LEN(ip) != IPH_LEN(&cs->cs_ip) && ntohs(IPH_LEN(&cs->cs_ip)) == hlen) { break; } /* no break */ /* fall through */ case SPECIAL_I: case SPECIAL_D: /* * actual changes match one of our special case encodings -- * send packet uncompressed. */ goto uncompressed; case NEW_S|NEW_A: if (deltaS == deltaA && deltaS == ntohs(IPH_LEN(&cs->cs_ip)) - hlen) { /* special case for echoed terminal traffic */ changes = SPECIAL_I; cp = new_seq; } break; case NEW_S: if (deltaS == ntohs(IPH_LEN(&cs->cs_ip)) - hlen) { /* special case for data xfer */ changes = SPECIAL_D; cp = new_seq; } break; } deltaS = (u_short)(ntohs(IPH_ID(ip)) - ntohs(IPH_ID(&cs->cs_ip))); if (deltaS != 1) { ENCODEZ(deltaS); changes |= NEW_I; } if (TCPH_FLAGS(th) & TCP_PSH) { changes |= TCP_PUSH_BIT; } /* * Grab the cksum before we overwrite it below. Then update our * state with this packet's header. */ deltaA = ntohs(th->chksum); MEMCPY(&cs->cs_ip, ip, hlen); /* * We want to use the original packet as our compressed packet. * (cp - new_seq) is the number of bytes we need for compressed * sequence numbers. In addition we need one byte for the change * mask, one for the connection id and two for the tcp checksum. * So, (cp - new_seq) + 4 bytes of header are needed. hlen is how * many bytes of the original packet to toss so subtract the two to * get the new packet size. */ deltaS = (u_short)(cp - new_seq); if (!comp->compressSlot || comp->last_xmit != cs->cs_id) { comp->last_xmit = cs->cs_id; hlen -= deltaS + 4; if(pbuf_header(pb, -hlen)){ /* Can we cope with this failing? Just assert for now */ LWIP_ASSERT("pbuf_header failed\n", 0); } cp = (u_char *)pb->payload; *cp++ = (u_char)(changes | NEW_C); *cp++ = cs->cs_id; } else { hlen -= deltaS + 3; if(pbuf_header(pb, -hlen)) { /* Can we cope with this failing? Just assert for now */ LWIP_ASSERT("pbuf_header failed\n", 0); } cp = (u_char *)pb->payload; *cp++ = (u_char)changes; } *cp++ = (u_char)(deltaA >> 8); *cp++ = (u_char)deltaA; MEMCPY(cp, new_seq, deltaS); INCR(vjs_compressed); return (TYPE_COMPRESSED_TCP); /* * Update connection state cs & send uncompressed packet (that is, * a regular ip/tcp packet but with the 'conversation id' we hope * to use on future compressed packets in the protocol field). */ uncompressed: MEMCPY(&cs->cs_ip, ip, hlen); IPH_PROTO_SET(ip, cs->cs_id); comp->last_xmit = cs->cs_id; return (TYPE_UNCOMPRESSED_TCP); } /* * Called when we may have missed a packet. */ void vj_uncompress_err(struct vjcompress *comp) { comp->flags |= VJF_TOSS; INCR(vjs_errorin); } /* * "Uncompress" a packet of type TYPE_UNCOMPRESSED_TCP. * Return 0 on success, -1 on failure. */ int vj_uncompress_uncomp(struct pbuf *nb, struct vjcompress *comp) { register u_int hlen; register struct cstate *cs; register struct ip_hdr *ip; ip = (struct ip_hdr *)nb->payload; hlen = IPH_HL(ip) << 2; if (IPH_PROTO(ip) >= MAX_SLOTS || hlen + sizeof(struct tcp_hdr) > nb->len || (hlen += TCPH_HDRLEN(((struct tcp_hdr *)&((char *)ip)[hlen])) << 2) > nb->len || hlen > MAX_HDR) { PPPDEBUG(LOG_INFO, ("vj_uncompress_uncomp: bad cid=%d, hlen=%d buflen=%d\n", IPH_PROTO(ip), hlen, nb->len)); comp->flags |= VJF_TOSS; INCR(vjs_errorin); return -1; } cs = &comp->rstate[comp->last_recv = IPH_PROTO(ip)]; comp->flags &=~ VJF_TOSS; IPH_PROTO_SET(ip, IP_PROTO_TCP); MEMCPY(&cs->cs_ip, ip, hlen); cs->cs_hlen = (u_short)hlen; INCR(vjs_uncompressedin); return 0; } /* * Uncompress a packet of type TYPE_COMPRESSED_TCP. * The packet is composed of a buffer chain and the first buffer * must contain an accurate chain length. * The first buffer must include the entire compressed TCP/IP header. * This procedure replaces the compressed header with the uncompressed * header and returns the length of the VJ header. */ int vj_uncompress_tcp(struct pbuf **nb, struct vjcompress *comp) { u_char *cp; struct tcp_hdr *th; struct cstate *cs; u_short *bp; struct pbuf *n0 = *nb; u32_t tmp; u_int vjlen, hlen, changes; INCR(vjs_compressedin); cp = (u_char *)n0->payload; changes = *cp++; if (changes & NEW_C) { /* * Make sure the state index is in range, then grab the state. * If we have a good state index, clear the 'discard' flag. */ if (*cp >= MAX_SLOTS) { PPPDEBUG(LOG_INFO, ("vj_uncompress_tcp: bad cid=%d\n", *cp)); goto bad; } comp->flags &=~ VJF_TOSS; comp->last_recv = *cp++; } else { /* * this packet has an implicit state index. If we've * had a line error since the last time we got an * explicit state index, we have to toss the packet. */ if (comp->flags & VJF_TOSS) { PPPDEBUG(LOG_INFO, ("vj_uncompress_tcp: tossing\n")); INCR(vjs_tossed); return (-1); } } cs = &comp->rstate[comp->last_recv]; hlen = IPH_HL(&cs->cs_ip) << 2; th = (struct tcp_hdr *)&((u_char *)&cs->cs_ip)[hlen]; th->chksum = htons((*cp << 8) | cp[1]); cp += 2; if (changes & TCP_PUSH_BIT) { TCPH_SET_FLAG(th, TCP_PSH); } else { TCPH_UNSET_FLAG(th, TCP_PSH); } switch (changes & SPECIALS_MASK) { case SPECIAL_I: { register u32_t i = ntohs(IPH_LEN(&cs->cs_ip)) - cs->cs_hlen; /* some compilers can't nest inline assembler.. */ tmp = ntohl(th->ackno) + i; th->ackno = htonl(tmp); tmp = ntohl(th->seqno) + i; th->seqno = htonl(tmp); } break; case SPECIAL_D: /* some compilers can't nest inline assembler.. */ tmp = ntohl(th->seqno) + ntohs(IPH_LEN(&cs->cs_ip)) - cs->cs_hlen; th->seqno = htonl(tmp); break; default: if (changes & NEW_U) { TCPH_SET_FLAG(th, TCP_URG); DECODEU(th->urgp); } else { TCPH_UNSET_FLAG(th, TCP_URG); } if (changes & NEW_W) { DECODES(th->wnd); } if (changes & NEW_A) { DECODEL(th->ackno); } if (changes & NEW_S) { DECODEL(th->seqno); } break; } if (changes & NEW_I) { DECODES(cs->cs_ip._id); } else { IPH_ID_SET(&cs->cs_ip, ntohs(IPH_ID(&cs->cs_ip)) + 1); IPH_ID_SET(&cs->cs_ip, htons(IPH_ID(&cs->cs_ip))); } /* * At this point, cp points to the first byte of data in the * packet. Fill in the IP total length and update the IP * header checksum. */ vjlen = (u_short)(cp - (u_char*)n0->payload); if (n0->len < vjlen) { /* * We must have dropped some characters (crc should detect * this but the old slip framing won't) */ PPPDEBUG(LOG_INFO, ("vj_uncompress_tcp: head buffer %d too short %d\n", n0->len, vjlen)); goto bad; } #if BYTE_ORDER == LITTLE_ENDIAN tmp = n0->tot_len - vjlen + cs->cs_hlen; IPH_LEN_SET(&cs->cs_ip, htons((u_short)tmp)); #else IPH_LEN_SET(&cs->cs_ip, htons(n0->tot_len - vjlen + cs->cs_hlen)); #endif /* recompute the ip header checksum */ bp = (u_short *) &cs->cs_ip; IPH_CHKSUM_SET(&cs->cs_ip, 0); for (tmp = 0; hlen > 0; hlen -= 2) { tmp += *bp++; } tmp = (tmp & 0xffff) + (tmp >> 16); tmp = (tmp & 0xffff) + (tmp >> 16); IPH_CHKSUM_SET(&cs->cs_ip, (u_short)(~tmp)); /* Remove the compressed header and prepend the uncompressed header. */ if(pbuf_header(n0, -((s16_t)(vjlen)))) { /* Can we cope with this failing? Just assert for now */ LWIP_ASSERT("pbuf_header failed\n", 0); goto bad; } if(LWIP_MEM_ALIGN(n0->payload) != n0->payload) { struct pbuf *np, *q; u8_t *bufptr; #if IP_FORWARD /* If IP forwarding is enabled we are using a PBUF_LINK packet type so * the packet is being allocated with enough header space to be * forwarded (to Ethernet for example). */ np = pbuf_alloc(PBUF_LINK, n0->len + cs->cs_hlen, PBUF_POOL); #else /* IP_FORWARD */ np = pbuf_alloc(PBUF_RAW, n0->len + cs->cs_hlen, PBUF_POOL); #endif /* IP_FORWARD */ if(!np) { PPPDEBUG(LOG_WARNING, ("vj_uncompress_tcp: realign failed\n")); goto bad; } if(pbuf_header(np, -cs->cs_hlen)) { /* Can we cope with this failing? Just assert for now */ LWIP_ASSERT("pbuf_header failed\n", 0); goto bad; } bufptr = n0->payload; for(q = np; q != NULL; q = q->next) { MEMCPY(q->payload, bufptr, q->len); bufptr += q->len; } if(n0->next) { pbuf_chain(np, n0->next); pbuf_dechain(n0); } pbuf_free(n0); n0 = np; } if(pbuf_header(n0, cs->cs_hlen)) { struct pbuf *np; LWIP_ASSERT("vj_uncompress_tcp: cs->cs_hlen <= PBUF_POOL_BUFSIZE", cs->cs_hlen <= PBUF_POOL_BUFSIZE); np = pbuf_alloc(PBUF_RAW, cs->cs_hlen, PBUF_POOL); if(!np) { PPPDEBUG(LOG_WARNING, ("vj_uncompress_tcp: prepend failed\n")); goto bad; } pbuf_cat(np, n0); n0 = np; } LWIP_ASSERT("n0->len >= cs->cs_hlen", n0->len >= cs->cs_hlen); MEMCPY(n0->payload, &cs->cs_ip, cs->cs_hlen); *nb = n0; return vjlen; bad: comp->flags |= VJF_TOSS; INCR(vjs_errorin); return (-1); } #endif /* PPP_SUPPORT && VJ_SUPPORT */ ocproxy-1.60/lwip/src/netif/slipif.c000066400000000000000000000367001303453231400174500ustar00rootroot00000000000000/** * @file * SLIP Interface * */ /* * Copyright (c) 2001-2004 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the Institute nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * This file is built upon the file: src/arch/rtxc/netif/sioslip.c * * Author: Magnus Ivarsson * Simon Goldschmidt * * Usage: This netif can be used in three ways: * 1) For NO_SYS==0, an RX thread can be used which blocks on sio_read() * until data is received. * 2) In your main loop, call slipif_poll() to check for new RX bytes, * completed packets are fed into netif->input(). * 3) Call slipif_received_byte[s]() from your serial RX ISR and * slipif_process_rxqueue() from your main loop. ISR level decodes * packets and puts completed packets on a queue which is fed into * the stack from the main loop (needs SYS_LIGHTWEIGHT_PROT for * pbuf_alloc to work on ISR level!). * */ /* * This is an arch independent SLIP netif. The specific serial hooks must be * provided by another file. They are sio_open, sio_read/sio_tryread and sio_send */ #include "netif/slipif.h" #include "lwip/opt.h" #if LWIP_HAVE_SLIPIF #include "lwip/def.h" #include "lwip/pbuf.h" #include "lwip/stats.h" #include "lwip/snmp.h" #include "lwip/sio.h" #include "lwip/sys.h" #define SLIP_END 0xC0 /* 0300: start and end of every packet */ #define SLIP_ESC 0xDB /* 0333: escape start (one byte escaped data follows) */ #define SLIP_ESC_END 0xDC /* 0334: following escape: original byte is 0xC0 (END) */ #define SLIP_ESC_ESC 0xDD /* 0335: following escape: original byte is 0xDB (ESC) */ /** Maximum packet size that is received by this netif */ #ifndef SLIP_MAX_SIZE #define SLIP_MAX_SIZE 1500 #endif /** Define this to the interface speed for SNMP * (sio_fd is the sio_fd_t returned by sio_open). * The default value of zero means 'unknown'. */ #ifndef SLIP_SIO_SPEED #define SLIP_SIO_SPEED(sio_fd) 0 #endif enum slipif_recv_state { SLIP_RECV_NORMAL, SLIP_RECV_ESCAPE, }; struct slipif_priv { sio_fd_t sd; /* q is the whole pbuf chain for a packet, p is the current pbuf in the chain */ struct pbuf *p, *q; u8_t state; u16_t i, recved; #if SLIP_RX_FROM_ISR struct pbuf *rxpackets; #endif }; /** * Send a pbuf doing the necessary SLIP encapsulation * * Uses the serial layer's sio_send() * * @param netif the lwip network interface structure for this slipif * @param p the pbuf chaing packet to send * @return always returns ERR_OK since the serial layer does not provide return values */ static err_t slipif_output(struct netif *netif, struct pbuf *p) { struct slipif_priv *priv; struct pbuf *q; u16_t i; u8_t c; LWIP_ASSERT("netif != NULL", (netif != NULL)); LWIP_ASSERT("netif->state != NULL", (netif->state != NULL)); LWIP_ASSERT("p != NULL", (p != NULL)); LWIP_DEBUGF(SLIP_DEBUG, ("slipif_output(%"U16_F"): sending %"U16_F" bytes\n", (u16_t)netif->num, p->tot_len)); priv = netif->state; /* Send pbuf out on the serial I/O device. */ /* Start with packet delimiter. */ sio_send(SLIP_END, priv->sd); for (q = p; q != NULL; q = q->next) { for (i = 0; i < q->len; i++) { c = ((u8_t *)q->payload)[i]; switch (c) { case SLIP_END: /* need to escape this byte (0xC0 -> 0xDB, 0xDC) */ sio_send(SLIP_ESC, priv->sd); sio_send(SLIP_ESC_END, priv->sd); break; case SLIP_ESC: /* need to escape this byte (0xDB -> 0xDB, 0xDD) */ sio_send(SLIP_ESC, priv->sd); sio_send(SLIP_ESC_ESC, priv->sd); break; default: /* normal byte - no need for escaping */ sio_send(c, priv->sd); break; } } } /* End with packet delimiter. */ sio_send(SLIP_END, priv->sd); return ERR_OK; } /** * Send a pbuf doing the necessary SLIP encapsulation * * Uses the serial layer's sio_send() * * @param netif the lwip network interface structure for this slipif * @param p the pbuf chaing packet to send * @param ipaddr the ip address to send the packet to (not used for slipif) * @return always returns ERR_OK since the serial layer does not provide return values */ static err_t slipif_output_v4(struct netif *netif, struct pbuf *p, ip_addr_t *ipaddr) { LWIP_UNUSED_ARG(ipaddr); return slipif_output(netif, p); } #if LWIP_IPV6 /** * Send a pbuf doing the necessary SLIP encapsulation * * Uses the serial layer's sio_send() * * @param netif the lwip network interface structure for this slipif * @param p the pbuf chaing packet to send * @param ipaddr the ip address to send the packet to (not used for slipif) * @return always returns ERR_OK since the serial layer does not provide return values */ static err_t slipif_output_v6(struct netif *netif, struct pbuf *p, ip6_addr_t *ipaddr) { LWIP_UNUSED_ARG(ipaddr); return slipif_output(netif, p); } #endif /* LWIP_IPV6 */ /** * Handle the incoming SLIP stream character by character * * @param netif the lwip network interface structure for this slipif * @param c received character (multiple calls to this function will * return a complete packet, NULL is returned before - used for polling) * @return The IP packet when SLIP_END is received */ static struct pbuf* slipif_rxbyte(struct netif *netif, u8_t c) { struct slipif_priv *priv; struct pbuf *t; LWIP_ASSERT("netif != NULL", (netif != NULL)); LWIP_ASSERT("netif->state != NULL", (netif->state != NULL)); priv = netif->state; switch (priv->state) { case SLIP_RECV_NORMAL: switch (c) { case SLIP_END: if (priv->recved > 0) { /* Received whole packet. */ /* Trim the pbuf to the size of the received packet. */ pbuf_realloc(priv->q, priv->recved); LINK_STATS_INC(link.recv); LWIP_DEBUGF(SLIP_DEBUG, ("slipif: Got packet (%"U16_F" bytes)\n", priv->recved)); t = priv->q; priv->p = priv->q = NULL; priv->i = priv->recved = 0; return t; } return NULL; case SLIP_ESC: priv->state = SLIP_RECV_ESCAPE; return NULL; } /* end switch (c) */ break; case SLIP_RECV_ESCAPE: /* un-escape END or ESC bytes, leave other bytes (although that would be a protocol error) */ switch (c) { case SLIP_ESC_END: c = SLIP_END; break; case SLIP_ESC_ESC: c = SLIP_ESC; break; } priv->state = SLIP_RECV_NORMAL; break; } /* end switch (priv->state) */ /* byte received, packet not yet completely received */ if (priv->p == NULL) { /* allocate a new pbuf */ LWIP_DEBUGF(SLIP_DEBUG, ("slipif_input: alloc\n")); priv->p = pbuf_alloc(PBUF_LINK, (PBUF_POOL_BUFSIZE - PBUF_LINK_HLEN), PBUF_POOL); if (priv->p == NULL) { LINK_STATS_INC(link.drop); LWIP_DEBUGF(SLIP_DEBUG, ("slipif_input: no new pbuf! (DROP)\n")); /* don't process any further since we got no pbuf to receive to */ return NULL; } if (priv->q != NULL) { /* 'chain' the pbuf to the existing chain */ pbuf_cat(priv->q, priv->p); } else { /* p is the first pbuf in the chain */ priv->q = priv->p; } } /* this automatically drops bytes if > SLIP_MAX_SIZE */ if ((priv->p != NULL) && (priv->recved <= SLIP_MAX_SIZE)) { ((u8_t *)priv->p->payload)[priv->i] = c; priv->recved++; priv->i++; if (priv->i >= priv->p->len) { /* on to the next pbuf */ priv->i = 0; if (priv->p->next != NULL && priv->p->next->len > 0) { /* p is a chain, on to the next in the chain */ priv->p = priv->p->next; } else { /* p is a single pbuf, set it to NULL so next time a new * pbuf is allocated */ priv->p = NULL; } } } return NULL; } /** Like slipif_rxbyte, but passes completed packets to netif->input * * @param netif The lwip network interface structure for this slipif * @param data received character */ static void slipif_rxbyte_input(struct netif *netif, u8_t c) { struct pbuf *p; p = slipif_rxbyte(netif, c); if (p != NULL) { if (netif->input(p, netif) != ERR_OK) { pbuf_free(p); } } } #if SLIP_USE_RX_THREAD /** * The SLIP input thread. * * Feed the IP layer with incoming packets * * @param nf the lwip network interface structure for this slipif */ static void slipif_loop_thread(void *nf) { u8_t c; struct netif *netif = (struct netif *)nf; struct slipif_priv *priv = (struct slipif_priv *)netif->state; while (1) { if (sio_read(priv->sd, &c, 1) > 0) { slipif_rxbyte_input(netif, c); } } } #endif /* SLIP_USE_RX_THREAD */ /** * SLIP netif initialization * * Call the arch specific sio_open and remember * the opened device in the state field of the netif. * * @param netif the lwip network interface structure for this slipif * @return ERR_OK if serial line could be opened, * ERR_MEM if no memory could be allocated, * ERR_IF is serial line couldn't be opened * * @note netif->num must contain the number of the serial port to open * (0 by default). If netif->state is != NULL, it is interpreted as an * u8_t pointer pointing to the serial port number instead of netif->num. * */ err_t slipif_init(struct netif *netif) { struct slipif_priv *priv; u8_t sio_num; LWIP_DEBUGF(SLIP_DEBUG, ("slipif_init: netif->num=%"U16_F"\n", (u16_t)netif->num)); /* Allocate private data */ priv = (struct slipif_priv *)mem_malloc(sizeof(struct slipif_priv)); if (!priv) { return ERR_MEM; } netif->name[0] = 's'; netif->name[1] = 'l'; netif->output = slipif_output_v4; #if LWIP_IPV6 netif->output_ip6 = slipif_output_v6; #endif /* LWIP_IPV6 */ netif->mtu = SLIP_MAX_SIZE; netif->flags |= NETIF_FLAG_POINTTOPOINT; /* netif->state or netif->num contain the port number */ if (netif->state != NULL) { sio_num = *(u8_t*)netif->state; } else { sio_num = netif->num; } /* Try to open the serial port. */ priv->sd = sio_open(sio_num); if (!priv->sd) { /* Opening the serial port failed. */ mem_free(priv); return ERR_IF; } /* Initialize private data */ priv->p = NULL; priv->q = NULL; priv->state = SLIP_RECV_NORMAL; priv->i = 0; priv->recved = 0; #if SLIP_RX_FROM_ISR priv->rxpackets = NULL; #endif netif->state = priv; /* initialize the snmp variables and counters inside the struct netif */ NETIF_INIT_SNMP(netif, snmp_ifType_slip, SLIP_SIO_SPEED(priv->sd)); #if SLIP_USE_RX_THREAD /* Create a thread to poll the serial line. */ sys_thread_new(SLIPIF_THREAD_NAME, slipif_loop_thread, netif, SLIPIF_THREAD_STACKSIZE, SLIPIF_THREAD_PRIO); #endif /* SLIP_USE_RX_THREAD */ return ERR_OK; } /** * Polls the serial device and feeds the IP layer with incoming packets. * * @param netif The lwip network interface structure for this slipif */ void slipif_poll(struct netif *netif) { u8_t c; struct slipif_priv *priv; LWIP_ASSERT("netif != NULL", (netif != NULL)); LWIP_ASSERT("netif->state != NULL", (netif->state != NULL)); priv = (struct slipif_priv *)netif->state; while (sio_tryread(priv->sd, &c, 1) > 0) { slipif_rxbyte_input(netif, c); } } #if SLIP_RX_FROM_ISR /** * Feeds the IP layer with incoming packets that were receive * * @param netif The lwip network interface structure for this slipif */ void slipif_process_rxqueue(struct netif *netif) { struct slipif_priv *priv; SYS_ARCH_DECL_PROTECT(old_level); LWIP_ASSERT("netif != NULL", (netif != NULL)); LWIP_ASSERT("netif->state != NULL", (netif->state != NULL)); priv = (struct slipif_priv *)netif->state; SYS_ARCH_PROTECT(old_level); while (priv->rxpackets != NULL) { struct pbuf *p = priv->rxpackets; #if SLIP_RX_QUEUE /* dequeue packet */ struct pbuf *q = p; while ((q->len != q->tot_len) && (q->next != NULL)) { q = q->next; } priv->rxpackets = q->next; q->next = NULL; #else /* SLIP_RX_QUEUE */ priv->rxpackets = NULL; #endif /* SLIP_RX_QUEUE */ SYS_ARCH_UNPROTECT(old_level); if (netif->input(p, netif) != ERR_OK) { pbuf_free(p); } SYS_ARCH_PROTECT(old_level); } } /** Like slipif_rxbyte, but queues completed packets. * * @param netif The lwip network interface structure for this slipif * @param data Received serial byte */ static void slipif_rxbyte_enqueue(struct netif *netif, u8_t data) { struct pbuf *p; struct slipif_priv *priv = (struct slipif_priv *)netif->state; SYS_ARCH_DECL_PROTECT(old_level); p = slipif_rxbyte(netif, data); if (p != NULL) { SYS_ARCH_PROTECT(old_level); if (priv->rxpackets != NULL) { #if SLIP_RX_QUEUE /* queue multiple pbufs */ struct pbuf *q = p; while(q->next != NULL) { q = q->next; } q->next = p; } else { #else /* SLIP_RX_QUEUE */ pbuf_free(priv->rxpackets); } { #endif /* SLIP_RX_QUEUE */ priv->rxpackets = p; } SYS_ARCH_UNPROTECT(old_level); } } /** * Process a received byte, completed packets are put on a queue that is * fed into IP through slipif_process_rxqueue(). * * This function can be called from ISR if SYS_LIGHTWEIGHT_PROT is enabled. * * @param netif The lwip network interface structure for this slipif * @param data received character */ void slipif_received_byte(struct netif *netif, u8_t data) { LWIP_ASSERT("netif != NULL", (netif != NULL)); LWIP_ASSERT("netif->state != NULL", (netif->state != NULL)); slipif_rxbyte_enqueue(netif, data); } /** * Process multiple received byte, completed packets are put on a queue that is * fed into IP through slipif_process_rxqueue(). * * This function can be called from ISR if SYS_LIGHTWEIGHT_PROT is enabled. * * @param netif The lwip network interface structure for this slipif * @param data received character * @param len Number of received characters */ void slipif_received_bytes(struct netif *netif, u8_t *data, u8_t len) { u8_t i; u8_t *rxdata = data; LWIP_ASSERT("netif != NULL", (netif != NULL)); LWIP_ASSERT("netif->state != NULL", (netif->state != NULL)); for (i = 0; i < len; i++, rxdata++) { slipif_rxbyte_enqueue(netif, *rxdata); } } #endif /* SLIP_RX_FROM_ISR */ #endif /* LWIP_HAVE_SLIPIF */ ocproxy-1.60/lwip/test/000077500000000000000000000000001303453231400150735ustar00rootroot00000000000000ocproxy-1.60/lwip/test/unit/000077500000000000000000000000001303453231400160525ustar00rootroot00000000000000ocproxy-1.60/lwip/test/unit/core/000077500000000000000000000000001303453231400170025ustar00rootroot00000000000000ocproxy-1.60/lwip/test/unit/core/test_mem.c000066400000000000000000000025221303453231400207640ustar00rootroot00000000000000#include "test_mem.h" #include "lwip/mem.h" #include "lwip/stats.h" #if !LWIP_STATS || !MEM_STATS #error "This tests needs MEM-statistics enabled" #endif #if LWIP_DNS #error "This test needs DNS turned off (as it mallocs on init)" #endif /* Setups/teardown functions */ static void mem_setup(void) { } static void mem_teardown(void) { } /* Test functions */ /** Call mem_malloc, mem_free and mem_trim and check stats */ START_TEST(test_mem_one) { #define SIZE1 16 #define SIZE1_2 12 #define SIZE2 16 void *p1, *p2; mem_size_t s1, s2; LWIP_UNUSED_ARG(_i); #if LWIP_DNS fail("This test needs DNS turned off (as it mallocs on init)"); #endif fail_unless(lwip_stats.mem.used == 0); p1 = mem_malloc(SIZE1); fail_unless(p1 != NULL); fail_unless(lwip_stats.mem.used >= SIZE1); s1 = lwip_stats.mem.used; p2 = mem_malloc(SIZE2); fail_unless(p2 != NULL); fail_unless(lwip_stats.mem.used >= SIZE2 + s1); s2 = lwip_stats.mem.used; mem_trim(p1, SIZE1_2); mem_free(p2); fail_unless(lwip_stats.mem.used <= s2 - SIZE2); mem_free(p1); fail_unless(lwip_stats.mem.used == 0); } END_TEST /** Create the suite including all tests for this module */ Suite * mem_suite(void) { testfunc tests[] = { TESTFUNC(test_mem_one) }; return create_suite("MEM", tests, sizeof(tests)/sizeof(testfunc), mem_setup, mem_teardown); } ocproxy-1.60/lwip/test/unit/core/test_mem.h000066400000000000000000000001711303453231400207670ustar00rootroot00000000000000#ifndef LWIP_HDR_TEST_MEM_H__ #define LWIP_HDR_TEST_MEM_H__ #include "../lwip_check.h" Suite *mem_suite(void); #endif ocproxy-1.60/lwip/test/unit/core/test_pbuf.c000066400000000000000000000075451303453231400211540ustar00rootroot00000000000000#include "test_pbuf.h" #include "lwip/pbuf.h" #include "lwip/stats.h" #if !LWIP_STATS || !MEM_STATS ||!MEMP_STATS #error "This tests needs MEM- and MEMP-statistics enabled" #endif #if LWIP_DNS #error "This test needs DNS turned off (as it mallocs on init)" #endif #if !LWIP_TCP || !TCP_QUEUE_OOSEQ || !LWIP_WND_SCALE #error "This test needs TCP OOSEQ queueing and window scaling enabled" #endif /* Setups/teardown functions */ static void pbuf_setup(void) { } static void pbuf_teardown(void) { } #define TESTBUFSIZE_1 65535 #define TESTBUFSIZE_2 65530 #define TESTBUFSIZE_3 50050 static u8_t testbuf_1[TESTBUFSIZE_1]; static u8_t testbuf_1a[TESTBUFSIZE_1]; static u8_t testbuf_2[TESTBUFSIZE_2]; static u8_t testbuf_2a[TESTBUFSIZE_2]; static u8_t testbuf_3[TESTBUFSIZE_3]; static u8_t testbuf_3a[TESTBUFSIZE_3]; /* Test functions */ /** Call pbuf_copy on a pbuf with zero length */ START_TEST(test_pbuf_copy_zero_pbuf) { struct pbuf *p1, *p2, *p3; err_t err; LWIP_UNUSED_ARG(_i); fail_unless(lwip_stats.mem.used == 0); fail_unless(lwip_stats.memp[MEMP_PBUF_POOL].used == 0); p1 = pbuf_alloc(PBUF_RAW, 1024, PBUF_RAM); fail_unless(p1 != NULL); fail_unless(p1->ref == 1); p2 = pbuf_alloc(PBUF_RAW, 2, PBUF_POOL); fail_unless(p2 != NULL); fail_unless(p2->ref == 1); p2->len = p2->tot_len = 0; pbuf_cat(p1, p2); fail_unless(p1->ref == 1); fail_unless(p2->ref == 1); p3 = pbuf_alloc(PBUF_RAW, p1->tot_len, PBUF_POOL); err = pbuf_copy(p3, p1); fail_unless(err == ERR_VAL); pbuf_free(p1); pbuf_free(p3); fail_unless(lwip_stats.mem.used == 0); fail_unless(lwip_stats.mem.used == 0); fail_unless(lwip_stats.memp[MEMP_PBUF_POOL].used == 0); } END_TEST START_TEST(test_pbuf_split_64k_on_small_pbufs) { struct pbuf *p, *rest=NULL; LWIP_UNUSED_ARG(_i); p = pbuf_alloc(PBUF_RAW, 1, PBUF_POOL); pbuf_split_64k(p, &rest); fail_unless(p->tot_len == 1); pbuf_free(p); } END_TEST START_TEST(test_pbuf_queueing_bigger_than_64k) { int i; err_t err; struct pbuf *p1, *p2, *p3, *rest2=NULL, *rest3=NULL; LWIP_UNUSED_ARG(_i); for(i = 0; i < TESTBUFSIZE_1; i++) testbuf_1[i] = rand(); for(i = 0; i < TESTBUFSIZE_2; i++) testbuf_2[i] = rand(); for(i = 0; i < TESTBUFSIZE_3; i++) testbuf_3[i] = rand(); p1 = pbuf_alloc(PBUF_RAW, TESTBUFSIZE_1, PBUF_POOL); fail_unless(p1 != NULL); p2 = pbuf_alloc(PBUF_RAW, TESTBUFSIZE_2, PBUF_POOL); fail_unless(p2 != NULL); p3 = pbuf_alloc(PBUF_RAW, TESTBUFSIZE_3, PBUF_POOL); fail_unless(p3 != NULL); err = pbuf_take(p1, testbuf_1, TESTBUFSIZE_1); fail_unless(err == ERR_OK); err = pbuf_take(p2, testbuf_2, TESTBUFSIZE_2); fail_unless(err == ERR_OK); err = pbuf_take(p3, testbuf_3, TESTBUFSIZE_3); fail_unless(err == ERR_OK); pbuf_cat(p1, p2); pbuf_cat(p1, p3); pbuf_split_64k(p1, &rest2); fail_unless(p1->tot_len == TESTBUFSIZE_1); fail_unless(rest2->tot_len == (u16_t)((TESTBUFSIZE_2+TESTBUFSIZE_3) & 0xFFFF)); pbuf_split_64k(rest2, &rest3); fail_unless(rest2->tot_len == TESTBUFSIZE_2); fail_unless(rest3->tot_len == TESTBUFSIZE_3); pbuf_copy_partial(p1, testbuf_1a, TESTBUFSIZE_1, 0); pbuf_copy_partial(rest2, testbuf_2a, TESTBUFSIZE_2, 0); pbuf_copy_partial(rest3, testbuf_3a, TESTBUFSIZE_3, 0); for(i = 0; i < TESTBUFSIZE_1; i++) fail_unless(testbuf_1[i] == testbuf_1a[i]); for(i = 0; i < TESTBUFSIZE_2; i++) fail_unless(testbuf_2[i] == testbuf_2a[i]); for(i = 0; i < TESTBUFSIZE_3; i++) fail_unless(testbuf_3[i] == testbuf_3a[i]); pbuf_free(p1); pbuf_free(rest2); pbuf_free(rest3); } END_TEST /** Create the suite including all tests for this module */ Suite * pbuf_suite(void) { testfunc tests[] = { TESTFUNC(test_pbuf_copy_zero_pbuf), TESTFUNC(test_pbuf_split_64k_on_small_pbufs), TESTFUNC(test_pbuf_queueing_bigger_than_64k) }; return create_suite("PBUF", tests, sizeof(tests)/sizeof(testfunc), pbuf_setup, pbuf_teardown); } ocproxy-1.60/lwip/test/unit/core/test_pbuf.h000066400000000000000000000001741303453231400211500ustar00rootroot00000000000000#ifndef LWIP_HDR_TEST_PBUF_H__ #define LWIP_HDR_TEST_PBUF_H__ #include "../lwip_check.h" Suite *pbuf_suite(void); #endif ocproxy-1.60/lwip/test/unit/dhcp/000077500000000000000000000000001303453231400167705ustar00rootroot00000000000000ocproxy-1.60/lwip/test/unit/dhcp/test_dhcp.c000066400000000000000000001015621303453231400211160ustar00rootroot00000000000000#include "test_dhcp.h" #include "lwip/netif.h" #include "lwip/dhcp.h" #include "netif/etharp.h" struct netif net_test; static const u8_t broadcast[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; static const u8_t magic_cookie[] = { 0x63, 0x82, 0x53, 0x63 }; static u8_t dhcp_offer[] = { 0x00, 0x23, 0xc1, 0xde, 0xd0, 0x0d, /* To unit */ 0x00, 0x0F, 0xEE, 0x30, 0xAB, 0x22, /* From Remote host */ 0x08, 0x00, /* Protocol: IP */ 0x45, 0x10, 0x01, 0x48, 0x00, 0x00, 0x00, 0x00, 0x80, 0x11, 0x36, 0xcc, 0xc3, 0xaa, 0xbd, 0xab, 0xc3, 0xaa, 0xbd, 0xc8, /* IP header */ 0x00, 0x43, 0x00, 0x44, 0x01, 0x34, 0x00, 0x00, /* UDP header */ 0x02, /* Type == Boot reply */ 0x01, 0x06, /* Hw Ethernet, 6 bytes addrlen */ 0x00, /* 0 hops */ 0xAA, 0xAA, 0xAA, 0xAA, /* Transaction id, will be overwritten */ 0x00, 0x00, /* 0 seconds elapsed */ 0x00, 0x00, /* Flags (unicast) */ 0x00, 0x00, 0x00, 0x00, /* Client ip */ 0xc3, 0xaa, 0xbd, 0xc8, /* Your IP */ 0xc3, 0xaa, 0xbd, 0xab, /* DHCP server ip */ 0x00, 0x00, 0x00, 0x00, /* relay agent */ 0x00, 0x23, 0xc1, 0xde, 0xd0, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* MAC addr + padding */ /* Empty server name and boot file name */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x82, 0x53, 0x63, /* Magic cookie */ 0x35, 0x01, 0x02, /* Message type: Offer */ 0x36, 0x04, 0xc3, 0xaa, 0xbd, 0xab, /* Server identifier (IP) */ 0x33, 0x04, 0x00, 0x00, 0x00, 0x78, /* Lease time 2 minutes */ 0x03, 0x04, 0xc3, 0xaa, 0xbd, 0xab, /* Router IP */ 0x01, 0x04, 0xff, 0xff, 0xff, 0x00, /* Subnet mask */ 0xff, /* End option */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Padding */ }; static u8_t dhcp_ack[] = { 0x00, 0x23, 0xc1, 0xde, 0xd0, 0x0d, /* To unit */ 0x00, 0x0f, 0xEE, 0x30, 0xAB, 0x22, /* From remote host */ 0x08, 0x00, /* Proto IP */ 0x45, 0x10, 0x01, 0x48, 0x00, 0x00, 0x00, 0x00, 0x80, 0x11, 0x36, 0xcc, 0xc3, 0xaa, 0xbd, 0xab, 0xc3, 0xaa, 0xbd, 0xc8, /* IP header */ 0x00, 0x43, 0x00, 0x44, 0x01, 0x34, 0x00, 0x00, /* UDP header */ 0x02, /* Bootp reply */ 0x01, 0x06, /* Hw type Eth, len 6 */ 0x00, /* 0 hops */ 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, /* 0 seconds elapsed */ 0x00, 0x00, /* Flags (unicast) */ 0x00, 0x00, 0x00, 0x00, /* Client IP */ 0xc3, 0xaa, 0xbd, 0xc8, /* Your IP */ 0xc3, 0xaa, 0xbd, 0xab, /* DHCP server IP */ 0x00, 0x00, 0x00, 0x00, /* Relay agent */ 0x00, 0x23, 0xc1, 0xde, 0xd0, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Macaddr + padding */ /* Empty server name and boot file name */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x82, 0x53, 0x63, /* Magic cookie */ 0x35, 0x01, 0x05, /* Dhcp message type ack */ 0x36, 0x04, 0xc3, 0xaa, 0xbd, 0xab, /* DHCP server identifier */ 0x33, 0x04, 0x00, 0x00, 0x00, 0x78, /* Lease time 2 minutes */ 0x03, 0x04, 0xc3, 0xaa, 0xbd, 0xab, /* Router IP */ 0x01, 0x04, 0xff, 0xff, 0xff, 0x00, /* Netmask */ 0xff, /* End marker */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Padding */ }; static const u8_t arpreply[] = { 0x00, 0x23, 0xC1, 0xDE, 0xD0, 0x0D, /* dst mac */ 0x00, 0x32, 0x44, 0x20, 0x01, 0x02, /* src mac */ 0x08, 0x06, /* proto arp */ 0x00, 0x01, /* hw eth */ 0x08, 0x00, /* proto ip */ 0x06, /* hw addr len 6 */ 0x04, /* proto addr len 4 */ 0x00, 0x02, /* arp reply */ 0x00, 0x32, 0x44, 0x20, 0x01, 0x02, /* sender mac */ 0xc3, 0xaa, 0xbd, 0xc8, /* sender ip */ 0x00, 0x23, 0xC1, 0xDE, 0xD0, 0x0D, /* target mac */ 0x00, 0x00, 0x00, 0x00, /* target ip */ }; static int txpacket; static enum tcase { TEST_LWIP_DHCP, TEST_LWIP_DHCP_NAK, TEST_LWIP_DHCP_RELAY, TEST_LWIP_DHCP_NAK_NO_ENDMARKER, } tcase; static int debug = 0; static void setdebug(int a) {debug = a;} static int tick = 0; static void tick_lwip(void) { tick++; if (tick % 5 == 0) { dhcp_fine_tmr(); } if (tick % 600 == 0) { dhcp_coarse_tmr(); } } static void send_pkt(struct netif *netif, const u8_t *data, u32_t len) { struct pbuf *p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL); struct pbuf *q; if (debug) { /* Dump data */ u32_t i; printf("RX data (len %d)", p->tot_len); for (i = 0; i < len; i++) { printf(" %02X", data[i]); } printf("\n"); } fail_unless(p != NULL); for(q = p; q != NULL; q = q->next) { memcpy(q->payload, data, q->len); data += q->len; } netif->input(p, netif); } static err_t lwip_tx_func(struct netif *netif, struct pbuf *p); static err_t testif_init(struct netif *netif) { netif->name[0] = 'c'; netif->name[1] = 'h'; netif->output = etharp_output; netif->linkoutput = lwip_tx_func; netif->mtu = 1500; netif->hwaddr_len = 6; netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP; netif->hwaddr[0] = 0x00; netif->hwaddr[1] = 0x23; netif->hwaddr[2] = 0xC1; netif->hwaddr[3] = 0xDE; netif->hwaddr[4] = 0xD0; netif->hwaddr[5] = 0x0D; return ERR_OK; } static void dhcp_setup(void) { txpacket = 0; } static void dhcp_teardown(void) { } static void check_pkt(struct pbuf *p, u32_t pos, const u8_t *mem, u32_t len) { u8_t *data; fail_if((pos + len) > p->tot_len); while (pos > p->len && p->next) { pos -= p->len; p = p->next; } fail_if(p == NULL); fail_unless(pos + len <= p->len); /* All data we seek within same pbuf */ data = p->payload; fail_if(memcmp(&data[pos], mem, len), "data at pos %d, len %d in packet %d did not match", pos, len, txpacket); } static void check_pkt_fuzzy(struct pbuf *p, u32_t startpos, const u8_t *mem, u32_t len) { int found; u32_t i; u8_t *data; fail_if((startpos + len) > p->tot_len); while (startpos > p->len && p->next) { startpos -= p->len; p = p->next; } fail_if(p == NULL); fail_unless(startpos + len <= p->len); /* All data we seek within same pbuf */ found = 0; data = p->payload; for (i = startpos; i <= (p->len - len); i++) { if (memcmp(&data[i], mem, len) == 0) { found = 1; break; } } fail_unless(found); } static err_t lwip_tx_func(struct netif *netif, struct pbuf *p) { fail_unless(netif == &net_test); txpacket++; if (debug) { struct pbuf *pp = p; /* Dump data */ printf("TX data (pkt %d, len %d, tick %d)", txpacket, p->tot_len, tick); do { int i; for (i = 0; i < pp->len; i++) { printf(" %02X", ((u8_t *) pp->payload)[i]); } if (pp->next) { pp = pp->next; } } while (pp->next); printf("\n"); } switch (tcase) { case TEST_LWIP_DHCP: switch (txpacket) { case 1: case 2: { const u8_t ipproto[] = { 0x08, 0x00 }; const u8_t bootp_start[] = { 0x01, 0x01, 0x06, 0x00}; /* bootp request, eth, hwaddr len 6, 0 hops */ const u8_t ipaddrs[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; check_pkt(p, 0, broadcast, 6); /* eth level dest: broadcast */ check_pkt(p, 6, netif->hwaddr, 6); /* eth level src: unit mac */ check_pkt(p, 12, ipproto, sizeof(ipproto)); /* eth level proto: ip */ check_pkt(p, 42, bootp_start, sizeof(bootp_start)); check_pkt(p, 53, ipaddrs, sizeof(ipaddrs)); check_pkt(p, 70, netif->hwaddr, 6); /* mac addr inside bootp */ check_pkt(p, 278, magic_cookie, sizeof(magic_cookie)); /* Check dchp message type, can be at different positions */ if (txpacket == 1) { u8_t dhcp_discover_opt[] = { 0x35, 0x01, 0x01 }; check_pkt_fuzzy(p, 282, dhcp_discover_opt, sizeof(dhcp_discover_opt)); } else if (txpacket == 2) { u8_t dhcp_request_opt[] = { 0x35, 0x01, 0x03 }; u8_t requested_ipaddr[] = { 0x32, 0x04, 0xc3, 0xaa, 0xbd, 0xc8 }; /* Ask for offered IP */ check_pkt_fuzzy(p, 282, dhcp_request_opt, sizeof(dhcp_request_opt)); check_pkt_fuzzy(p, 282, requested_ipaddr, sizeof(requested_ipaddr)); } break; } case 3: case 4: case 5: { const u8_t arpproto[] = { 0x08, 0x06 }; check_pkt(p, 0, broadcast, 6); /* eth level dest: broadcast */ check_pkt(p, 6, netif->hwaddr, 6); /* eth level src: unit mac */ check_pkt(p, 12, arpproto, sizeof(arpproto)); /* eth level proto: ip */ break; } } break; case TEST_LWIP_DHCP_NAK: { const u8_t ipproto[] = { 0x08, 0x00 }; const u8_t bootp_start[] = { 0x01, 0x01, 0x06, 0x00}; /* bootp request, eth, hwaddr len 6, 0 hops */ const u8_t ipaddrs[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; const u8_t dhcp_nak_opt[] = { 0x35, 0x01, 0x04 }; const u8_t requested_ipaddr[] = { 0x32, 0x04, 0xc3, 0xaa, 0xbd, 0xc8 }; /* offered IP */ fail_unless(txpacket == 4); check_pkt(p, 0, broadcast, 6); /* eth level dest: broadcast */ check_pkt(p, 6, netif->hwaddr, 6); /* eth level src: unit mac */ check_pkt(p, 12, ipproto, sizeof(ipproto)); /* eth level proto: ip */ check_pkt(p, 42, bootp_start, sizeof(bootp_start)); check_pkt(p, 53, ipaddrs, sizeof(ipaddrs)); check_pkt(p, 70, netif->hwaddr, 6); /* mac addr inside bootp */ check_pkt(p, 278, magic_cookie, sizeof(magic_cookie)); check_pkt_fuzzy(p, 282, dhcp_nak_opt, sizeof(dhcp_nak_opt)); /* NAK the ack */ check_pkt_fuzzy(p, 282, requested_ipaddr, sizeof(requested_ipaddr)); break; } case TEST_LWIP_DHCP_RELAY: switch (txpacket) { case 1: case 2: { const u8_t ipproto[] = { 0x08, 0x00 }; const u8_t bootp_start[] = { 0x01, 0x01, 0x06, 0x00}; /* bootp request, eth, hwaddr len 6, 0 hops */ const u8_t ipaddrs[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; check_pkt(p, 0, broadcast, 6); /* eth level dest: broadcast */ check_pkt(p, 6, netif->hwaddr, 6); /* eth level src: unit mac */ check_pkt(p, 12, ipproto, sizeof(ipproto)); /* eth level proto: ip */ check_pkt(p, 42, bootp_start, sizeof(bootp_start)); check_pkt(p, 53, ipaddrs, sizeof(ipaddrs)); check_pkt(p, 70, netif->hwaddr, 6); /* mac addr inside bootp */ check_pkt(p, 278, magic_cookie, sizeof(magic_cookie)); /* Check dchp message type, can be at different positions */ if (txpacket == 1) { u8_t dhcp_discover_opt[] = { 0x35, 0x01, 0x01 }; check_pkt_fuzzy(p, 282, dhcp_discover_opt, sizeof(dhcp_discover_opt)); } else if (txpacket == 2) { u8_t dhcp_request_opt[] = { 0x35, 0x01, 0x03 }; u8_t requested_ipaddr[] = { 0x32, 0x04, 0x4f, 0x8a, 0x33, 0x05 }; /* Ask for offered IP */ check_pkt_fuzzy(p, 282, dhcp_request_opt, sizeof(dhcp_request_opt)); check_pkt_fuzzy(p, 282, requested_ipaddr, sizeof(requested_ipaddr)); } break; } case 3: case 4: case 5: case 6: { const u8_t arpproto[] = { 0x08, 0x06 }; check_pkt(p, 0, broadcast, 6); /* eth level dest: broadcast */ check_pkt(p, 6, netif->hwaddr, 6); /* eth level src: unit mac */ check_pkt(p, 12, arpproto, sizeof(arpproto)); /* eth level proto: ip */ break; } case 7: { const u8_t fake_arp[6] = { 0x12, 0x34, 0x56, 0x78, 0x9a, 0xab }; const u8_t ipproto[] = { 0x08, 0x00 }; const u8_t bootp_start[] = { 0x01, 0x01, 0x06, 0x00}; /* bootp request, eth, hwaddr len 6, 0 hops */ const u8_t ipaddrs[] = { 0x00, 0x4f, 0x8a, 0x33, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; const u8_t dhcp_request_opt[] = { 0x35, 0x01, 0x03 }; check_pkt(p, 0, fake_arp, 6); /* eth level dest: broadcast */ check_pkt(p, 6, netif->hwaddr, 6); /* eth level src: unit mac */ check_pkt(p, 12, ipproto, sizeof(ipproto)); /* eth level proto: ip */ check_pkt(p, 42, bootp_start, sizeof(bootp_start)); check_pkt(p, 53, ipaddrs, sizeof(ipaddrs)); check_pkt(p, 70, netif->hwaddr, 6); /* mac addr inside bootp */ check_pkt(p, 278, magic_cookie, sizeof(magic_cookie)); /* Check dchp message type, can be at different positions */ check_pkt_fuzzy(p, 282, dhcp_request_opt, sizeof(dhcp_request_opt)); break; } } break; default: break; } return ERR_OK; } /* * Test basic happy flow DHCP session. * Validate that xid is checked. */ START_TEST(test_dhcp) { struct ip_addr addr; struct ip_addr netmask; struct ip_addr gw; int i; u32_t xid; LWIP_UNUSED_ARG(_i); tcase = TEST_LWIP_DHCP; setdebug(0); IP4_ADDR(&addr, 0, 0, 0, 0); IP4_ADDR(&netmask, 0, 0, 0, 0); IP4_ADDR(&gw, 0, 0, 0, 0); netif_add(&net_test, &addr, &netmask, &gw, &net_test, testif_init, ethernet_input); dhcp_start(&net_test); fail_unless(txpacket == 1); /* DHCP discover sent */ xid = net_test.dhcp->xid; /* Write bad xid, not using htonl! */ memcpy(&dhcp_offer[46], &xid, 4); send_pkt(&net_test, dhcp_offer, sizeof(dhcp_offer)); /* Interface down */ fail_if(netif_is_up(&net_test)); /* IP addresses should be zero */ fail_if(memcmp(&addr, &net_test.ip_addr, sizeof(struct ip_addr))); fail_if(memcmp(&netmask, &net_test.netmask, sizeof(struct ip_addr))); fail_if(memcmp(&gw, &net_test.gw, sizeof(struct ip_addr))); fail_unless(txpacket == 1, "TX %d packets, expected 1", txpacket); /* Nothing more sent */ xid = htonl(net_test.dhcp->xid); memcpy(&dhcp_offer[46], &xid, 4); /* insert correct transaction id */ send_pkt(&net_test, dhcp_offer, sizeof(dhcp_offer)); fail_unless(txpacket == 2, "TX %d packets, expected 2", txpacket); /* DHCP request sent */ xid = net_test.dhcp->xid; /* Write bad xid, not using htonl! */ memcpy(&dhcp_ack[46], &xid, 4); send_pkt(&net_test, dhcp_ack, sizeof(dhcp_ack)); fail_unless(txpacket == 2, "TX %d packets, still expected 2", txpacket); /* No more sent */ xid = htonl(net_test.dhcp->xid); /* xid updated */ memcpy(&dhcp_ack[46], &xid, 4); /* insert transaction id */ send_pkt(&net_test, dhcp_ack, sizeof(dhcp_ack)); for (i = 0; i < 20; i++) { tick_lwip(); } fail_unless(txpacket == 4, "TX %d packets, expected 4", txpacket); /* ARP requests sent */ /* Interface up */ fail_unless(netif_is_up(&net_test)); /* Now it should have taken the IP */ IP4_ADDR(&addr, 195, 170, 189, 200); IP4_ADDR(&netmask, 255, 255, 255, 0); IP4_ADDR(&gw, 195, 170, 189, 171); fail_if(memcmp(&addr, &net_test.ip_addr, sizeof(struct ip_addr))); fail_if(memcmp(&netmask, &net_test.netmask, sizeof(struct ip_addr))); fail_if(memcmp(&gw, &net_test.gw, sizeof(struct ip_addr))); netif_remove(&net_test); } END_TEST /* * Test that IP address is not taken and NAK is sent if someone * replies to ARP requests for the offered address. */ START_TEST(test_dhcp_nak) { struct ip_addr addr; struct ip_addr netmask; struct ip_addr gw; u32_t xid; LWIP_UNUSED_ARG(_i); tcase = TEST_LWIP_DHCP; setdebug(0); IP4_ADDR(&addr, 0, 0, 0, 0); IP4_ADDR(&netmask, 0, 0, 0, 0); IP4_ADDR(&gw, 0, 0, 0, 0); netif_add(&net_test, &addr, &netmask, &gw, &net_test, testif_init, ethernet_input); dhcp_start(&net_test); fail_unless(txpacket == 1); /* DHCP discover sent */ xid = net_test.dhcp->xid; /* Write bad xid, not using htonl! */ memcpy(&dhcp_offer[46], &xid, 4); send_pkt(&net_test, dhcp_offer, sizeof(dhcp_offer)); /* Interface down */ fail_if(netif_is_up(&net_test)); /* IP addresses should be zero */ fail_if(memcmp(&addr, &net_test.ip_addr, sizeof(struct ip_addr))); fail_if(memcmp(&netmask, &net_test.netmask, sizeof(struct ip_addr))); fail_if(memcmp(&gw, &net_test.gw, sizeof(struct ip_addr))); fail_unless(txpacket == 1); /* Nothing more sent */ xid = htonl(net_test.dhcp->xid); memcpy(&dhcp_offer[46], &xid, 4); /* insert correct transaction id */ send_pkt(&net_test, dhcp_offer, sizeof(dhcp_offer)); fail_unless(txpacket == 2); /* DHCP request sent */ xid = net_test.dhcp->xid; /* Write bad xid, not using htonl! */ memcpy(&dhcp_ack[46], &xid, 4); send_pkt(&net_test, dhcp_ack, sizeof(dhcp_ack)); fail_unless(txpacket == 2); /* No more sent */ xid = htonl(net_test.dhcp->xid); /* xid updated */ memcpy(&dhcp_ack[46], &xid, 4); /* insert transaction id */ send_pkt(&net_test, dhcp_ack, sizeof(dhcp_ack)); fail_unless(txpacket == 3); /* ARP request sent */ tcase = TEST_LWIP_DHCP_NAK; /* Switch testcase */ /* Send arp reply, mark offered IP as taken */ send_pkt(&net_test, arpreply, sizeof(arpreply)); fail_unless(txpacket == 4); /* DHCP nak sent */ netif_remove(&net_test); } END_TEST /* * Test case based on captured data where * replies are sent from a different IP than the * one the client unicasted to. */ START_TEST(test_dhcp_relayed) { u8_t relay_offer[] = { 0x00, 0x23, 0xc1, 0xde, 0xd0, 0x0d, 0x00, 0x22, 0x93, 0x5a, 0xf7, 0x60, 0x08, 0x00, 0x45, 0x00, 0x01, 0x38, 0xfd, 0x53, 0x00, 0x00, 0x40, 0x11, 0x78, 0x46, 0x4f, 0x8a, 0x32, 0x02, 0x4f, 0x8a, 0x33, 0x05, 0x00, 0x43, 0x00, 0x44, 0x01, 0x24, 0x00, 0x00, 0x02, 0x01, 0x06, 0x00, 0x51, 0x35, 0xb6, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4f, 0x8a, 0x33, 0x05, 0x00, 0x00, 0x00, 0x00, 0x0a, 0xb5, 0x04, 0x01, 0x00, 0x23, 0xc1, 0xde, 0xd0, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x82, 0x53, 0x63, 0x01, 0x04, 0xff, 0xff, 0xfe, 0x00, 0x03, 0x04, 0x4f, 0x8a, 0x32, 0x01, 0x06, 0x08, 0x4f, 0x8a, 0x00, 0xb4, 0x55, 0x08, 0x1f, 0xd1, 0x1c, 0x04, 0x4f, 0x8a, 0x33, 0xff, 0x33, 0x04, 0x00, 0x00, 0x54, 0x49, 0x35, 0x01, 0x02, 0x36, 0x04, 0x0a, 0xb5, 0x04, 0x01, 0xff }; u8_t relay_ack1[] = { 0x00, 0x23, 0xc1, 0xde, 0xd0, 0x0d, 0x00, 0x22, 0x93, 0x5a, 0xf7, 0x60, 0x08, 0x00, 0x45, 0x00, 0x01, 0x38, 0xfd, 0x55, 0x00, 0x00, 0x40, 0x11, 0x78, 0x44, 0x4f, 0x8a, 0x32, 0x02, 0x4f, 0x8a, 0x33, 0x05, 0x00, 0x43, 0x00, 0x44, 0x01, 0x24, 0x00, 0x00, 0x02, 0x01, 0x06, 0x00, 0x51, 0x35, 0xb6, 0xa1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4f, 0x8a, 0x33, 0x05, 0x00, 0x00, 0x00, 0x00, 0x0a, 0xb5, 0x04, 0x01, 0x00, 0x23, 0xc1, 0xde, 0xd0, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x82, 0x53, 0x63, 0x01, 0x04, 0xff, 0xff, 0xfe, 0x00, 0x03, 0x04, 0x4f, 0x8a, 0x32, 0x01, 0x06, 0x08, 0x4f, 0x8a, 0x00, 0xb4, 0x55, 0x08, 0x1f, 0xd1, 0x1c, 0x04, 0x4f, 0x8a, 0x33, 0xff, 0x33, 0x04, 0x00, 0x00, 0x54, 0x49, 0x35, 0x01, 0x05, 0x36, 0x04, 0x0a, 0xb5, 0x04, 0x01, 0xff }; u8_t relay_ack2[] = { 0x00, 0x23, 0xc1, 0xde, 0xd0, 0x0d, 0x00, 0x22, 0x93, 0x5a, 0xf7, 0x60, 0x08, 0x00, 0x45, 0x00, 0x01, 0x38, 0xfa, 0x18, 0x00, 0x00, 0x40, 0x11, 0x7b, 0x81, 0x4f, 0x8a, 0x32, 0x02, 0x4f, 0x8a, 0x33, 0x05, 0x00, 0x43, 0x00, 0x44, 0x01, 0x24, 0x00, 0x00, 0x02, 0x01, 0x06, 0x00, 0x49, 0x8b, 0x6e, 0xab, 0x00, 0x00, 0x00, 0x00, 0x4f, 0x8a, 0x33, 0x05, 0x4f, 0x8a, 0x33, 0x05, 0x00, 0x00, 0x00, 0x00, 0x0a, 0xb5, 0x04, 0x01, 0x00, 0x23, 0xc1, 0xde, 0xd0, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x82, 0x53, 0x63, 0x01, 0x04, 0xff, 0xff, 0xfe, 0x00, 0x03, 0x04, 0x4f, 0x8a, 0x32, 0x01, 0x06, 0x08, 0x4f, 0x8a, 0x00, 0xb4, 0x55, 0x08, 0x1f, 0xd1, 0x1c, 0x04, 0x4f, 0x8a, 0x33, 0xff, 0x33, 0x04, 0x00, 0x00, 0x54, 0x60, 0x35, 0x01, 0x05, 0x36, 0x04, 0x0a, 0xb5, 0x04, 0x01, 0xff }; const u8_t arp_resp[] = { 0x00, 0x23, 0xc1, 0xde, 0xd0, 0x0d, /* DEST */ 0x00, 0x22, 0x93, 0x5a, 0xf7, 0x60, /* SRC */ 0x08, 0x06, /* Type: ARP */ 0x00, 0x01, /* HW: Ethernet */ 0x08, 0x00, /* PROTO: IP */ 0x06, /* HW size */ 0x04, /* PROTO size */ 0x00, 0x02, /* OPCODE: Reply */ 0x12, 0x34, 0x56, 0x78, 0x9a, 0xab, /* Target MAC */ 0x4f, 0x8a, 0x32, 0x01, /* Target IP */ 0x00, 0x23, 0xc1, 0x00, 0x06, 0x50, /* src mac */ 0x4f, 0x8a, 0x33, 0x05, /* src ip */ /* Padding follows.. */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; struct ip_addr addr; struct ip_addr netmask; struct ip_addr gw; int i; u32_t xid; LWIP_UNUSED_ARG(_i); tcase = TEST_LWIP_DHCP_RELAY; setdebug(0); IP4_ADDR(&addr, 0, 0, 0, 0); IP4_ADDR(&netmask, 0, 0, 0, 0); IP4_ADDR(&gw, 0, 0, 0, 0); netif_add(&net_test, &addr, &netmask, &gw, &net_test, testif_init, ethernet_input); dhcp_start(&net_test); fail_unless(txpacket == 1); /* DHCP discover sent */ /* Interface down */ fail_if(netif_is_up(&net_test)); /* IP addresses should be zero */ fail_if(memcmp(&addr, &net_test.ip_addr, sizeof(struct ip_addr))); fail_if(memcmp(&netmask, &net_test.netmask, sizeof(struct ip_addr))); fail_if(memcmp(&gw, &net_test.gw, sizeof(struct ip_addr))); fail_unless(txpacket == 1); /* Nothing more sent */ xid = htonl(net_test.dhcp->xid); memcpy(&relay_offer[46], &xid, 4); /* insert correct transaction id */ send_pkt(&net_test, relay_offer, sizeof(relay_offer)); /* request sent? */ fail_unless(txpacket == 2, "txpkt = %d, should be 2", txpacket); xid = htonl(net_test.dhcp->xid); /* xid updated */ memcpy(&relay_ack1[46], &xid, 4); /* insert transaction id */ send_pkt(&net_test, relay_ack1, sizeof(relay_ack1)); for (i = 0; i < 25; i++) { tick_lwip(); } fail_unless(txpacket == 4, "txpkt should be 5, is %d", txpacket); /* ARP requests sent */ /* Interface up */ fail_unless(netif_is_up(&net_test)); /* Now it should have taken the IP */ IP4_ADDR(&addr, 79, 138, 51, 5); IP4_ADDR(&netmask, 255, 255, 254, 0); IP4_ADDR(&gw, 79, 138, 50, 1); fail_if(memcmp(&addr, &net_test.ip_addr, sizeof(struct ip_addr))); fail_if(memcmp(&netmask, &net_test.netmask, sizeof(struct ip_addr))); fail_if(memcmp(&gw, &net_test.gw, sizeof(struct ip_addr))); fail_unless(txpacket == 4, "txpacket = %d", txpacket); for (i = 0; i < 108000 - 25; i++) { tick_lwip(); } fail_unless(netif_is_up(&net_test)); fail_unless(txpacket == 6, "txpacket = %d", txpacket); /* We need to send arp response here.. */ send_pkt(&net_test, arp_resp, sizeof(arp_resp)); fail_unless(txpacket == 7, "txpacket = %d", txpacket); fail_unless(netif_is_up(&net_test)); xid = htonl(net_test.dhcp->xid); /* xid updated */ memcpy(&relay_ack2[46], &xid, 4); /* insert transaction id */ send_pkt(&net_test, relay_ack2, sizeof(relay_ack2)); for (i = 0; i < 100000; i++) { tick_lwip(); } fail_unless(txpacket == 7, "txpacket = %d", txpacket); netif_remove(&net_test); } END_TEST START_TEST(test_dhcp_nak_no_endmarker) { struct ip_addr addr; struct ip_addr netmask; struct ip_addr gw; u8_t dhcp_nack_no_endmarker[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x54, 0x75, 0xd0, 0x26, 0xd0, 0x0d, 0x08, 0x00, 0x45, 0x00, 0x01, 0x15, 0x38, 0x86, 0x00, 0x00, 0xff, 0x11, 0xc0, 0xa8, 0xc0, 0xa8, 0x01, 0x01, 0xff, 0xff, 0xff, 0xff, 0x00, 0x43, 0x00, 0x44, 0x01, 0x01, 0x00, 0x00, 0x02, 0x01, 0x06, 0x00, 0x7a, 0xcb, 0xba, 0xf2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0xc1, 0xde, 0xd0, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x82, 0x53, 0x63, 0x35, 0x01, 0x06, 0x36, 0x04, 0xc0, 0xa8, 0x01, 0x01, 0x31, 0xef, 0xad, 0x72, 0x31, 0x43, 0x4e, 0x44, 0x30, 0x32, 0x35, 0x30, 0x43, 0x52, 0x47, 0x44, 0x38, 0x35, 0x36, 0x3c, 0x08, 0x4d, 0x53, 0x46, 0x54, 0x20, 0x35, 0x2e, 0x30, 0x37, 0x0d, 0x01, 0x0f, 0x03, 0x06, 0x2c, 0x2e, 0x2f, 0x1f, 0x21, 0x79, 0xf9, 0x2b, 0xfc, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe2, 0x71, 0xf3, 0x5b, 0xe2, 0x71, 0x2e, 0x01, 0x08, 0x03, 0x04, 0xc0, 0xa8, 0x01, 0x01, 0xff, 0xeb, 0x1e, 0x44, 0xec, 0xeb, 0x1e, 0x30, 0x37, 0x0c, 0x01, 0x0f, 0x03, 0x06, 0x2c, 0x2e, 0x2f, 0x1f, 0x21, 0x79, 0xf9, 0x2b, 0xff, 0x25, 0xc0, 0x09, 0xd6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; u32_t xid; LWIP_UNUSED_ARG(_i); tcase = TEST_LWIP_DHCP_NAK_NO_ENDMARKER; setdebug(0); IP4_ADDR(&addr, 0, 0, 0, 0); IP4_ADDR(&netmask, 0, 0, 0, 0); IP4_ADDR(&gw, 0, 0, 0, 0); netif_add(&net_test, &addr, &netmask, &gw, &net_test, testif_init, ethernet_input); dhcp_start(&net_test); fail_unless(txpacket == 1); /* DHCP discover sent */ xid = net_test.dhcp->xid; /* Write bad xid, not using htonl! */ memcpy(&dhcp_offer[46], &xid, 4); send_pkt(&net_test, dhcp_offer, sizeof(dhcp_offer)); /* Interface down */ fail_if(netif_is_up(&net_test)); /* IP addresses should be zero */ fail_if(memcmp(&addr, &net_test.ip_addr, sizeof(struct ip_addr))); fail_if(memcmp(&netmask, &net_test.netmask, sizeof(struct ip_addr))); fail_if(memcmp(&gw, &net_test.gw, sizeof(struct ip_addr))); fail_unless(txpacket == 1); /* Nothing more sent */ xid = htonl(net_test.dhcp->xid); memcpy(&dhcp_offer[46], &xid, 4); /* insert correct transaction id */ send_pkt(&net_test, dhcp_offer, sizeof(dhcp_offer)); fail_unless(net_test.dhcp->state == DHCP_REQUESTING); fail_unless(txpacket == 2); /* No more sent */ xid = htonl(net_test.dhcp->xid); /* xid updated */ memcpy(&dhcp_nack_no_endmarker[46], &xid, 4); /* insert transaction id */ send_pkt(&net_test, dhcp_nack_no_endmarker, sizeof(dhcp_nack_no_endmarker)); /* NAK should put us in another state for a while, no other way detecting it */ fail_unless(net_test.dhcp->state != DHCP_REQUESTING); netif_remove(&net_test); } END_TEST /** Create the suite including all tests for this module */ Suite * dhcp_suite(void) { testfunc tests[] = { TESTFUNC(test_dhcp), TESTFUNC(test_dhcp_nak), TESTFUNC(test_dhcp_relayed), TESTFUNC(test_dhcp_nak_no_endmarker) }; return create_suite("DHCP", tests, sizeof(tests)/sizeof(testfunc), dhcp_setup, dhcp_teardown); } ocproxy-1.60/lwip/test/unit/dhcp/test_dhcp.h000066400000000000000000000001741303453231400211200ustar00rootroot00000000000000#ifndef LWIP_HDR_TEST_DHCP_H__ #define LWIP_HDR_TEST_DHCP_H__ #include "../lwip_check.h" Suite* dhcp_suite(void); #endif ocproxy-1.60/lwip/test/unit/etharp/000077500000000000000000000000001303453231400173355ustar00rootroot00000000000000ocproxy-1.60/lwip/test/unit/etharp/test_etharp.c000066400000000000000000000166061303453231400220340ustar00rootroot00000000000000#include "test_etharp.h" #include "lwip/udp.h" #include "netif/etharp.h" #include "lwip/stats.h" #if !LWIP_STATS || !UDP_STATS || !MEMP_STATS || !ETHARP_STATS #error "This tests needs UDP-, MEMP- and ETHARP-statistics enabled" #endif #if !ETHARP_SUPPORT_STATIC_ENTRIES #error "This test needs ETHARP_SUPPORT_STATIC_ENTRIES enabled" #endif static struct netif test_netif; static ip_addr_t test_ipaddr, test_netmask, test_gw; struct eth_addr test_ethaddr = {1,1,1,1,1,1}; struct eth_addr test_ethaddr2 = {1,1,1,1,1,2}; struct eth_addr test_ethaddr3 = {1,1,1,1,1,3}; struct eth_addr test_ethaddr4 = {1,1,1,1,1,4}; static int linkoutput_ctr; /* Helper functions */ static void etharp_remove_all(void) { int i; /* call etharp_tmr often enough to have all entries cleaned */ for(i = 0; i < 0xff; i++) { etharp_tmr(); } } static err_t default_netif_linkoutput(struct netif *netif, struct pbuf *p) { fail_unless(netif == &test_netif); fail_unless(p != NULL); linkoutput_ctr++; return ERR_OK; } static err_t default_netif_init(struct netif *netif) { fail_unless(netif != NULL); netif->linkoutput = default_netif_linkoutput; netif->output = etharp_output; netif->mtu = 1500; netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP; netif->hwaddr_len = ETHARP_HWADDR_LEN; return ERR_OK; } static void default_netif_add(void) { IP4_ADDR(&test_gw, 192,168,0,1); IP4_ADDR(&test_ipaddr, 192,168,0,1); IP4_ADDR(&test_netmask, 255,255,0,0); fail_unless(netif_default == NULL); netif_set_default(netif_add(&test_netif, &test_ipaddr, &test_netmask, &test_gw, NULL, default_netif_init, NULL)); netif_set_up(&test_netif); } static void default_netif_remove(void) { fail_unless(netif_default == &test_netif); netif_remove(&test_netif); } static void create_arp_response(ip_addr_t *adr) { int k; struct eth_hdr *ethhdr; struct etharp_hdr *etharphdr; struct pbuf *p = pbuf_alloc(PBUF_RAW, sizeof(struct eth_hdr) + sizeof(struct etharp_hdr), PBUF_RAM); if(p == NULL) { FAIL_RET(); } ethhdr = (struct eth_hdr*)p->payload; etharphdr = (struct etharp_hdr*)(ethhdr + 1); ethhdr->dest = test_ethaddr; ethhdr->src = test_ethaddr2; ethhdr->type = htons(ETHTYPE_ARP); etharphdr->hwtype = htons(/*HWTYPE_ETHERNET*/ 1); etharphdr->proto = htons(ETHTYPE_IP); etharphdr->hwlen = ETHARP_HWADDR_LEN; etharphdr->protolen = sizeof(ip_addr_t); etharphdr->opcode = htons(ARP_REPLY); SMEMCPY(ðarphdr->sipaddr, adr, sizeof(ip_addr_t)); SMEMCPY(ðarphdr->dipaddr, &test_ipaddr, sizeof(ip_addr_t)); k = 6; while(k > 0) { k--; /* Write the ARP MAC-Addresses */ etharphdr->shwaddr.addr[k] = test_ethaddr2.addr[k]; etharphdr->dhwaddr.addr[k] = test_ethaddr.addr[k]; /* Write the Ethernet MAC-Addresses */ ethhdr->dest.addr[k] = test_ethaddr.addr[k]; ethhdr->src.addr[k] = test_ethaddr2.addr[k]; } ethernet_input(p, &test_netif); } /* Setups/teardown functions */ static void etharp_setup(void) { etharp_remove_all(); default_netif_add(); } static void etharp_teardown(void) { etharp_remove_all(); default_netif_remove(); } /* Test functions */ START_TEST(test_etharp_table) { #if ETHARP_SUPPORT_STATIC_ENTRIES err_t err; #endif /* ETHARP_SUPPORT_STATIC_ENTRIES */ s8_t idx; ip_addr_t *unused_ipaddr; struct eth_addr *unused_ethaddr; struct udp_pcb* pcb; LWIP_UNUSED_ARG(_i); if (netif_default != &test_netif) { fail("This test needs a default netif"); } linkoutput_ctr = 0; pcb = udp_new(); fail_unless(pcb != NULL); if (pcb != NULL) { ip_addr_t adrs[ARP_TABLE_SIZE + 2]; int i; for(i = 0; i < ARP_TABLE_SIZE + 2; i++) { IP4_ADDR(&adrs[i], 192,168,0,i+2); } /* fill ARP-table with dynamic entries */ for(i = 0; i < ARP_TABLE_SIZE; i++) { struct pbuf *p = pbuf_alloc(PBUF_TRANSPORT, 10, PBUF_RAM); fail_unless(p != NULL); if (p != NULL) { err_t err = udp_sendto(pcb, p, &adrs[i], 123); fail_unless(err == ERR_OK); /* etharp request sent? */ fail_unless(linkoutput_ctr == (2*i) + 1); pbuf_free(p); /* create an ARP response */ create_arp_response(&adrs[i]); /* queued UDP packet sent? */ fail_unless(linkoutput_ctr == (2*i) + 2); idx = etharp_find_addr(NULL, &adrs[i], &unused_ethaddr, &unused_ipaddr); fail_unless(idx == i); etharp_tmr(); } } linkoutput_ctr = 0; #if ETHARP_SUPPORT_STATIC_ENTRIES /* create one static entry */ err = etharp_add_static_entry(&adrs[ARP_TABLE_SIZE], &test_ethaddr3); fail_unless(err == ERR_OK); idx = etharp_find_addr(NULL, &adrs[ARP_TABLE_SIZE], &unused_ethaddr, &unused_ipaddr); fail_unless(idx == 0); fail_unless(linkoutput_ctr == 0); #endif /* ETHARP_SUPPORT_STATIC_ENTRIES */ linkoutput_ctr = 0; /* fill ARP-table with dynamic entries */ for(i = 0; i < ARP_TABLE_SIZE; i++) { struct pbuf *p = pbuf_alloc(PBUF_TRANSPORT, 10, PBUF_RAM); fail_unless(p != NULL); if (p != NULL) { err_t err = udp_sendto(pcb, p, &adrs[i], 123); fail_unless(err == ERR_OK); /* etharp request sent? */ fail_unless(linkoutput_ctr == (2*i) + 1); pbuf_free(p); /* create an ARP response */ create_arp_response(&adrs[i]); /* queued UDP packet sent? */ fail_unless(linkoutput_ctr == (2*i) + 2); idx = etharp_find_addr(NULL, &adrs[i], &unused_ethaddr, &unused_ipaddr); if (i < ARP_TABLE_SIZE - 1) { fail_unless(idx == i+1); } else { /* the last entry must not overwrite the static entry! */ fail_unless(idx == 1); } etharp_tmr(); } } #if ETHARP_SUPPORT_STATIC_ENTRIES /* create a second static entry */ err = etharp_add_static_entry(&adrs[ARP_TABLE_SIZE+1], &test_ethaddr4); fail_unless(err == ERR_OK); idx = etharp_find_addr(NULL, &adrs[ARP_TABLE_SIZE], &unused_ethaddr, &unused_ipaddr); fail_unless(idx == 0); idx = etharp_find_addr(NULL, &adrs[ARP_TABLE_SIZE+1], &unused_ethaddr, &unused_ipaddr); fail_unless(idx == 2); /* and remove it again */ err = etharp_remove_static_entry(&adrs[ARP_TABLE_SIZE+1]); fail_unless(err == ERR_OK); idx = etharp_find_addr(NULL, &adrs[ARP_TABLE_SIZE], &unused_ethaddr, &unused_ipaddr); fail_unless(idx == 0); idx = etharp_find_addr(NULL, &adrs[ARP_TABLE_SIZE+1], &unused_ethaddr, &unused_ipaddr); fail_unless(idx == -1); #endif /* ETHARP_SUPPORT_STATIC_ENTRIES */ /* check that static entries don't time out */ etharp_remove_all(); idx = etharp_find_addr(NULL, &adrs[ARP_TABLE_SIZE], &unused_ethaddr, &unused_ipaddr); fail_unless(idx == 0); #if ETHARP_SUPPORT_STATIC_ENTRIES /* remove the first static entry */ err = etharp_remove_static_entry(&adrs[ARP_TABLE_SIZE]); fail_unless(err == ERR_OK); idx = etharp_find_addr(NULL, &adrs[ARP_TABLE_SIZE], &unused_ethaddr, &unused_ipaddr); fail_unless(idx == -1); idx = etharp_find_addr(NULL, &adrs[ARP_TABLE_SIZE+1], &unused_ethaddr, &unused_ipaddr); fail_unless(idx == -1); #endif /* ETHARP_SUPPORT_STATIC_ENTRIES */ udp_remove(pcb); } } END_TEST /** Create the suite including all tests for this module */ Suite * etharp_suite(void) { testfunc tests[] = { TESTFUNC(test_etharp_table) }; return create_suite("ETHARP", tests, sizeof(tests)/sizeof(testfunc), etharp_setup, etharp_teardown); } ocproxy-1.60/lwip/test/unit/etharp/test_etharp.h000066400000000000000000000002021303453231400220220ustar00rootroot00000000000000#ifndef LWIP_HDR_TEST_ETHARP_H__ #define LWIP_HDR_TEST_ETHARP_H__ #include "../lwip_check.h" Suite* etharp_suite(void); #endif ocproxy-1.60/lwip/test/unit/lwip_check.h000066400000000000000000000024741303453231400203420ustar00rootroot00000000000000#ifndef LWIP_HDR_LWIP_CHECK_H__ #define LWIP_HDR_LWIP_CHECK_H__ /* Common header file for lwIP unit tests using the check framework */ #include #include #include #define FAIL_RET() do { fail(); return; } while(0) #define EXPECT(x) fail_unless(x) #define EXPECT_RET(x) do { fail_unless(x); if(!(x)) { return; }} while(0) #define EXPECT_RETX(x, y) do { fail_unless(x); if(!(x)) { return y; }} while(0) #define EXPECT_RETNULL(x) EXPECT_RETX(x, NULL) typedef struct { TFun func; const char *name; } testfunc; #define TESTFUNC(x) {(x), "" # x "" } /* Modified function from check.h, supplying function name */ #define tcase_add_named_test(tc,tf) \ _tcase_add_test((tc),(tf).func,(tf).name,0, 0, 0, 1) /** typedef for a function returning a test suite */ typedef Suite* (suite_getter_fn)(void); /** Create a test suite */ static Suite* create_suite(const char* name, testfunc *tests, size_t num_tests, SFun setup, SFun teardown) { size_t i; Suite *s = suite_create(name); for(i = 0; i < num_tests; i++) { TCase *tc_core = tcase_create(name); if ((setup != NULL) || (teardown != NULL)) { tcase_add_checked_fixture(tc_core, setup, teardown); } tcase_add_named_test(tc_core, tests[i]); suite_add_tcase(s, tc_core); } return s; } #endif /* LWIP_HDR_LWIP_CHECK_H__ */ ocproxy-1.60/lwip/test/unit/lwip_unittests.c000066400000000000000000000017651303453231400213240ustar00rootroot00000000000000#include "lwip_check.h" #include "udp/test_udp.h" #include "tcp/test_tcp.h" #include "tcp/test_tcp_oos.h" #include "core/test_mem.h" #include "core/test_pbuf.h" #include "etharp/test_etharp.h" #include "dhcp/test_dhcp.h" #include "lwip/init.h" int main() { int number_failed; SRunner *sr; size_t i; suite_getter_fn* suites[] = { udp_suite, tcp_suite, tcp_oos_suite, mem_suite, pbuf_suite, etharp_suite, dhcp_suite }; size_t num = sizeof(suites)/sizeof(void*); LWIP_ASSERT("No suites defined", num > 0); lwip_init(); sr = srunner_create((suites[0])()); for(i = 1; i < num; i++) { srunner_add_suite(sr, ((suite_getter_fn*)suites[i])()); } #ifdef LWIP_UNITTESTS_NOFORK srunner_set_fork_status(sr, CK_NOFORK); #endif #ifdef LWIP_UNITTESTS_FORK srunner_set_fork_status(sr, CK_FORK); #endif srunner_run_all(sr, CK_NORMAL); number_failed = srunner_ntests_failed(sr); srunner_free(sr); return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; } ocproxy-1.60/lwip/test/unit/lwipopts.h000066400000000000000000000050551303453231400201110ustar00rootroot00000000000000/* * Copyright (c) 2001-2003 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Simon Goldschmidt * */ #ifndef LWIP_HDR_LWIPOPTS_H__ #define LWIP_HDR_LWIPOPTS_H__ /* Prevent having to link sys_arch.c (we don't test the API layers in unit tests) */ #define NO_SYS 1 #define LWIP_NETCONN 0 #define LWIP_SOCKET 0 /* Enable DHCP to test it, disable UDP checksum to easier inject packets */ #define LWIP_DHCP 1 /* Minimal changes to opt.h required for tcp unit tests: */ #define MEM_SIZE 16000 #define TCP_SND_QUEUELEN 40 #define MEMP_NUM_TCP_SEG TCP_SND_QUEUELEN #define TCP_SND_BUF (12 * TCP_MSS) #define TCP_WND (10 * TCP_MSS) #define LWIP_WND_SCALE 1 #define TCP_RCV_SCALE 0 #define PBUF_POOL_SIZE 400 // pbuf tests need ~200KByte /* Minimal changes to opt.h required for etharp unit tests: */ #define ETHARP_SUPPORT_STATIC_ENTRIES 1 #endif /* LWIP_HDR_LWIPOPTS_H__ */ ocproxy-1.60/lwip/test/unit/tcp/000077500000000000000000000000001303453231400166405ustar00rootroot00000000000000ocproxy-1.60/lwip/test/unit/tcp/tcp_helper.c000066400000000000000000000222201303453231400211270ustar00rootroot00000000000000#include "tcp_helper.h" #include "lwip/tcp_impl.h" #include "lwip/stats.h" #include "lwip/pbuf.h" #include "lwip/inet_chksum.h" #if !LWIP_STATS || !TCP_STATS || !MEMP_STATS #error "This tests needs TCP- and MEMP-statistics enabled" #endif /** Remove all pcbs on the given list. */ static void tcp_remove(struct tcp_pcb* pcb_list) { struct tcp_pcb *pcb = pcb_list; struct tcp_pcb *pcb2; while(pcb != NULL) { pcb2 = pcb; pcb = pcb->next; tcp_abort(pcb2); } } /** Remove all pcbs on listen-, active- and time-wait-list (bound- isn't exported). */ void tcp_remove_all(void) { tcp_remove(tcp_listen_pcbs.pcbs); tcp_remove(tcp_active_pcbs); tcp_remove(tcp_tw_pcbs); fail_unless(lwip_stats.memp[MEMP_TCP_PCB].used == 0); fail_unless(lwip_stats.memp[MEMP_TCP_PCB_LISTEN].used == 0); fail_unless(lwip_stats.memp[MEMP_TCP_SEG].used == 0); fail_unless(lwip_stats.memp[MEMP_PBUF_POOL].used == 0); } /** Create a TCP segment usable for passing to tcp_input */ static struct pbuf* tcp_create_segment_wnd(ip_addr_t* src_ip, ip_addr_t* dst_ip, u16_t src_port, u16_t dst_port, void* data, size_t data_len, u32_t seqno, u32_t ackno, u8_t headerflags, u16_t wnd) { struct pbuf *p, *q; struct ip_hdr* iphdr; struct tcp_hdr* tcphdr; u16_t pbuf_len = (u16_t)(sizeof(struct ip_hdr) + sizeof(struct tcp_hdr) + data_len); p = pbuf_alloc(PBUF_RAW, pbuf_len, PBUF_POOL); EXPECT_RETNULL(p != NULL); /* first pbuf must be big enough to hold the headers */ EXPECT_RETNULL(p->len >= (sizeof(struct ip_hdr) + sizeof(struct tcp_hdr))); if (data_len > 0) { /* first pbuf must be big enough to hold at least 1 data byte, too */ EXPECT_RETNULL(p->len > (sizeof(struct ip_hdr) + sizeof(struct tcp_hdr))); } for(q = p; q != NULL; q = q->next) { memset(q->payload, 0, q->len); } iphdr = p->payload; /* fill IP header */ iphdr->dest.addr = dst_ip->addr; iphdr->src.addr = src_ip->addr; IPH_VHL_SET(iphdr, 4, IP_HLEN / 4); IPH_TOS_SET(iphdr, 0); IPH_LEN_SET(iphdr, htons(p->tot_len)); IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN)); /* let p point to TCP header */ pbuf_header(p, -(s16_t)sizeof(struct ip_hdr)); tcphdr = p->payload; tcphdr->src = htons(src_port); tcphdr->dest = htons(dst_port); tcphdr->seqno = htonl(seqno); tcphdr->ackno = htonl(ackno); TCPH_HDRLEN_SET(tcphdr, sizeof(struct tcp_hdr)/4); TCPH_FLAGS_SET(tcphdr, headerflags); tcphdr->wnd = htons(wnd); if (data_len > 0) { /* let p point to TCP data */ pbuf_header(p, -(s16_t)sizeof(struct tcp_hdr)); /* copy data */ pbuf_take(p, data, data_len); /* let p point to TCP header again */ pbuf_header(p, sizeof(struct tcp_hdr)); } /* calculate checksum */ tcphdr->chksum = inet_chksum_pseudo(p, IP_PROTO_TCP, p->tot_len, src_ip, dst_ip); pbuf_header(p, sizeof(struct ip_hdr)); return p; } /** Create a TCP segment usable for passing to tcp_input */ struct pbuf* tcp_create_segment(ip_addr_t* src_ip, ip_addr_t* dst_ip, u16_t src_port, u16_t dst_port, void* data, size_t data_len, u32_t seqno, u32_t ackno, u8_t headerflags) { return tcp_create_segment_wnd(src_ip, dst_ip, src_port, dst_port, data, data_len, seqno, ackno, headerflags, TCP_WND); } /** Create a TCP segment usable for passing to tcp_input * - IP-addresses, ports, seqno and ackno are taken from pcb * - seqno and ackno can be altered with an offset */ struct pbuf* tcp_create_rx_segment(struct tcp_pcb* pcb, void* data, size_t data_len, u32_t seqno_offset, u32_t ackno_offset, u8_t headerflags) { return tcp_create_segment(&pcb->remote_ip, &pcb->local_ip, pcb->remote_port, pcb->local_port, data, data_len, pcb->rcv_nxt + seqno_offset, pcb->lastack + ackno_offset, headerflags); } /** Create a TCP segment usable for passing to tcp_input * - IP-addresses, ports, seqno and ackno are taken from pcb * - seqno and ackno can be altered with an offset * - TCP window can be adjusted */ struct pbuf* tcp_create_rx_segment_wnd(struct tcp_pcb* pcb, void* data, size_t data_len, u32_t seqno_offset, u32_t ackno_offset, u8_t headerflags, u16_t wnd) { return tcp_create_segment_wnd(&pcb->remote_ip, &pcb->local_ip, pcb->remote_port, pcb->local_port, data, data_len, pcb->rcv_nxt + seqno_offset, pcb->lastack + ackno_offset, headerflags, wnd); } /** Safely bring a tcp_pcb into the requested state */ void tcp_set_state(struct tcp_pcb* pcb, enum tcp_state state, ip_addr_t* local_ip, ip_addr_t* remote_ip, u16_t local_port, u16_t remote_port) { /* @todo: are these all states? */ /* @todo: remove from previous list */ pcb->state = state; if (state == ESTABLISHED) { TCP_REG(&tcp_active_pcbs, pcb); pcb->local_ip.addr = local_ip->addr; pcb->local_port = local_port; pcb->remote_ip.addr = remote_ip->addr; pcb->remote_port = remote_port; } else if(state == LISTEN) { TCP_REG(&tcp_listen_pcbs.pcbs, pcb); pcb->local_ip.addr = local_ip->addr; pcb->local_port = local_port; } else if(state == TIME_WAIT) { TCP_REG(&tcp_tw_pcbs, pcb); pcb->local_ip.addr = local_ip->addr; pcb->local_port = local_port; pcb->remote_ip.addr = remote_ip->addr; pcb->remote_port = remote_port; } else { fail(); } } void test_tcp_counters_err(void* arg, err_t err) { struct test_tcp_counters* counters = arg; EXPECT_RET(arg != NULL); counters->err_calls++; counters->last_err = err; } static void test_tcp_counters_check_rxdata(struct test_tcp_counters* counters, struct pbuf* p) { struct pbuf* q; u32_t i, received; if(counters->expected_data == NULL) { /* no data to compare */ return; } EXPECT_RET(counters->recved_bytes + p->tot_len <= counters->expected_data_len); received = counters->recved_bytes; for(q = p; q != NULL; q = q->next) { char *data = q->payload; for(i = 0; i < q->len; i++) { EXPECT_RET(data[i] == counters->expected_data[received]); received++; } } EXPECT(received == counters->recved_bytes + p->tot_len); } err_t test_tcp_counters_recv(void* arg, struct tcp_pcb* pcb, struct pbuf* p, err_t err) { struct test_tcp_counters* counters = arg; EXPECT_RETX(arg != NULL, ERR_OK); EXPECT_RETX(pcb != NULL, ERR_OK); EXPECT_RETX(err == ERR_OK, ERR_OK); if (p != NULL) { if (counters->close_calls == 0) { counters->recv_calls++; test_tcp_counters_check_rxdata(counters, p); counters->recved_bytes += p->tot_len; } else { counters->recv_calls_after_close++; counters->recved_bytes_after_close += p->tot_len; } pbuf_free(p); } else { counters->close_calls++; } EXPECT(counters->recv_calls_after_close == 0 && counters->recved_bytes_after_close == 0); return ERR_OK; } /** Allocate a pcb and set up the test_tcp_counters_* callbacks */ struct tcp_pcb* test_tcp_new_counters_pcb(struct test_tcp_counters* counters) { struct tcp_pcb* pcb = tcp_new(); if (pcb != NULL) { /* set up args and callbacks */ tcp_arg(pcb, counters); tcp_recv(pcb, test_tcp_counters_recv); tcp_err(pcb, test_tcp_counters_err); pcb->snd_wnd = TCP_WND; pcb->snd_wnd_max = TCP_WND; } return pcb; } /** Calls tcp_input() after adjusting current_iphdr_dest */ void test_tcp_input(struct pbuf *p, struct netif *inp) { struct ip_hdr *iphdr = (struct ip_hdr*)p->payload; /* these lines are a hack, don't use them as an example :-) */ ip_addr_copy(*ipX_current_dest_addr(), iphdr->dest); ip_addr_copy(*ipX_current_src_addr(), iphdr->src); ip_current_netif() = inp; ip_current_header() = iphdr; /* since adding IPv6, p->payload must point to tcp header, not ip header */ pbuf_header(p, -(s16_t)sizeof(struct ip_hdr)); tcp_input(p, inp); ipX_current_dest_addr()->addr = 0; ipX_current_src_addr()->addr = 0; ip_current_netif() = NULL; ip_current_header() = NULL; } static err_t test_tcp_netif_output(struct netif *netif, struct pbuf *p, ip_addr_t *ipaddr) { struct test_tcp_txcounters *txcounters = (struct test_tcp_txcounters*)netif->state; LWIP_UNUSED_ARG(ipaddr); if (txcounters != NULL) { txcounters->num_tx_calls++; txcounters->num_tx_bytes += p->tot_len; if (txcounters->copy_tx_packets) { struct pbuf *p_copy = pbuf_alloc(PBUF_LINK, p->tot_len, PBUF_RAM); err_t err; EXPECT(p_copy != NULL); err = pbuf_copy(p_copy, p); EXPECT(err == ERR_OK); if (txcounters->tx_packets == NULL) { txcounters->tx_packets = p_copy; } else { pbuf_cat(txcounters->tx_packets, p_copy); } } } return ERR_OK; } void test_tcp_init_netif(struct netif *netif, struct test_tcp_txcounters *txcounters, ip_addr_t *ip_addr, ip_addr_t *netmask) { struct netif *n; memset(netif, 0, sizeof(struct netif)); if (txcounters != NULL) { memset(txcounters, 0, sizeof(struct test_tcp_txcounters)); netif->state = txcounters; } netif->output = test_tcp_netif_output; netif->flags |= NETIF_FLAG_UP; ip_addr_copy(netif->netmask, *netmask); ip_addr_copy(netif->ip_addr, *ip_addr); for (n = netif_list; n != NULL; n = n->next) { if (n == netif) { return; } } netif->next = NULL; netif_list = netif; } ocproxy-1.60/lwip/test/unit/tcp/tcp_helper.h000066400000000000000000000034171303453231400211430ustar00rootroot00000000000000#ifndef LWIP_HDR_TCP_HELPER_H__ #define LWIP_HDR_TCP_HELPER_H__ #include "../lwip_check.h" #include "lwip/arch.h" #include "lwip/tcp.h" #include "lwip/netif.h" /* counters used for test_tcp_counters_* callback functions */ struct test_tcp_counters { u32_t recv_calls; u32_t recved_bytes; u32_t recv_calls_after_close; u32_t recved_bytes_after_close; u32_t close_calls; u32_t err_calls; err_t last_err; char* expected_data; u32_t expected_data_len; }; struct test_tcp_txcounters { u32_t num_tx_calls; u32_t num_tx_bytes; u8_t copy_tx_packets; struct pbuf *tx_packets; }; /* Helper functions */ void tcp_remove_all(void); struct pbuf* tcp_create_segment(ip_addr_t* src_ip, ip_addr_t* dst_ip, u16_t src_port, u16_t dst_port, void* data, size_t data_len, u32_t seqno, u32_t ackno, u8_t headerflags); struct pbuf* tcp_create_rx_segment(struct tcp_pcb* pcb, void* data, size_t data_len, u32_t seqno_offset, u32_t ackno_offset, u8_t headerflags); struct pbuf* tcp_create_rx_segment_wnd(struct tcp_pcb* pcb, void* data, size_t data_len, u32_t seqno_offset, u32_t ackno_offset, u8_t headerflags, u16_t wnd); void tcp_set_state(struct tcp_pcb* pcb, enum tcp_state state, ip_addr_t* local_ip, ip_addr_t* remote_ip, u16_t local_port, u16_t remote_port); void test_tcp_counters_err(void* arg, err_t err); err_t test_tcp_counters_recv(void* arg, struct tcp_pcb* pcb, struct pbuf* p, err_t err); struct tcp_pcb* test_tcp_new_counters_pcb(struct test_tcp_counters* counters); void test_tcp_input(struct pbuf *p, struct netif *inp); void test_tcp_init_netif(struct netif *netif, struct test_tcp_txcounters *txcounters, ip_addr_t *ip_addr, ip_addr_t *netmask); #endif ocproxy-1.60/lwip/test/unit/tcp/test_tcp.c000066400000000000000000000514331303453231400206370ustar00rootroot00000000000000#include "test_tcp.h" #include "lwip/tcp_impl.h" #include "lwip/stats.h" #include "tcp_helper.h" #ifdef _MSC_VER #pragma warning(disable: 4307) /* we explicitly wrap around TCP seqnos */ #endif #if !LWIP_STATS || !TCP_STATS || !MEMP_STATS #error "This tests needs TCP- and MEMP-statistics enabled" #endif #if TCP_SND_BUF <= TCP_WND #error "This tests needs TCP_SND_BUF to be > TCP_WND" #endif static u8_t test_tcp_timer; /* our own version of tcp_tmr so we can reset fast/slow timer state */ static void test_tcp_tmr(void) { tcp_fasttmr(); if (++test_tcp_timer & 1) { tcp_slowtmr(); } } /* Setups/teardown functions */ static void tcp_setup(void) { /* reset iss to default (6510) */ tcp_ticks = 0; tcp_ticks = 0 - (tcp_next_iss() - 6510); tcp_next_iss(); tcp_ticks = 0; test_tcp_timer = 0; tcp_remove_all(); } static void tcp_teardown(void) { tcp_remove_all(); netif_list = NULL; netif_default = NULL; } /* Test functions */ /** Call tcp_new() and tcp_abort() and test memp stats */ START_TEST(test_tcp_new_abort) { struct tcp_pcb* pcb; LWIP_UNUSED_ARG(_i); fail_unless(lwip_stats.memp[MEMP_TCP_PCB].used == 0); pcb = tcp_new(); fail_unless(pcb != NULL); if (pcb != NULL) { fail_unless(lwip_stats.memp[MEMP_TCP_PCB].used == 1); tcp_abort(pcb); fail_unless(lwip_stats.memp[MEMP_TCP_PCB].used == 0); } } END_TEST /** Create an ESTABLISHED pcb and check if receive callback is called */ START_TEST(test_tcp_recv_inseq) { struct test_tcp_counters counters; struct tcp_pcb* pcb; struct pbuf* p; char data[] = {1, 2, 3, 4}; ip_addr_t remote_ip, local_ip, netmask; u16_t data_len; u16_t remote_port = 0x100, local_port = 0x101; struct netif netif; struct test_tcp_txcounters txcounters; LWIP_UNUSED_ARG(_i); /* initialize local vars */ memset(&netif, 0, sizeof(netif)); IP4_ADDR(&local_ip, 192, 168, 1, 1); IP4_ADDR(&remote_ip, 192, 168, 1, 2); IP4_ADDR(&netmask, 255, 255, 255, 0); test_tcp_init_netif(&netif, &txcounters, &local_ip, &netmask); data_len = sizeof(data); /* initialize counter struct */ memset(&counters, 0, sizeof(counters)); counters.expected_data_len = data_len; counters.expected_data = data; /* create and initialize the pcb */ pcb = test_tcp_new_counters_pcb(&counters); EXPECT_RET(pcb != NULL); tcp_set_state(pcb, ESTABLISHED, &local_ip, &remote_ip, local_port, remote_port); /* create a segment */ p = tcp_create_rx_segment(pcb, counters.expected_data, data_len, 0, 0, 0); EXPECT(p != NULL); if (p != NULL) { /* pass the segment to tcp_input */ test_tcp_input(p, &netif); /* check if counters are as expected */ EXPECT(counters.close_calls == 0); EXPECT(counters.recv_calls == 1); EXPECT(counters.recved_bytes == data_len); EXPECT(counters.err_calls == 0); } /* make sure the pcb is freed */ EXPECT(lwip_stats.memp[MEMP_TCP_PCB].used == 1); tcp_abort(pcb); EXPECT(lwip_stats.memp[MEMP_TCP_PCB].used == 0); } END_TEST /** Provoke fast retransmission by duplicate ACKs and then recover by ACKing all sent data. * At the end, send more data. */ START_TEST(test_tcp_fast_retx_recover) { struct netif netif; struct test_tcp_txcounters txcounters; struct test_tcp_counters counters; struct tcp_pcb* pcb; struct pbuf* p; char data1[] = { 1, 2, 3, 4}; char data2[] = { 5, 6, 7, 8}; char data3[] = { 9, 10, 11, 12}; char data4[] = {13, 14, 15, 16}; char data5[] = {17, 18, 19, 20}; char data6[] = {21, 22, 23, 24}; ip_addr_t remote_ip, local_ip, netmask; u16_t remote_port = 0x100, local_port = 0x101; err_t err; LWIP_UNUSED_ARG(_i); /* initialize local vars */ IP4_ADDR(&local_ip, 192, 168, 1, 1); IP4_ADDR(&remote_ip, 192, 168, 1, 2); IP4_ADDR(&netmask, 255, 255, 255, 0); test_tcp_init_netif(&netif, &txcounters, &local_ip, &netmask); memset(&counters, 0, sizeof(counters)); /* create and initialize the pcb */ pcb = test_tcp_new_counters_pcb(&counters); EXPECT_RET(pcb != NULL); tcp_set_state(pcb, ESTABLISHED, &local_ip, &remote_ip, local_port, remote_port); pcb->mss = TCP_MSS; /* disable initial congestion window (we don't send a SYN here...) */ pcb->cwnd = pcb->snd_wnd; /* send data1 */ err = tcp_write(pcb, data1, sizeof(data1), TCP_WRITE_FLAG_COPY); EXPECT_RET(err == ERR_OK); err = tcp_output(pcb); EXPECT_RET(err == ERR_OK); EXPECT_RET(txcounters.num_tx_calls == 1); EXPECT_RET(txcounters.num_tx_bytes == sizeof(data1) + sizeof(struct tcp_hdr) + sizeof(struct ip_hdr)); memset(&txcounters, 0, sizeof(txcounters)); /* "recv" ACK for data1 */ p = tcp_create_rx_segment(pcb, NULL, 0, 0, 4, TCP_ACK); EXPECT_RET(p != NULL); test_tcp_input(p, &netif); EXPECT_RET(txcounters.num_tx_calls == 0); EXPECT_RET(pcb->unacked == NULL); /* send data2 */ err = tcp_write(pcb, data2, sizeof(data2), TCP_WRITE_FLAG_COPY); EXPECT_RET(err == ERR_OK); err = tcp_output(pcb); EXPECT_RET(err == ERR_OK); EXPECT_RET(txcounters.num_tx_calls == 1); EXPECT_RET(txcounters.num_tx_bytes == sizeof(data2) + sizeof(struct tcp_hdr) + sizeof(struct ip_hdr)); memset(&txcounters, 0, sizeof(txcounters)); /* duplicate ACK for data1 (data2 is lost) */ p = tcp_create_rx_segment(pcb, NULL, 0, 0, 0, TCP_ACK); EXPECT_RET(p != NULL); test_tcp_input(p, &netif); EXPECT_RET(txcounters.num_tx_calls == 0); EXPECT_RET(pcb->dupacks == 1); /* send data3 */ err = tcp_write(pcb, data3, sizeof(data3), TCP_WRITE_FLAG_COPY); EXPECT_RET(err == ERR_OK); err = tcp_output(pcb); EXPECT_RET(err == ERR_OK); /* nagle enabled, no tx calls */ EXPECT_RET(txcounters.num_tx_calls == 0); EXPECT_RET(txcounters.num_tx_bytes == 0); memset(&txcounters, 0, sizeof(txcounters)); /* 2nd duplicate ACK for data1 (data2 and data3 are lost) */ p = tcp_create_rx_segment(pcb, NULL, 0, 0, 0, TCP_ACK); EXPECT_RET(p != NULL); test_tcp_input(p, &netif); EXPECT_RET(txcounters.num_tx_calls == 0); EXPECT_RET(pcb->dupacks == 2); /* queue data4, don't send it (unsent-oversize is != 0) */ err = tcp_write(pcb, data4, sizeof(data4), TCP_WRITE_FLAG_COPY); EXPECT_RET(err == ERR_OK); /* 3nd duplicate ACK for data1 (data2 and data3 are lost) -> fast retransmission */ p = tcp_create_rx_segment(pcb, NULL, 0, 0, 0, TCP_ACK); EXPECT_RET(p != NULL); test_tcp_input(p, &netif); /*EXPECT_RET(txcounters.num_tx_calls == 1);*/ EXPECT_RET(pcb->dupacks == 3); memset(&txcounters, 0, sizeof(txcounters)); /* TODO: check expected data?*/ /* send data5, not output yet */ err = tcp_write(pcb, data5, sizeof(data5), TCP_WRITE_FLAG_COPY); EXPECT_RET(err == ERR_OK); /*err = tcp_output(pcb); EXPECT_RET(err == ERR_OK);*/ EXPECT_RET(txcounters.num_tx_calls == 0); EXPECT_RET(txcounters.num_tx_bytes == 0); memset(&txcounters, 0, sizeof(txcounters)); { int i = 0; do { err = tcp_write(pcb, data6, TCP_MSS, TCP_WRITE_FLAG_COPY); i++; }while(err == ERR_OK); EXPECT_RET(err != ERR_OK); } err = tcp_output(pcb); EXPECT_RET(err == ERR_OK); /*EXPECT_RET(txcounters.num_tx_calls == 0); EXPECT_RET(txcounters.num_tx_bytes == 0);*/ memset(&txcounters, 0, sizeof(txcounters)); /* send even more data */ err = tcp_write(pcb, data5, sizeof(data5), TCP_WRITE_FLAG_COPY); EXPECT_RET(err == ERR_OK); err = tcp_output(pcb); EXPECT_RET(err == ERR_OK); /* ...and even more data */ err = tcp_write(pcb, data5, sizeof(data5), TCP_WRITE_FLAG_COPY); EXPECT_RET(err == ERR_OK); err = tcp_output(pcb); EXPECT_RET(err == ERR_OK); /* ...and even more data */ err = tcp_write(pcb, data5, sizeof(data5), TCP_WRITE_FLAG_COPY); EXPECT_RET(err == ERR_OK); err = tcp_output(pcb); EXPECT_RET(err == ERR_OK); /* ...and even more data */ err = tcp_write(pcb, data5, sizeof(data5), TCP_WRITE_FLAG_COPY); EXPECT_RET(err == ERR_OK); err = tcp_output(pcb); EXPECT_RET(err == ERR_OK); /* send ACKs for data2 and data3 */ p = tcp_create_rx_segment(pcb, NULL, 0, 0, 12, TCP_ACK); EXPECT_RET(p != NULL); test_tcp_input(p, &netif); /*EXPECT_RET(txcounters.num_tx_calls == 0);*/ /* ...and even more data */ err = tcp_write(pcb, data5, sizeof(data5), TCP_WRITE_FLAG_COPY); EXPECT_RET(err == ERR_OK); err = tcp_output(pcb); EXPECT_RET(err == ERR_OK); /* ...and even more data */ err = tcp_write(pcb, data5, sizeof(data5), TCP_WRITE_FLAG_COPY); EXPECT_RET(err == ERR_OK); err = tcp_output(pcb); EXPECT_RET(err == ERR_OK); #if 0 /* create expected segment */ p1 = tcp_create_rx_segment(pcb, counters.expected_data, data_len, 0, 0, 0); EXPECT_RET(p != NULL); if (p != NULL) { /* pass the segment to tcp_input */ test_tcp_input(p, &netif); /* check if counters are as expected */ EXPECT_RET(counters.close_calls == 0); EXPECT_RET(counters.recv_calls == 1); EXPECT_RET(counters.recved_bytes == data_len); EXPECT_RET(counters.err_calls == 0); } #endif /* make sure the pcb is freed */ EXPECT_RET(lwip_stats.memp[MEMP_TCP_PCB].used == 1); tcp_abort(pcb); EXPECT_RET(lwip_stats.memp[MEMP_TCP_PCB].used == 0); } END_TEST static u8_t tx_data[TCP_WND*2]; static void check_seqnos(struct tcp_seg *segs, int num_expected, u32_t *seqnos_expected) { struct tcp_seg *s = segs; int i; for (i = 0; i < num_expected; i++, s = s->next) { EXPECT_RET(s != NULL); EXPECT(s->tcphdr->seqno == htonl(seqnos_expected[i])); } EXPECT(s == NULL); } /** Send data with sequence numbers that wrap around the u32_t range. * Then, provoke fast retransmission by duplicate ACKs and check that all * segment lists are still properly sorted. */ START_TEST(test_tcp_fast_rexmit_wraparound) { struct netif netif; struct test_tcp_txcounters txcounters; struct test_tcp_counters counters; struct tcp_pcb* pcb; struct pbuf* p; ip_addr_t remote_ip, local_ip, netmask; u16_t remote_port = 0x100, local_port = 0x101; err_t err; #define SEQNO1 (0xFFFFFF00 - TCP_MSS) #define ISS 6510 u16_t i, sent_total = 0; u32_t seqnos[] = { SEQNO1, SEQNO1 + (1 * TCP_MSS), SEQNO1 + (2 * TCP_MSS), SEQNO1 + (3 * TCP_MSS), SEQNO1 + (4 * TCP_MSS), SEQNO1 + (5 * TCP_MSS)}; LWIP_UNUSED_ARG(_i); for (i = 0; i < sizeof(tx_data); i++) { tx_data[i] = (u8_t)i; } /* initialize local vars */ IP4_ADDR(&local_ip, 192, 168, 1, 1); IP4_ADDR(&remote_ip, 192, 168, 1, 2); IP4_ADDR(&netmask, 255, 255, 255, 0); test_tcp_init_netif(&netif, &txcounters, &local_ip, &netmask); memset(&counters, 0, sizeof(counters)); /* create and initialize the pcb */ tcp_ticks = SEQNO1 - ISS; pcb = test_tcp_new_counters_pcb(&counters); EXPECT_RET(pcb != NULL); EXPECT(pcb->lastack == SEQNO1); tcp_set_state(pcb, ESTABLISHED, &local_ip, &remote_ip, local_port, remote_port); pcb->mss = TCP_MSS; /* disable initial congestion window (we don't send a SYN here...) */ pcb->cwnd = 2*TCP_MSS; /* send 6 mss-sized segments */ for (i = 0; i < 6; i++) { err = tcp_write(pcb, &tx_data[sent_total], TCP_MSS, TCP_WRITE_FLAG_COPY); EXPECT_RET(err == ERR_OK); sent_total += TCP_MSS; } check_seqnos(pcb->unsent, 6, seqnos); EXPECT(pcb->unacked == NULL); err = tcp_output(pcb); EXPECT(txcounters.num_tx_calls == 2); EXPECT(txcounters.num_tx_bytes == 2 * (TCP_MSS + 40U)); memset(&txcounters, 0, sizeof(txcounters)); check_seqnos(pcb->unacked, 2, seqnos); check_seqnos(pcb->unsent, 4, &seqnos[2]); /* ACK the first segment */ p = tcp_create_rx_segment(pcb, NULL, 0, 0, TCP_MSS, TCP_ACK); test_tcp_input(p, &netif); /* ensure this didn't trigger a retransmission */ EXPECT(txcounters.num_tx_calls == 1); EXPECT(txcounters.num_tx_bytes == TCP_MSS + 40U); memset(&txcounters, 0, sizeof(txcounters)); check_seqnos(pcb->unacked, 2, &seqnos[1]); check_seqnos(pcb->unsent, 3, &seqnos[3]); /* 3 dupacks */ EXPECT(pcb->dupacks == 0); p = tcp_create_rx_segment(pcb, NULL, 0, 0, 0, TCP_ACK); test_tcp_input(p, &netif); EXPECT(txcounters.num_tx_calls == 0); EXPECT(pcb->dupacks == 1); p = tcp_create_rx_segment(pcb, NULL, 0, 0, 0, TCP_ACK); test_tcp_input(p, &netif); EXPECT(txcounters.num_tx_calls == 0); EXPECT(pcb->dupacks == 2); /* 3rd dupack -> fast rexmit */ p = tcp_create_rx_segment(pcb, NULL, 0, 0, 0, TCP_ACK); test_tcp_input(p, &netif); EXPECT(pcb->dupacks == 3); EXPECT(txcounters.num_tx_calls == 4); memset(&txcounters, 0, sizeof(txcounters)); EXPECT(pcb->unsent == NULL); check_seqnos(pcb->unacked, 5, &seqnos[1]); /* make sure the pcb is freed */ EXPECT_RET(lwip_stats.memp[MEMP_TCP_PCB].used == 1); tcp_abort(pcb); EXPECT_RET(lwip_stats.memp[MEMP_TCP_PCB].used == 0); } END_TEST /** Send data with sequence numbers that wrap around the u32_t range. * Then, provoke RTO retransmission and check that all * segment lists are still properly sorted. */ START_TEST(test_tcp_rto_rexmit_wraparound) { struct netif netif; struct test_tcp_txcounters txcounters; struct test_tcp_counters counters; struct tcp_pcb* pcb; ip_addr_t remote_ip, local_ip, netmask; u16_t remote_port = 0x100, local_port = 0x101; err_t err; #define SEQNO1 (0xFFFFFF00 - TCP_MSS) #define ISS 6510 u16_t i, sent_total = 0; u32_t seqnos[] = { SEQNO1, SEQNO1 + (1 * TCP_MSS), SEQNO1 + (2 * TCP_MSS), SEQNO1 + (3 * TCP_MSS), SEQNO1 + (4 * TCP_MSS), SEQNO1 + (5 * TCP_MSS)}; LWIP_UNUSED_ARG(_i); for (i = 0; i < sizeof(tx_data); i++) { tx_data[i] = (u8_t)i; } /* initialize local vars */ IP4_ADDR(&local_ip, 192, 168, 1, 1); IP4_ADDR(&remote_ip, 192, 168, 1, 2); IP4_ADDR(&netmask, 255, 255, 255, 0); test_tcp_init_netif(&netif, &txcounters, &local_ip, &netmask); memset(&counters, 0, sizeof(counters)); /* create and initialize the pcb */ tcp_ticks = 0; tcp_ticks = 0 - tcp_next_iss(); tcp_ticks = SEQNO1 - tcp_next_iss(); pcb = test_tcp_new_counters_pcb(&counters); EXPECT_RET(pcb != NULL); EXPECT(pcb->lastack == SEQNO1); tcp_set_state(pcb, ESTABLISHED, &local_ip, &remote_ip, local_port, remote_port); pcb->mss = TCP_MSS; /* disable initial congestion window (we don't send a SYN here...) */ pcb->cwnd = 2*TCP_MSS; /* send 6 mss-sized segments */ for (i = 0; i < 6; i++) { err = tcp_write(pcb, &tx_data[sent_total], TCP_MSS, TCP_WRITE_FLAG_COPY); EXPECT_RET(err == ERR_OK); sent_total += TCP_MSS; } check_seqnos(pcb->unsent, 6, seqnos); EXPECT(pcb->unacked == NULL); err = tcp_output(pcb); EXPECT(txcounters.num_tx_calls == 2); EXPECT(txcounters.num_tx_bytes == 2 * (TCP_MSS + 40U)); memset(&txcounters, 0, sizeof(txcounters)); check_seqnos(pcb->unacked, 2, seqnos); check_seqnos(pcb->unsent, 4, &seqnos[2]); /* call the tcp timer some times */ for (i = 0; i < 10; i++) { test_tcp_tmr(); EXPECT(txcounters.num_tx_calls == 0); } /* 11th call to tcp_tmr: RTO rexmit fires */ test_tcp_tmr(); EXPECT(txcounters.num_tx_calls == 1); check_seqnos(pcb->unacked, 1, seqnos); check_seqnos(pcb->unsent, 5, &seqnos[1]); /* fake greater cwnd */ pcb->cwnd = pcb->snd_wnd; /* send more data */ err = tcp_output(pcb); EXPECT(err == ERR_OK); /* check queues are sorted */ EXPECT(pcb->unsent == NULL); check_seqnos(pcb->unacked, 6, seqnos); /* make sure the pcb is freed */ EXPECT_RET(lwip_stats.memp[MEMP_TCP_PCB].used == 1); tcp_abort(pcb); EXPECT_RET(lwip_stats.memp[MEMP_TCP_PCB].used == 0); } END_TEST /** Provoke fast retransmission by duplicate ACKs and then recover by ACKing all sent data. * At the end, send more data. */ static void test_tcp_tx_full_window_lost(u8_t zero_window_probe_from_unsent) { struct netif netif; struct test_tcp_txcounters txcounters; struct test_tcp_counters counters; struct tcp_pcb* pcb; struct pbuf *p; ip_addr_t remote_ip, local_ip, netmask; u16_t remote_port = 0x100, local_port = 0x101; err_t err; u16_t sent_total, i; u8_t expected = 0xFE; for (i = 0; i < sizeof(tx_data); i++) { u8_t d = (u8_t)i; if (d == 0xFE) { d = 0xF0; } tx_data[i] = d; } if (zero_window_probe_from_unsent) { tx_data[TCP_WND] = expected; } else { tx_data[0] = expected; } /* initialize local vars */ IP4_ADDR(&local_ip, 192, 168, 1, 1); IP4_ADDR(&remote_ip, 192, 168, 1, 2); IP4_ADDR(&netmask, 255, 255, 255, 0); test_tcp_init_netif(&netif, &txcounters, &local_ip, &netmask); memset(&counters, 0, sizeof(counters)); memset(&txcounters, 0, sizeof(txcounters)); /* create and initialize the pcb */ pcb = test_tcp_new_counters_pcb(&counters); EXPECT_RET(pcb != NULL); tcp_set_state(pcb, ESTABLISHED, &local_ip, &remote_ip, local_port, remote_port); pcb->mss = TCP_MSS; /* disable initial congestion window (we don't send a SYN here...) */ pcb->cwnd = pcb->snd_wnd; /* send a full window (minus 1 packets) of TCP data in MSS-sized chunks */ sent_total = 0; if ((TCP_WND - TCP_MSS) % TCP_MSS != 0) { u16_t initial_data_len = (TCP_WND - TCP_MSS) % TCP_MSS; err = tcp_write(pcb, &tx_data[sent_total], initial_data_len, TCP_WRITE_FLAG_COPY); EXPECT_RET(err == ERR_OK); err = tcp_output(pcb); EXPECT_RET(err == ERR_OK); EXPECT(txcounters.num_tx_calls == 1); EXPECT(txcounters.num_tx_bytes == initial_data_len + 40U); memset(&txcounters, 0, sizeof(txcounters)); sent_total += initial_data_len; } for (; sent_total < (TCP_WND - TCP_MSS); sent_total += TCP_MSS) { err = tcp_write(pcb, &tx_data[sent_total], TCP_MSS, TCP_WRITE_FLAG_COPY); EXPECT_RET(err == ERR_OK); err = tcp_output(pcb); EXPECT_RET(err == ERR_OK); EXPECT(txcounters.num_tx_calls == 1); EXPECT(txcounters.num_tx_bytes == TCP_MSS + 40U); memset(&txcounters, 0, sizeof(txcounters)); } EXPECT(sent_total == (TCP_WND - TCP_MSS)); /* now ACK the packet before the first */ p = tcp_create_rx_segment(pcb, NULL, 0, 0, 0, TCP_ACK); test_tcp_input(p, &netif); /* ensure this didn't trigger a retransmission */ EXPECT(txcounters.num_tx_calls == 0); EXPECT(txcounters.num_tx_bytes == 0); EXPECT(pcb->persist_backoff == 0); /* send the last packet, now a complete window has been sent */ err = tcp_write(pcb, &tx_data[sent_total], TCP_MSS, TCP_WRITE_FLAG_COPY); sent_total += TCP_MSS; EXPECT_RET(err == ERR_OK); err = tcp_output(pcb); EXPECT_RET(err == ERR_OK); EXPECT(txcounters.num_tx_calls == 1); EXPECT(txcounters.num_tx_bytes == TCP_MSS + 40U); memset(&txcounters, 0, sizeof(txcounters)); EXPECT(pcb->persist_backoff == 0); if (zero_window_probe_from_unsent) { /* ACK all data but close the TX window */ p = tcp_create_rx_segment_wnd(pcb, NULL, 0, 0, TCP_WND, TCP_ACK, 0); test_tcp_input(p, &netif); /* ensure this didn't trigger any transmission */ EXPECT(txcounters.num_tx_calls == 0); EXPECT(txcounters.num_tx_bytes == 0); EXPECT(pcb->persist_backoff == 1); } /* send one byte more (out of window) -> persist timer starts */ err = tcp_write(pcb, &tx_data[sent_total], 1, TCP_WRITE_FLAG_COPY); EXPECT_RET(err == ERR_OK); err = tcp_output(pcb); EXPECT_RET(err == ERR_OK); EXPECT(txcounters.num_tx_calls == 0); EXPECT(txcounters.num_tx_bytes == 0); memset(&txcounters, 0, sizeof(txcounters)); if (!zero_window_probe_from_unsent) { /* no persist timer unless a zero window announcement has been received */ EXPECT(pcb->persist_backoff == 0); } else { EXPECT(pcb->persist_backoff == 1); /* call tcp_timer some more times to let persist timer count up */ for (i = 0; i < 4; i++) { test_tcp_tmr(); EXPECT(txcounters.num_tx_calls == 0); EXPECT(txcounters.num_tx_bytes == 0); } /* this should trigger the zero-window-probe */ txcounters.copy_tx_packets = 1; test_tcp_tmr(); txcounters.copy_tx_packets = 0; EXPECT(txcounters.num_tx_calls == 1); EXPECT(txcounters.num_tx_bytes == 1 + 40U); EXPECT(txcounters.tx_packets != NULL); if (txcounters.tx_packets != NULL) { u8_t sent; u16_t ret; ret = pbuf_copy_partial(txcounters.tx_packets, &sent, 1, 40U); EXPECT(ret == 1); EXPECT(sent == expected); } if (txcounters.tx_packets != NULL) { pbuf_free(txcounters.tx_packets); txcounters.tx_packets = NULL; } } /* make sure the pcb is freed */ EXPECT_RET(lwip_stats.memp[MEMP_TCP_PCB].used == 1); tcp_abort(pcb); EXPECT_RET(lwip_stats.memp[MEMP_TCP_PCB].used == 0); } START_TEST(test_tcp_tx_full_window_lost_from_unsent) { LWIP_UNUSED_ARG(_i); test_tcp_tx_full_window_lost(1); } END_TEST START_TEST(test_tcp_tx_full_window_lost_from_unacked) { LWIP_UNUSED_ARG(_i); test_tcp_tx_full_window_lost(0); } END_TEST /** Create the suite including all tests for this module */ Suite * tcp_suite(void) { testfunc tests[] = { TESTFUNC(test_tcp_new_abort), TESTFUNC(test_tcp_recv_inseq), TESTFUNC(test_tcp_fast_retx_recover), TESTFUNC(test_tcp_fast_rexmit_wraparound), TESTFUNC(test_tcp_rto_rexmit_wraparound), TESTFUNC(test_tcp_tx_full_window_lost_from_unacked), TESTFUNC(test_tcp_tx_full_window_lost_from_unsent) }; return create_suite("TCP", tests, sizeof(tests)/sizeof(testfunc), tcp_setup, tcp_teardown); } ocproxy-1.60/lwip/test/unit/tcp/test_tcp.h000066400000000000000000000001711303453231400206350ustar00rootroot00000000000000#ifndef LWIP_HDR_TEST_TCP_H__ #define LWIP_HDR_TEST_TCP_H__ #include "../lwip_check.h" Suite *tcp_suite(void); #endif ocproxy-1.60/lwip/test/unit/tcp/test_tcp_oos.c000066400000000000000000000772361303453231400215300ustar00rootroot00000000000000#include "test_tcp_oos.h" #include "lwip/tcp_impl.h" #include "lwip/stats.h" #include "tcp_helper.h" #if !LWIP_STATS || !TCP_STATS || !MEMP_STATS #error "This tests needs TCP- and MEMP-statistics enabled" #endif #if !TCP_QUEUE_OOSEQ #error "This tests needs TCP_QUEUE_OOSEQ enabled" #endif /** CHECK_SEGMENTS_ON_OOSEQ: * 1: check count, seqno and len of segments on pcb->ooseq (strict) * 0: only check that bytes are received in correct order (less strict) */ #define CHECK_SEGMENTS_ON_OOSEQ 1 #if CHECK_SEGMENTS_ON_OOSEQ #define EXPECT_OOSEQ(x) EXPECT(x) #else #define EXPECT_OOSEQ(x) #endif /* helper functions */ /** Get the numbers of segments on the ooseq list */ static int tcp_oos_count(struct tcp_pcb* pcb) { int num = 0; struct tcp_seg* seg = pcb->ooseq; while(seg != NULL) { num++; seg = seg->next; } return num; } /** Get the numbers of pbufs on the ooseq list */ static int tcp_oos_pbuf_count(struct tcp_pcb* pcb) { int num = 0; struct tcp_seg* seg = pcb->ooseq; while(seg != NULL) { num += pbuf_clen(seg->p); seg = seg->next; } return num; } /** Get the seqno of a segment (by index) on the ooseq list * * @param pcb the pcb to check for ooseq segments * @param seg_index index of the segment on the ooseq list * @return seqno of the segment */ static u32_t tcp_oos_seg_seqno(struct tcp_pcb* pcb, int seg_index) { int num = 0; struct tcp_seg* seg = pcb->ooseq; /* then check the actual segment */ while(seg != NULL) { if(num == seg_index) { return seg->tcphdr->seqno; } num++; seg = seg->next; } fail(); return 0; } /** Get the tcplen (datalen + SYN/FIN) of a segment (by index) on the ooseq list * * @param pcb the pcb to check for ooseq segments * @param seg_index index of the segment on the ooseq list * @return tcplen of the segment */ static int tcp_oos_seg_tcplen(struct tcp_pcb* pcb, int seg_index) { int num = 0; struct tcp_seg* seg = pcb->ooseq; /* then check the actual segment */ while(seg != NULL) { if(num == seg_index) { return TCP_TCPLEN(seg); } num++; seg = seg->next; } fail(); return -1; } /** Get the tcplen (datalen + SYN/FIN) of all segments on the ooseq list * * @param pcb the pcb to check for ooseq segments * @return tcplen of all segment */ static int tcp_oos_tcplen(struct tcp_pcb* pcb) { int len = 0; struct tcp_seg* seg = pcb->ooseq; /* then check the actual segment */ while(seg != NULL) { len += TCP_TCPLEN(seg); seg = seg->next; } return len; } /* Setup/teardown functions */ static void tcp_oos_setup(void) { tcp_remove_all(); } static void tcp_oos_teardown(void) { tcp_remove_all(); netif_list = NULL; netif_default = NULL; } /* Test functions */ /** create multiple segments and pass them to tcp_input in a wrong * order to see if ooseq-caching works correctly * FIN is received in out-of-sequence segments only */ START_TEST(test_tcp_recv_ooseq_FIN_OOSEQ) { struct test_tcp_counters counters; struct tcp_pcb* pcb; struct pbuf *p_8_9, *p_4_8, *p_4_10, *p_2_14, *p_fin, *pinseq; char data[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}; ip_addr_t remote_ip, local_ip, netmask; u16_t data_len; u16_t remote_port = 0x100, local_port = 0x101; struct netif netif; LWIP_UNUSED_ARG(_i); /* initialize local vars */ memset(&netif, 0, sizeof(netif)); IP4_ADDR(&local_ip, 192, 168, 1, 1); IP4_ADDR(&remote_ip, 192, 168, 1, 2); IP4_ADDR(&netmask, 255, 255, 255, 0); test_tcp_init_netif(&netif, NULL, &local_ip, &netmask); data_len = sizeof(data); /* initialize counter struct */ memset(&counters, 0, sizeof(counters)); counters.expected_data_len = data_len; counters.expected_data = data; /* create and initialize the pcb */ pcb = test_tcp_new_counters_pcb(&counters); EXPECT_RET(pcb != NULL); tcp_set_state(pcb, ESTABLISHED, &local_ip, &remote_ip, local_port, remote_port); /* create segments */ /* pinseq is sent as last segment! */ pinseq = tcp_create_rx_segment(pcb, &data[0], 4, 0, 0, TCP_ACK); /* p1: 8 bytes before FIN */ /* seqno: 8..16 */ p_8_9 = tcp_create_rx_segment(pcb, &data[8], 8, 8, 0, TCP_ACK|TCP_FIN); /* p2: 4 bytes before p1, including the first 4 bytes of p1 (partly duplicate) */ /* seqno: 4..11 */ p_4_8 = tcp_create_rx_segment(pcb, &data[4], 8, 4, 0, TCP_ACK); /* p3: same as p2 but 2 bytes longer */ /* seqno: 4..13 */ p_4_10 = tcp_create_rx_segment(pcb, &data[4], 10, 4, 0, TCP_ACK); /* p4: 14 bytes before FIN, includes data from p1 and p2, plus partly from pinseq */ /* seqno: 2..15 */ p_2_14 = tcp_create_rx_segment(pcb, &data[2], 14, 2, 0, TCP_ACK); /* FIN, seqno 16 */ p_fin = tcp_create_rx_segment(pcb, NULL, 0,16, 0, TCP_ACK|TCP_FIN); EXPECT(pinseq != NULL); EXPECT(p_8_9 != NULL); EXPECT(p_4_8 != NULL); EXPECT(p_4_10 != NULL); EXPECT(p_2_14 != NULL); EXPECT(p_fin != NULL); if ((pinseq != NULL) && (p_8_9 != NULL) && (p_4_8 != NULL) && (p_4_10 != NULL) && (p_2_14 != NULL) && (p_fin != NULL)) { /* pass the segment to tcp_input */ test_tcp_input(p_8_9, &netif); /* check if counters are as expected */ EXPECT(counters.close_calls == 0); EXPECT(counters.recv_calls == 0); EXPECT(counters.recved_bytes == 0); EXPECT(counters.err_calls == 0); /* check ooseq queue */ EXPECT_OOSEQ(tcp_oos_count(pcb) == 1); EXPECT_OOSEQ(tcp_oos_seg_seqno(pcb, 0) == 8); EXPECT_OOSEQ(tcp_oos_seg_tcplen(pcb, 0) == 9); /* includes FIN */ /* pass the segment to tcp_input */ test_tcp_input(p_4_8, &netif); /* check if counters are as expected */ EXPECT(counters.close_calls == 0); EXPECT(counters.recv_calls == 0); EXPECT(counters.recved_bytes == 0); EXPECT(counters.err_calls == 0); /* check ooseq queue */ EXPECT_OOSEQ(tcp_oos_count(pcb) == 2); EXPECT_OOSEQ(tcp_oos_seg_seqno(pcb, 0) == 4); EXPECT_OOSEQ(tcp_oos_seg_tcplen(pcb, 0) == 4); EXPECT_OOSEQ(tcp_oos_seg_seqno(pcb, 1) == 8); EXPECT_OOSEQ(tcp_oos_seg_tcplen(pcb, 1) == 9); /* includes FIN */ /* pass the segment to tcp_input */ test_tcp_input(p_4_10, &netif); /* check if counters are as expected */ EXPECT(counters.close_calls == 0); EXPECT(counters.recv_calls == 0); EXPECT(counters.recved_bytes == 0); EXPECT(counters.err_calls == 0); /* ooseq queue: unchanged */ EXPECT_OOSEQ(tcp_oos_count(pcb) == 2); EXPECT_OOSEQ(tcp_oos_seg_seqno(pcb, 0) == 4); EXPECT_OOSEQ(tcp_oos_seg_tcplen(pcb, 0) == 4); EXPECT_OOSEQ(tcp_oos_seg_seqno(pcb, 1) == 8); EXPECT_OOSEQ(tcp_oos_seg_tcplen(pcb, 1) == 9); /* includes FIN */ /* pass the segment to tcp_input */ test_tcp_input(p_2_14, &netif); /* check if counters are as expected */ EXPECT(counters.close_calls == 0); EXPECT(counters.recv_calls == 0); EXPECT(counters.recved_bytes == 0); EXPECT(counters.err_calls == 0); /* check ooseq queue */ EXPECT_OOSEQ(tcp_oos_count(pcb) == 1); EXPECT_OOSEQ(tcp_oos_seg_seqno(pcb, 0) == 2); EXPECT_OOSEQ(tcp_oos_seg_tcplen(pcb, 0) == 15); /* includes FIN */ /* pass the segment to tcp_input */ test_tcp_input(p_fin, &netif); /* check if counters are as expected */ EXPECT(counters.close_calls == 0); EXPECT(counters.recv_calls == 0); EXPECT(counters.recved_bytes == 0); EXPECT(counters.err_calls == 0); /* ooseq queue: unchanged */ EXPECT_OOSEQ(tcp_oos_count(pcb) == 1); EXPECT_OOSEQ(tcp_oos_seg_seqno(pcb, 0) == 2); EXPECT_OOSEQ(tcp_oos_seg_tcplen(pcb, 0) == 15); /* includes FIN */ /* pass the segment to tcp_input */ test_tcp_input(pinseq, &netif); /* check if counters are as expected */ EXPECT(counters.close_calls == 1); EXPECT(counters.recv_calls == 1); EXPECT(counters.recved_bytes == data_len); EXPECT(counters.err_calls == 0); EXPECT(pcb->ooseq == NULL); } /* make sure the pcb is freed */ EXPECT(lwip_stats.memp[MEMP_TCP_PCB].used == 1); tcp_abort(pcb); EXPECT(lwip_stats.memp[MEMP_TCP_PCB].used == 0); } END_TEST /** create multiple segments and pass them to tcp_input in a wrong * order to see if ooseq-caching works correctly * FIN is received IN-SEQUENCE at the end */ START_TEST(test_tcp_recv_ooseq_FIN_INSEQ) { struct test_tcp_counters counters; struct tcp_pcb* pcb; struct pbuf *p_1_2, *p_4_8, *p_3_11, *p_2_12, *p_15_1, *p_15_1a, *pinseq, *pinseqFIN; char data[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}; ip_addr_t remote_ip, local_ip, netmask; u16_t data_len; u16_t remote_port = 0x100, local_port = 0x101; struct netif netif; LWIP_UNUSED_ARG(_i); /* initialize local vars */ memset(&netif, 0, sizeof(netif)); IP4_ADDR(&local_ip, 192, 168, 1, 1); IP4_ADDR(&remote_ip, 192, 168, 1, 2); IP4_ADDR(&netmask, 255, 255, 255, 0); test_tcp_init_netif(&netif, NULL, &local_ip, &netmask); data_len = sizeof(data); /* initialize counter struct */ memset(&counters, 0, sizeof(counters)); counters.expected_data_len = data_len; counters.expected_data = data; /* create and initialize the pcb */ pcb = test_tcp_new_counters_pcb(&counters); EXPECT_RET(pcb != NULL); tcp_set_state(pcb, ESTABLISHED, &local_ip, &remote_ip, local_port, remote_port); /* create segments */ /* p1: 7 bytes - 2 before FIN */ /* seqno: 1..2 */ p_1_2 = tcp_create_rx_segment(pcb, &data[1], 2, 1, 0, TCP_ACK); /* p2: 4 bytes before p1, including the first 4 bytes of p1 (partly duplicate) */ /* seqno: 4..11 */ p_4_8 = tcp_create_rx_segment(pcb, &data[4], 8, 4, 0, TCP_ACK); /* p3: same as p2 but 2 bytes longer and one byte more at the front */ /* seqno: 3..13 */ p_3_11 = tcp_create_rx_segment(pcb, &data[3], 11, 3, 0, TCP_ACK); /* p4: 13 bytes - 2 before FIN - should be ignored as contained in p1 and p3 */ /* seqno: 2..13 */ p_2_12 = tcp_create_rx_segment(pcb, &data[2], 12, 2, 0, TCP_ACK); /* pinseq is the first segment that is held back to create ooseq! */ /* seqno: 0..3 */ pinseq = tcp_create_rx_segment(pcb, &data[0], 4, 0, 0, TCP_ACK); /* p5: last byte before FIN */ /* seqno: 15 */ p_15_1 = tcp_create_rx_segment(pcb, &data[15], 1, 15, 0, TCP_ACK); /* p6: same as p5, should be ignored */ p_15_1a= tcp_create_rx_segment(pcb, &data[15], 1, 15, 0, TCP_ACK); /* pinseqFIN: last 2 bytes plus FIN */ /* only segment containing seqno 14 and FIN */ pinseqFIN = tcp_create_rx_segment(pcb, &data[14], 2, 14, 0, TCP_ACK|TCP_FIN); EXPECT(pinseq != NULL); EXPECT(p_1_2 != NULL); EXPECT(p_4_8 != NULL); EXPECT(p_3_11 != NULL); EXPECT(p_2_12 != NULL); EXPECT(p_15_1 != NULL); EXPECT(p_15_1a != NULL); EXPECT(pinseqFIN != NULL); if ((pinseq != NULL) && (p_1_2 != NULL) && (p_4_8 != NULL) && (p_3_11 != NULL) && (p_2_12 != NULL) && (p_15_1 != NULL) && (p_15_1a != NULL) && (pinseqFIN != NULL)) { /* pass the segment to tcp_input */ test_tcp_input(p_1_2, &netif); /* check if counters are as expected */ EXPECT(counters.close_calls == 0); EXPECT(counters.recv_calls == 0); EXPECT(counters.recved_bytes == 0); EXPECT(counters.err_calls == 0); /* check ooseq queue */ EXPECT_OOSEQ(tcp_oos_count(pcb) == 1); EXPECT_OOSEQ(tcp_oos_seg_seqno(pcb, 0) == 1); EXPECT_OOSEQ(tcp_oos_seg_tcplen(pcb, 0) == 2); /* pass the segment to tcp_input */ test_tcp_input(p_4_8, &netif); /* check if counters are as expected */ EXPECT(counters.close_calls == 0); EXPECT(counters.recv_calls == 0); EXPECT(counters.recved_bytes == 0); EXPECT(counters.err_calls == 0); /* check ooseq queue */ EXPECT_OOSEQ(tcp_oos_count(pcb) == 2); EXPECT_OOSEQ(tcp_oos_seg_seqno(pcb, 0) == 1); EXPECT_OOSEQ(tcp_oos_seg_tcplen(pcb, 0) == 2); EXPECT_OOSEQ(tcp_oos_seg_seqno(pcb, 1) == 4); EXPECT_OOSEQ(tcp_oos_seg_tcplen(pcb, 1) == 8); /* pass the segment to tcp_input */ test_tcp_input(p_3_11, &netif); /* check if counters are as expected */ EXPECT(counters.close_calls == 0); EXPECT(counters.recv_calls == 0); EXPECT(counters.recved_bytes == 0); EXPECT(counters.err_calls == 0); /* check ooseq queue */ EXPECT_OOSEQ(tcp_oos_count(pcb) == 2); EXPECT_OOSEQ(tcp_oos_seg_seqno(pcb, 0) == 1); EXPECT_OOSEQ(tcp_oos_seg_tcplen(pcb, 0) == 2); /* p_3_11 has removed p_4_8 from ooseq */ EXPECT_OOSEQ(tcp_oos_seg_seqno(pcb, 1) == 3); EXPECT_OOSEQ(tcp_oos_seg_tcplen(pcb, 1) == 11); /* pass the segment to tcp_input */ test_tcp_input(p_2_12, &netif); /* check if counters are as expected */ EXPECT(counters.close_calls == 0); EXPECT(counters.recv_calls == 0); EXPECT(counters.recved_bytes == 0); EXPECT(counters.err_calls == 0); /* check ooseq queue */ EXPECT_OOSEQ(tcp_oos_count(pcb) == 2); EXPECT_OOSEQ(tcp_oos_seg_seqno(pcb, 0) == 1); EXPECT_OOSEQ(tcp_oos_seg_tcplen(pcb, 0) == 1); EXPECT_OOSEQ(tcp_oos_seg_seqno(pcb, 1) == 2); EXPECT_OOSEQ(tcp_oos_seg_tcplen(pcb, 1) == 12); /* pass the segment to tcp_input */ test_tcp_input(pinseq, &netif); /* check if counters are as expected */ EXPECT(counters.close_calls == 0); EXPECT(counters.recv_calls == 1); EXPECT(counters.recved_bytes == 14); EXPECT(counters.err_calls == 0); EXPECT(pcb->ooseq == NULL); /* pass the segment to tcp_input */ test_tcp_input(p_15_1, &netif); /* check if counters are as expected */ EXPECT(counters.close_calls == 0); EXPECT(counters.recv_calls == 1); EXPECT(counters.recved_bytes == 14); EXPECT(counters.err_calls == 0); /* check ooseq queue */ EXPECT_OOSEQ(tcp_oos_count(pcb) == 1); EXPECT_OOSEQ(tcp_oos_seg_seqno(pcb, 0) == 15); EXPECT_OOSEQ(tcp_oos_seg_tcplen(pcb, 0) == 1); /* pass the segment to tcp_input */ test_tcp_input(p_15_1a, &netif); /* check if counters are as expected */ EXPECT(counters.close_calls == 0); EXPECT(counters.recv_calls == 1); EXPECT(counters.recved_bytes == 14); EXPECT(counters.err_calls == 0); /* check ooseq queue: unchanged */ EXPECT_OOSEQ(tcp_oos_count(pcb) == 1); EXPECT_OOSEQ(tcp_oos_seg_seqno(pcb, 0) == 15); EXPECT_OOSEQ(tcp_oos_seg_tcplen(pcb, 0) == 1); /* pass the segment to tcp_input */ test_tcp_input(pinseqFIN, &netif); /* check if counters are as expected */ EXPECT(counters.close_calls == 1); EXPECT(counters.recv_calls == 2); EXPECT(counters.recved_bytes == data_len); EXPECT(counters.err_calls == 0); EXPECT(pcb->ooseq == NULL); } /* make sure the pcb is freed */ EXPECT(lwip_stats.memp[MEMP_TCP_PCB].used == 1); tcp_abort(pcb); EXPECT(lwip_stats.memp[MEMP_TCP_PCB].used == 0); } END_TEST static char data_full_wnd[TCP_WND]; /** create multiple segments and pass them to tcp_input with the first segment missing * to simulate overruning the rxwin with ooseq queueing enabled */ START_TEST(test_tcp_recv_ooseq_overrun_rxwin) { #if !TCP_OOSEQ_MAX_BYTES && !TCP_OOSEQ_MAX_PBUFS int i, k; struct test_tcp_counters counters; struct tcp_pcb* pcb; struct pbuf *pinseq, *p_ovr; ip_addr_t remote_ip, local_ip, netmask; u16_t remote_port = 0x100, local_port = 0x101; struct netif netif; int datalen = 0; int datalen2; for(i = 0; i < sizeof(data_full_wnd); i++) { data_full_wnd[i] = (char)i; } /* initialize local vars */ memset(&netif, 0, sizeof(netif)); IP4_ADDR(&local_ip, 192, 168, 1, 1); IP4_ADDR(&remote_ip, 192, 168, 1, 2); IP4_ADDR(&netmask, 255, 255, 255, 0); test_tcp_init_netif(&netif, NULL, &local_ip, &netmask); /* initialize counter struct */ memset(&counters, 0, sizeof(counters)); counters.expected_data_len = TCP_WND; counters.expected_data = data_full_wnd; /* create and initialize the pcb */ pcb = test_tcp_new_counters_pcb(&counters); EXPECT_RET(pcb != NULL); tcp_set_state(pcb, ESTABLISHED, &local_ip, &remote_ip, local_port, remote_port); pcb->rcv_nxt = 0x8000; /* create segments */ /* pinseq is sent as last segment! */ pinseq = tcp_create_rx_segment(pcb, &data_full_wnd[0], TCP_MSS, 0, 0, TCP_ACK); for(i = TCP_MSS, k = 0; i < TCP_WND; i += TCP_MSS, k++) { int count, expected_datalen; struct pbuf *p = tcp_create_rx_segment(pcb, &data_full_wnd[TCP_MSS*(k+1)], TCP_MSS, TCP_MSS*(k+1), 0, TCP_ACK); EXPECT_RET(p != NULL); /* pass the segment to tcp_input */ test_tcp_input(p, &netif); /* check if counters are as expected */ EXPECT(counters.close_calls == 0); EXPECT(counters.recv_calls == 0); EXPECT(counters.recved_bytes == 0); EXPECT(counters.err_calls == 0); /* check ooseq queue */ count = tcp_oos_count(pcb); EXPECT_OOSEQ(count == k+1); datalen = tcp_oos_tcplen(pcb); if (i + TCP_MSS < TCP_WND) { expected_datalen = (k+1)*TCP_MSS; } else { expected_datalen = TCP_WND - TCP_MSS; } if (datalen != expected_datalen) { EXPECT_OOSEQ(datalen == expected_datalen); } } /* pass in one more segment, cleary overrunning the rxwin */ p_ovr = tcp_create_rx_segment(pcb, &data_full_wnd[TCP_MSS*(k+1)], TCP_MSS, TCP_MSS*(k+1), 0, TCP_ACK); EXPECT_RET(p_ovr != NULL); /* pass the segment to tcp_input */ test_tcp_input(p_ovr, &netif); /* check if counters are as expected */ EXPECT(counters.close_calls == 0); EXPECT(counters.recv_calls == 0); EXPECT(counters.recved_bytes == 0); EXPECT(counters.err_calls == 0); /* check ooseq queue */ EXPECT_OOSEQ(tcp_oos_count(pcb) == k); datalen2 = tcp_oos_tcplen(pcb); EXPECT_OOSEQ(datalen == datalen2); /* now pass inseq */ test_tcp_input(pinseq, &netif); EXPECT(pcb->ooseq == NULL); /* make sure the pcb is freed */ EXPECT(lwip_stats.memp[MEMP_TCP_PCB].used == 1); tcp_abort(pcb); EXPECT(lwip_stats.memp[MEMP_TCP_PCB].used == 0); #endif /* !TCP_OOSEQ_MAX_BYTES && !TCP_OOSEQ_MAX_PBUFS */ LWIP_UNUSED_ARG(_i); } END_TEST START_TEST(test_tcp_recv_ooseq_max_bytes) { #if TCP_OOSEQ_MAX_BYTES && (TCP_OOSEQ_MAX_BYTES < (TCP_WND + 1)) && (PBUF_POOL_BUFSIZE >= (TCP_MSS + PBUF_LINK_HLEN + PBUF_IP_HLEN + PBUF_TRANSPORT_HLEN)) int i, k; struct test_tcp_counters counters; struct tcp_pcb* pcb; struct pbuf *p_ovr; ip_addr_t remote_ip, local_ip, netmask; u16_t remote_port = 0x100, local_port = 0x101; struct netif netif; int datalen = 0; int datalen2; for(i = 0; i < sizeof(data_full_wnd); i++) { data_full_wnd[i] = (char)i; } /* initialize local vars */ memset(&netif, 0, sizeof(netif)); IP4_ADDR(&local_ip, 192, 168, 1, 1); IP4_ADDR(&remote_ip, 192, 168, 1, 2); IP4_ADDR(&netmask, 255, 255, 255, 0); test_tcp_init_netif(&netif, NULL, &local_ip, &netmask); /* initialize counter struct */ memset(&counters, 0, sizeof(counters)); counters.expected_data_len = TCP_WND; counters.expected_data = data_full_wnd; /* create and initialize the pcb */ pcb = test_tcp_new_counters_pcb(&counters); EXPECT_RET(pcb != NULL); tcp_set_state(pcb, ESTABLISHED, &local_ip, &remote_ip, local_port, remote_port); pcb->rcv_nxt = 0x8000; /* don't 'recv' the first segment (1 byte) so that all other segments will be ooseq */ /* create segments and 'recv' them */ for(k = 1, i = 1; k < TCP_OOSEQ_MAX_BYTES; k += TCP_MSS, i++) { int count; struct pbuf *p = tcp_create_rx_segment(pcb, &data_full_wnd[k], TCP_MSS, k, 0, TCP_ACK); EXPECT_RET(p != NULL); EXPECT_RET(p->next == NULL); /* pass the segment to tcp_input */ test_tcp_input(p, &netif); /* check if counters are as expected */ EXPECT(counters.close_calls == 0); EXPECT(counters.recv_calls == 0); EXPECT(counters.recved_bytes == 0); EXPECT(counters.err_calls == 0); /* check ooseq queue */ count = tcp_oos_pbuf_count(pcb); EXPECT_OOSEQ(count == i); datalen = tcp_oos_tcplen(pcb); EXPECT_OOSEQ(datalen == (i * TCP_MSS)); } /* pass in one more segment, overrunning the limit */ p_ovr = tcp_create_rx_segment(pcb, &data_full_wnd[k+1], 1, k+1, 0, TCP_ACK); EXPECT_RET(p_ovr != NULL); /* pass the segment to tcp_input */ test_tcp_input(p_ovr, &netif); /* check if counters are as expected */ EXPECT(counters.close_calls == 0); EXPECT(counters.recv_calls == 0); EXPECT(counters.recved_bytes == 0); EXPECT(counters.err_calls == 0); /* check ooseq queue (ensure the new segment was not accepted) */ EXPECT_OOSEQ(tcp_oos_count(pcb) == (i-1)); datalen2 = tcp_oos_tcplen(pcb); EXPECT_OOSEQ(datalen2 == ((i-1) * TCP_MSS)); /* make sure the pcb is freed */ EXPECT(lwip_stats.memp[MEMP_TCP_PCB].used == 1); tcp_abort(pcb); EXPECT(lwip_stats.memp[MEMP_TCP_PCB].used == 0); #endif /* TCP_OOSEQ_MAX_BYTES && (TCP_OOSEQ_MAX_BYTES < (TCP_WND + 1)) && (PBUF_POOL_BUFSIZE >= (TCP_MSS + PBUF_LINK_HLEN + PBUF_IP_HLEN + PBUF_TRANSPORT_HLEN)) */ LWIP_UNUSED_ARG(_i); } END_TEST START_TEST(test_tcp_recv_ooseq_max_pbufs) { #if TCP_OOSEQ_MAX_PBUFS && (TCP_OOSEQ_MAX_PBUFS < ((TCP_WND / TCP_MSS) + 1)) && (PBUF_POOL_BUFSIZE >= (TCP_MSS + PBUF_LINK_HLEN + PBUF_IP_HLEN + PBUF_TRANSPORT_HLEN)) int i; struct test_tcp_counters counters; struct tcp_pcb* pcb; struct pbuf *p_ovr; ip_addr_t remote_ip, local_ip, netmask; u16_t remote_port = 0x100, local_port = 0x101; struct netif netif; int datalen = 0; int datalen2; for(i = 0; i < sizeof(data_full_wnd); i++) { data_full_wnd[i] = (char)i; } /* initialize local vars */ memset(&netif, 0, sizeof(netif)); IP4_ADDR(&local_ip, 192, 168, 1, 1); IP4_ADDR(&remote_ip, 192, 168, 1, 2); IP4_ADDR(&netmask, 255, 255, 255, 0); test_tcp_init_netif(&netif, NULL, &local_ip, &netmask); /* initialize counter struct */ memset(&counters, 0, sizeof(counters)); counters.expected_data_len = TCP_WND; counters.expected_data = data_full_wnd; /* create and initialize the pcb */ pcb = test_tcp_new_counters_pcb(&counters); EXPECT_RET(pcb != NULL); tcp_set_state(pcb, ESTABLISHED, &local_ip, &remote_ip, local_port, remote_port); pcb->rcv_nxt = 0x8000; /* don't 'recv' the first segment (1 byte) so that all other segments will be ooseq */ /* create segments and 'recv' them */ for(i = 1; i <= TCP_OOSEQ_MAX_PBUFS; i++) { int count; struct pbuf *p = tcp_create_rx_segment(pcb, &data_full_wnd[i], 1, i, 0, TCP_ACK); EXPECT_RET(p != NULL); EXPECT_RET(p->next == NULL); /* pass the segment to tcp_input */ test_tcp_input(p, &netif); /* check if counters are as expected */ EXPECT(counters.close_calls == 0); EXPECT(counters.recv_calls == 0); EXPECT(counters.recved_bytes == 0); EXPECT(counters.err_calls == 0); /* check ooseq queue */ count = tcp_oos_pbuf_count(pcb); EXPECT_OOSEQ(count == i); datalen = tcp_oos_tcplen(pcb); EXPECT_OOSEQ(datalen == i); } /* pass in one more segment, overrunning the limit */ p_ovr = tcp_create_rx_segment(pcb, &data_full_wnd[i+1], 1, i+1, 0, TCP_ACK); EXPECT_RET(p_ovr != NULL); /* pass the segment to tcp_input */ test_tcp_input(p_ovr, &netif); /* check if counters are as expected */ EXPECT(counters.close_calls == 0); EXPECT(counters.recv_calls == 0); EXPECT(counters.recved_bytes == 0); EXPECT(counters.err_calls == 0); /* check ooseq queue (ensure the new segment was not accepted) */ EXPECT_OOSEQ(tcp_oos_count(pcb) == (i-1)); datalen2 = tcp_oos_tcplen(pcb); EXPECT_OOSEQ(datalen2 == (i-1)); /* make sure the pcb is freed */ EXPECT(lwip_stats.memp[MEMP_TCP_PCB].used == 1); tcp_abort(pcb); EXPECT(lwip_stats.memp[MEMP_TCP_PCB].used == 0); #endif /* TCP_OOSEQ_MAX_PBUFS && (TCP_OOSEQ_MAX_BYTES < (TCP_WND + 1)) && (PBUF_POOL_BUFSIZE >= (TCP_MSS + PBUF_LINK_HLEN + PBUF_IP_HLEN + PBUF_TRANSPORT_HLEN)) */ LWIP_UNUSED_ARG(_i); } END_TEST static void check_rx_counters(struct tcp_pcb *pcb, struct test_tcp_counters *counters, u32_t exp_close_calls, u32_t exp_rx_calls, u32_t exp_rx_bytes, u32_t exp_err_calls, int exp_oos_count, int exp_oos_len) { int oos_len; EXPECT(counters->close_calls == exp_close_calls); EXPECT(counters->recv_calls == exp_rx_calls); EXPECT(counters->recved_bytes == exp_rx_bytes); EXPECT(counters->err_calls == exp_err_calls); /* check that pbuf is queued in ooseq */ EXPECT_OOSEQ(tcp_oos_count(pcb) == exp_oos_count); oos_len = tcp_oos_tcplen(pcb); EXPECT_OOSEQ(exp_oos_len == oos_len); } /* this test uses 4 packets: * - data (len=TCP_MSS) * - FIN * - data after FIN (len=1) (invalid) * - 2nd FIN (invalid) * * the parameter 'delay_packet' is a bitmask that choses which on these packets is ooseq */ static void test_tcp_recv_ooseq_double_FINs(int delay_packet) { int i, k; struct test_tcp_counters counters; struct tcp_pcb* pcb; struct pbuf *p_normal_fin, *p_data_after_fin, *p, *p_2nd_fin_ooseq; ip_addr_t remote_ip, local_ip, netmask; u16_t remote_port = 0x100, local_port = 0x101; struct netif netif; u32_t exp_rx_calls = 0, exp_rx_bytes = 0, exp_close_calls = 0, exp_oos_pbufs = 0, exp_oos_tcplen = 0; int first_dropped = 0xff; int last_dropped = 0; for(i = 0; i < sizeof(data_full_wnd); i++) { data_full_wnd[i] = (char)i; } /* initialize local vars */ memset(&netif, 0, sizeof(netif)); IP4_ADDR(&local_ip, 192, 168, 1, 1); IP4_ADDR(&remote_ip, 192, 168, 1, 2); IP4_ADDR(&netmask, 255, 255, 255, 0); test_tcp_init_netif(&netif, NULL, &local_ip, &netmask); /* initialize counter struct */ memset(&counters, 0, sizeof(counters)); counters.expected_data_len = TCP_WND; counters.expected_data = data_full_wnd; /* create and initialize the pcb */ pcb = test_tcp_new_counters_pcb(&counters); EXPECT_RET(pcb != NULL); tcp_set_state(pcb, ESTABLISHED, &local_ip, &remote_ip, local_port, remote_port); pcb->rcv_nxt = 0x8000; /* create segments */ p = tcp_create_rx_segment(pcb, &data_full_wnd[0], TCP_MSS, 0, 0, TCP_ACK); p_normal_fin = tcp_create_rx_segment(pcb, NULL, 0, TCP_MSS, 0, TCP_ACK|TCP_FIN); k = 1; p_data_after_fin = tcp_create_rx_segment(pcb, &data_full_wnd[TCP_MSS+1], k, TCP_MSS+1, 0, TCP_ACK); p_2nd_fin_ooseq = tcp_create_rx_segment(pcb, NULL, 0, TCP_MSS+1+k, 0, TCP_ACK|TCP_FIN); if(delay_packet & 1) { /* drop normal data */ first_dropped = 1; last_dropped = 1; } else { /* send normal data */ test_tcp_input(p, &netif); exp_rx_calls++; exp_rx_bytes += TCP_MSS; } /* check if counters are as expected */ check_rx_counters(pcb, &counters, exp_close_calls, exp_rx_calls, exp_rx_bytes, 0, exp_oos_pbufs, exp_oos_tcplen); if(delay_packet & 2) { /* drop FIN */ if(first_dropped > 2) { first_dropped = 2; } last_dropped = 2; } else { /* send FIN */ test_tcp_input(p_normal_fin, &netif); if (first_dropped < 2) { /* already dropped packets, this one is ooseq */ exp_oos_pbufs++; exp_oos_tcplen++; } else { /* inseq */ exp_close_calls++; } } /* check if counters are as expected */ check_rx_counters(pcb, &counters, exp_close_calls, exp_rx_calls, exp_rx_bytes, 0, exp_oos_pbufs, exp_oos_tcplen); if(delay_packet & 4) { /* drop data-after-FIN */ if(first_dropped > 3) { first_dropped = 3; } last_dropped = 3; } else { /* send data-after-FIN */ test_tcp_input(p_data_after_fin, &netif); if (first_dropped < 3) { /* already dropped packets, this one is ooseq */ if (delay_packet & 2) { /* correct FIN was ooseq */ exp_oos_pbufs++; exp_oos_tcplen += k; } } else { /* inseq: no change */ } } /* check if counters are as expected */ check_rx_counters(pcb, &counters, exp_close_calls, exp_rx_calls, exp_rx_bytes, 0, exp_oos_pbufs, exp_oos_tcplen); if(delay_packet & 8) { /* drop 2nd-FIN */ if(first_dropped > 4) { first_dropped = 4; } last_dropped = 4; } else { /* send 2nd-FIN */ test_tcp_input(p_2nd_fin_ooseq, &netif); if (first_dropped < 3) { /* already dropped packets, this one is ooseq */ if (delay_packet & 2) { /* correct FIN was ooseq */ exp_oos_pbufs++; exp_oos_tcplen++; } } else { /* inseq: no change */ } } /* check if counters are as expected */ check_rx_counters(pcb, &counters, exp_close_calls, exp_rx_calls, exp_rx_bytes, 0, exp_oos_pbufs, exp_oos_tcplen); if(delay_packet & 1) { /* dropped normal data before */ test_tcp_input(p, &netif); exp_rx_calls++; exp_rx_bytes += TCP_MSS; if((delay_packet & 2) == 0) { /* normal FIN was NOT delayed */ exp_close_calls++; exp_oos_pbufs = exp_oos_tcplen = 0; } } /* check if counters are as expected */ check_rx_counters(pcb, &counters, exp_close_calls, exp_rx_calls, exp_rx_bytes, 0, exp_oos_pbufs, exp_oos_tcplen); if(delay_packet & 2) { /* dropped normal FIN before */ test_tcp_input(p_normal_fin, &netif); exp_close_calls++; exp_oos_pbufs = exp_oos_tcplen = 0; } /* check if counters are as expected */ check_rx_counters(pcb, &counters, exp_close_calls, exp_rx_calls, exp_rx_bytes, 0, exp_oos_pbufs, exp_oos_tcplen); if(delay_packet & 4) { /* dropped data-after-FIN before */ test_tcp_input(p_data_after_fin, &netif); } /* check if counters are as expected */ check_rx_counters(pcb, &counters, exp_close_calls, exp_rx_calls, exp_rx_bytes, 0, exp_oos_pbufs, exp_oos_tcplen); if(delay_packet & 8) { /* dropped 2nd-FIN before */ test_tcp_input(p_2nd_fin_ooseq, &netif); } /* check if counters are as expected */ check_rx_counters(pcb, &counters, exp_close_calls, exp_rx_calls, exp_rx_bytes, 0, exp_oos_pbufs, exp_oos_tcplen); /* check that ooseq data has been dumped */ EXPECT(pcb->ooseq == NULL); /* make sure the pcb is freed */ EXPECT(lwip_stats.memp[MEMP_TCP_PCB].used == 1); tcp_abort(pcb); EXPECT(lwip_stats.memp[MEMP_TCP_PCB].used == 0); } /** create multiple segments and pass them to tcp_input with the first segment missing * to simulate overruning the rxwin with ooseq queueing enabled */ #define FIN_TEST(name, num) \ START_TEST(name) \ { \ LWIP_UNUSED_ARG(_i); \ test_tcp_recv_ooseq_double_FINs(num); \ } \ END_TEST FIN_TEST(test_tcp_recv_ooseq_double_FIN_0, 0) FIN_TEST(test_tcp_recv_ooseq_double_FIN_1, 1) FIN_TEST(test_tcp_recv_ooseq_double_FIN_2, 2) FIN_TEST(test_tcp_recv_ooseq_double_FIN_3, 3) FIN_TEST(test_tcp_recv_ooseq_double_FIN_4, 4) FIN_TEST(test_tcp_recv_ooseq_double_FIN_5, 5) FIN_TEST(test_tcp_recv_ooseq_double_FIN_6, 6) FIN_TEST(test_tcp_recv_ooseq_double_FIN_7, 7) FIN_TEST(test_tcp_recv_ooseq_double_FIN_8, 8) FIN_TEST(test_tcp_recv_ooseq_double_FIN_9, 9) FIN_TEST(test_tcp_recv_ooseq_double_FIN_10, 10) FIN_TEST(test_tcp_recv_ooseq_double_FIN_11, 11) FIN_TEST(test_tcp_recv_ooseq_double_FIN_12, 12) FIN_TEST(test_tcp_recv_ooseq_double_FIN_13, 13) FIN_TEST(test_tcp_recv_ooseq_double_FIN_14, 14) FIN_TEST(test_tcp_recv_ooseq_double_FIN_15, 15) /** Create the suite including all tests for this module */ Suite * tcp_oos_suite(void) { testfunc tests[] = { TESTFUNC(test_tcp_recv_ooseq_FIN_OOSEQ), TESTFUNC(test_tcp_recv_ooseq_FIN_INSEQ), TESTFUNC(test_tcp_recv_ooseq_overrun_rxwin), TESTFUNC(test_tcp_recv_ooseq_max_bytes), TESTFUNC(test_tcp_recv_ooseq_max_pbufs), TESTFUNC(test_tcp_recv_ooseq_double_FIN_0), TESTFUNC(test_tcp_recv_ooseq_double_FIN_1), TESTFUNC(test_tcp_recv_ooseq_double_FIN_2), TESTFUNC(test_tcp_recv_ooseq_double_FIN_3), TESTFUNC(test_tcp_recv_ooseq_double_FIN_4), TESTFUNC(test_tcp_recv_ooseq_double_FIN_5), TESTFUNC(test_tcp_recv_ooseq_double_FIN_6), TESTFUNC(test_tcp_recv_ooseq_double_FIN_7), TESTFUNC(test_tcp_recv_ooseq_double_FIN_8), TESTFUNC(test_tcp_recv_ooseq_double_FIN_9), TESTFUNC(test_tcp_recv_ooseq_double_FIN_10), TESTFUNC(test_tcp_recv_ooseq_double_FIN_11), TESTFUNC(test_tcp_recv_ooseq_double_FIN_12), TESTFUNC(test_tcp_recv_ooseq_double_FIN_13), TESTFUNC(test_tcp_recv_ooseq_double_FIN_14), TESTFUNC(test_tcp_recv_ooseq_double_FIN_15) }; return create_suite("TCP_OOS", tests, sizeof(tests)/sizeof(testfunc), tcp_oos_setup, tcp_oos_teardown); } ocproxy-1.60/lwip/test/unit/tcp/test_tcp_oos.h000066400000000000000000000002051303453231400215130ustar00rootroot00000000000000#ifndef LWIP_HDR_TEST_TCP_OOS_H__ #define LWIP_HDR_TEST_TCP_OOS_H__ #include "../lwip_check.h" Suite *tcp_oos_suite(void); #endif ocproxy-1.60/lwip/test/unit/udp/000077500000000000000000000000001303453231400166425ustar00rootroot00000000000000ocproxy-1.60/lwip/test/unit/udp/test_udp.c000066400000000000000000000022761303453231400206440ustar00rootroot00000000000000#include "test_udp.h" #include "lwip/udp.h" #include "lwip/stats.h" #if !LWIP_STATS || !UDP_STATS || !MEMP_STATS #error "This tests needs UDP- and MEMP-statistics enabled" #endif /* Helper functions */ static void udp_remove_all(void) { struct udp_pcb *pcb = udp_pcbs; struct udp_pcb *pcb2; while(pcb != NULL) { pcb2 = pcb; pcb = pcb->next; udp_remove(pcb2); } fail_unless(lwip_stats.memp[MEMP_UDP_PCB].used == 0); } /* Setups/teardown functions */ static void udp_setup(void) { udp_remove_all(); } static void udp_teardown(void) { udp_remove_all(); } /* Test functions */ START_TEST(test_udp_new_remove) { struct udp_pcb* pcb; LWIP_UNUSED_ARG(_i); fail_unless(lwip_stats.memp[MEMP_UDP_PCB].used == 0); pcb = udp_new(); fail_unless(pcb != NULL); if (pcb != NULL) { fail_unless(lwip_stats.memp[MEMP_UDP_PCB].used == 1); udp_remove(pcb); fail_unless(lwip_stats.memp[MEMP_UDP_PCB].used == 0); } } END_TEST /** Create the suite including all tests for this module */ Suite * udp_suite(void) { testfunc tests[] = { TESTFUNC(test_udp_new_remove), }; return create_suite("UDP", tests, sizeof(tests)/sizeof(testfunc), udp_setup, udp_teardown); } ocproxy-1.60/lwip/test/unit/udp/test_udp.h000066400000000000000000000001711303453231400206410ustar00rootroot00000000000000#ifndef LWIP_HDR_TEST_UDP_H__ #define LWIP_HDR_TEST_UDP_H__ #include "../lwip_check.h" Suite* udp_suite(void); #endif ocproxy-1.60/ocproxy.1000066400000000000000000000115221303453231400147270ustar00rootroot00000000000000.\" Hey, EMACS: -*- nroff -*- .\" (C) Copyright 2012 David Edmondson , .\" .\" First parameter, NAME, should be all caps .\" Second parameter, SECTION, should be 1-8, maybe w/ subsection .\" other parameters are allowed: see man(7), man(1) .TH OCPROXY 1 "November 20, 2012" .\" Please adjust this date whenever revising the manpage. .\" .\" Some roff macros, for reference: .\" .nh disable hyphenation .\" .hy enable hyphenation .\" .ad l left justify .\" .ad b justify to both left and right margins .\" .nf disable filling .\" .fi enable filling .\" .br insert line break .\" .sp insert n+1 empty lines .\" for manpage-specific macros, see man(7) .SH NAME ocproxy \- lwip based proxy for openconnect .SH SYNOPSIS .B ocproxy .RI [ options ] .SH DESCRIPTION This manual page documents briefly the .B ocproxy command. .PP .\" TeX users may be more comfortable with the \fB\fP and .\" \fI\fP escape sequences to invode bold face and italics, .\" respectively. \fBocproxy\fP is a program that provides a SOCKS and port-forwarding proxy when used in conjunction with .BR openconnect (1). When using ocproxy, OpenConnect only handles network activity that the user specifically asks to proxy, so the VPN tunnel no longer "hijacks" all network traffic on the host. .PP \fBocproxy\fP accomplishes this by running a lwIP network stack in userland, so the OS kernel is no longer directly handling packets sent to and from the VPN connection. .SH "BASIC USAGE" .PP \fBocproxy\fP should be invoked directly from OpenConnect or another VPN program; a file descriptor number is passed through the \fBVPNFD\fP environment variable to tell \fBocproxy\fP how to send and receive VPN traffic. For example: .RS openconnect \-\-script\-tun \-\-script "ocproxy \-D 11080 \-L2222:unix\-host:22" vpn.example.com .RE .PP Commonly used options include: .TP \fB\-D, \-\-dynfw\fP [\fIbind_address\fP:]\fIport\fP Start up a SOCKS5 server on TCP port \fIport\fP to dynamically forward application-level traffic over the VPN proxy. This is intended to resemble the \fB-D\fP option to \fBssh\fP(1). If \fIbind_address\fP is unspecified, \fBocproxy\fP will bind to the loopback interface by default unless \fB\-\-allow\-remote\fP is used. .TP \fB\-L, \-\-localfw\fP \fIport:host:hostport\fP Bind to port local TCP port \fIport\fP, and forward incoming connections to \fIhost:hostport\fP on the VPN. \fIhost\fP can be a DNS name or a dotted-quad IP address. If the VPN supplied a default DNS domain name or \fB\-\-domain\fP was specified on the command line, unqualified hostnames may be used. This is intended to resemble the \fB-L\fP option to \fBssh\fP(1). .TP \fB\-g, \-\-allow\-remote\fP Local listening sockets opened by the \fB\-\-dynfw\fP and \fB\-\-localfw\fP options, by default, will be bound to the loopback interface only (127.0.0.1) so they are only available on the local machine. If \fB\-\-allow\-remote\fP is specified, the sockets will be bound to \fBINADDR_ANY\fP (0.0.0.0) instead, and other hosts may connect to them. This is intended to resemble the \fB-g\fP option to \fBssh\fP(1). .TP \fB\-k, \-\-keepalive\fP \fIinterval\fP Send a TCP keepalive packet every \fIinterval\fP seconds on each open connection, on the VPN side. This can help avoid idle timeouts, both on the VPN gateway and on any stateful firewalls in between the two ends. .SH "ADVANCED USAGE" .PP These options may be useful for debugging \fBocproxy\fP or diagnosing problems: .TP \fB\-v, \-\-verbose\fP Enable verbose debugging output. .TP \fB\-T, \-\-tcpdump\fP Write a log of all TCP or UDP packets traversing the VPN to \fI/tmp/tcpdump\fP. The format largely mirrors the output of the tcpdump(8) utility. .PP \fBocproxy\fP will normally retrieve IP configuration parameters through environment variables provided by OpenConnect. These options may be used to override the autodetected parameters: .TP \fB\-I, \-\-ip\fP \fIlocal_ip\fP Use \fIlocal_ip\fP for the VPN side IP address. Example: 192.168.5.20. This is normally set through the \fBINTERNAL_IP4_ADDRESS\fP environment variable. .TP \fB\-M, \-\-mtu\fP \fImtu_bytes\fP Use \fImtu_bytes\fP as the maximum transmit unit on the VPN interface; it generally depends on DTLS and UDP packet overhead. Example: 1300. This is normally set through the \fBINTERNAL_IP4_MTU\fP environment variable. .TP \fB\-d, \-\-dns\fP \fIdns_ip\fP Send all VPN side DNS queries to server \fIdns_ip\fP. Example: 192.168.5.2. This is normally set through the \fBINTERNAL_IP4_DNS\fP environment variable. .TP \fB\-o, \-\-domain\fP \fIdomain\fP Use \fIdomain\fP as the default DNS domain, for unqualified hostnames. This is normally set through the \fBCISCO_DEF_DOMAIN\fP environment variable. .SH SEE ALSO .BR vpnns (1), .BR openconnect (8), .BR ssh (1) .PP .I http://savannah.nongnu.org/projects/lwip/ ocproxy-1.60/ppa/000077500000000000000000000000001303453231400137215ustar00rootroot00000000000000ocproxy-1.60/ppa/compat000066400000000000000000000000021303453231400151170ustar00rootroot000000000000009 ocproxy-1.60/ppa/control000066400000000000000000000017451303453231400153330ustar00rootroot00000000000000Source: ocproxy Maintainer: Kevin Cernekee Section: net Priority: optional Build-Depends: debhelper (>= 9), dh-autoreconf, libevent-dev Standards-Version: 3.9.8 Vcs-Browser: https://anonscm.debian.org/cgit/collab-maint/ocproxy.git Vcs-Git: https://anonscm.debian.org/git/collab-maint/ocproxy.git Homepage: https://github.com/cernekee/ocproxy Package: ocproxy Architecture: any Depends: ${misc:Depends}, ${shlibs:Depends} Recommends: openconnect Description: lwIP based proxy for openconnect ocproxy is a lwIP based SOCKS and port-forwarding proxy for use with openconnect. It allows a non-administrator to use openconnect without the need for tunnel devices. Rather than adding the host machine to the network at the other end of the VPN, ocproxy allows a user to create a local SOCKS and port-forwarding proxy that is connected to the VPN. Web browsers, remote login utilities and other programs can then access the systems at the other end of the VPN via the proxy. ocproxy-1.60/ppa/copyright000066400000000000000000000052451303453231400156620ustar00rootroot00000000000000Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ Upstream-Name: ocproxy Upstream-Contact: Kevin Cernekee Source: https://github.com/cernekee/ocproxy Files: * Copyright: 2012-2014 David Edmondson 2012-2014 Kevin Cernekee 2016 Google Inc. License: BSD-3-clause Files: lwip/* contrib/* src/lwipopts.h Copyright: 2001-2003 Swedish Institute of Computer Science. License: BSD-3-clause Files: debian/* Copyright: 2012 David Edmondson License: GPL-2+ This package is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. . This package is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. . You should have received a copy of the GNU General Public License along with this program. If not, see . On Debian systems, the complete text of the GNU General Public License version 2 can be found in "/usr/share/common-licenses/GPL-2". License: BSD-3-clause Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: . 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. . THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ocproxy-1.60/ppa/patches/000077500000000000000000000000001303453231400153505ustar00rootroot00000000000000ocproxy-1.60/ppa/patches/series000066400000000000000000000000001303453231400165530ustar00rootroot00000000000000ocproxy-1.60/ppa/rules000077500000000000000000000001561303453231400150030ustar00rootroot00000000000000#!/usr/bin/make -f export V = 1 export DEB_BUILD_MAINT_OPTIONS = hardening=+all %: dh $@ --with autoreconf ocproxy-1.60/ppa/source/000077500000000000000000000000001303453231400152215ustar00rootroot00000000000000ocproxy-1.60/ppa/source/format000066400000000000000000000000141303453231400164270ustar00rootroot000000000000003.0 (quilt) ocproxy-1.60/ppa/watch000066400000000000000000000001051303453231400147460ustar00rootroot00000000000000version=3 https://github.com/cernekee/ocproxy/tags .*/(.*)\.tar\.gz ocproxy-1.60/release.sh000077500000000000000000000015551303453231400151260ustar00rootroot00000000000000#!/bin/bash gpgkey="BC0B0D65" set -ex set -o pipefail # autotools will search .:..:../.. for support files # let's make sure it can't search our repo, so we know it is getting all # required files from the release tarball builddir=tmp.build/a/b/c/d reldir=tmp.build/w/x/y/z repodir=`pwd` rm -rf tmp.build ocproxy-*.tar.gz ocproxy-*.tar.gz.asc mkdir -p $reldir git clone . $reldir pushd $reldir ./autogen.sh ./configure fakeroot make dist tarball=$(ls -1 ocproxy-*.tar.gz) mv $tarball $repodir popd mkdir -p $builddir pushd $builddir tar -zxf $repodir/$tarball --strip 1 ./configure --enable-vpnns make make distclean ./configure --enable-vpnns --prefix=/ CFLAGS="-Werror" make make install DESTDIR=`pwd`/pfx make clean popd rm -rf tmp.build if gpg --list-secret-keys $gpgkey >& /dev/null; then gpg --yes --armor --detach-sign --default-key $gpgkey $tarball fi exit 0 ocproxy-1.60/src/000077500000000000000000000000001303453231400137305ustar00rootroot00000000000000ocproxy-1.60/src/lwipopts.h000066400000000000000000000214501303453231400157640ustar00rootroot00000000000000/* * Copyright (c) 2001-2003 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */ #ifndef __LWIPOPTS_H__ #define __LWIPOPTS_H__ /* * Use the libc memory allocator. */ #define MEM_LIBC_MALLOC 0 #define MEMP_MEM_MALLOC 1 /* is included in cc.h! */ #define LWIP_TIMEVAL_PRIVATE 0 #define LWIP_DBG_MIN_LEVEL 0 #define LWIP_COMPAT_SOCKETS 0 #define LWIP_DEBUG 1 #define DELIF_DEBUG LWIP_DBG_OFF #define TCPDUMP_DEBUG LWIP_DBG_OFF #define OCIF_DEBUG LWIP_DBG_OFF #define TCPFW_DEBUG LWIP_DBG_ON #define MEM_DEBUG LWIP_DBG_OFF #define MEMP_DEBUG LWIP_DBG_OFF #define PBUF_DEBUG LWIP_DBG_OFF #define API_LIB_DEBUG LWIP_DBG_OFF #define API_MSG_DEBUG LWIP_DBG_OFF #define TCPIP_DEBUG LWIP_DBG_OFF #define NETIF_DEBUG LWIP_DBG_OFF #define DEMO_DEBUG LWIP_DBG_OFF #define IP_DEBUG LWIP_DBG_OFF #define IP_REASS_DEBUG LWIP_DBG_OFF #define RAW_DEBUG LWIP_DBG_OFF #define ICMP_DEBUG LWIP_DBG_OFF #define UDP_DEBUG LWIP_DBG_OFF #define TCP_DEBUG LWIP_DBG_OFF #define TCP_INPUT_DEBUG LWIP_DBG_OFF #define TCP_OUTPUT_DEBUG LWIP_DBG_OFF #define TCP_RTO_DEBUG LWIP_DBG_OFF #define TCP_CWND_DEBUG LWIP_DBG_OFF #define TCP_WND_DEBUG LWIP_DBG_OFF #define TCP_FR_DEBUG LWIP_DBG_OFF #define TCP_QLEN_DEBUG LWIP_DBG_OFF #define TCP_RST_DEBUG LWIP_DBG_OFF #define DNS_DEBUG LWIP_DBG_OFF extern unsigned char debug_flags; #define LWIP_DBG_TYPES_ON debug_flags #define NO_SYS 0 #define LWIP_SOCKET 0 #define LWIP_NETCONN 0 #define LWIP_SO_RCVTIMEO 1 #define LWIP_TCP_KEEPALIVE 1 /* ---------- Memory options ---------- */ /* MEM_ALIGNMENT: should be set to the alignment of the CPU for which lwIP is compiled. 4 byte alignment -> define MEM_ALIGNMENT to 4, 2 byte alignment -> define MEM_ALIGNMENT to 2. */ /* MSVC port: intel processors don't need 4-byte alignment, but are faster that way! */ #define MEM_ALIGNMENT 4 /* MEM_SIZE: the size of the heap memory. If the application will send a lot of data that needs to be copied, this should be set high. */ #define MEM_SIZE 1024000 /* MEMP_NUM_PBUF: the number of memp struct pbufs. If the application sends a lot of data out of ROM (or other static memory), this should be set high. */ #define MEMP_NUM_PBUF 1600 /* MEMP_NUM_RAW_PCB: the number of UDP protocol control blocks. One per active RAW "connection". */ #define MEMP_NUM_RAW_PCB 30 /* MEMP_NUM_UDP_PCB: the number of UDP protocol control blocks. One per active UDP "connection". */ #define MEMP_NUM_UDP_PCB 40 /* MEMP_NUM_TCP_PCB: the number of simulatenously active TCP connections. */ #define MEMP_NUM_TCP_PCB 1000 /* MEMP_NUM_TCP_PCB_LISTEN: the number of listening TCP connections. */ #define MEMP_NUM_TCP_PCB_LISTEN 80 /* MEMP_NUM_TCP_SEG: the number of simultaneously queued TCP segments. */ #define MEMP_NUM_TCP_SEG 1600 /* MEMP_NUM_SYS_TIMEOUT: the number of simulateously active timeouts. */ #define MEMP_NUM_SYS_TIMEOUT 300 /* The following four are used only with the sequential API and can be set to 0 if the application only will use the raw API. */ /* MEMP_NUM_NETBUF: the number of struct netbufs. */ #define MEMP_NUM_NETBUF 200 /* MEMP_NUM_NETCONN: the number of struct netconns. */ #define MEMP_NUM_NETCONN 1000 /* MEMP_NUM_TCPIP_MSG_*: the number of struct tcpip_msg, which is used for sequential API communication and incoming packets. Used in src/api/tcpip.c. */ #define MEMP_NUM_TCPIP_MSG_API 1600 #define MEMP_NUM_TCPIP_MSG_INPKT 1600 /* ---------- Pbuf options ---------- */ /* PBUF_POOL_SIZE: the number of buffers in the pbuf pool. */ #define PBUF_POOL_SIZE 10000 /* PBUF_POOL_BUFSIZE: the size of each pbuf in the pbuf pool. */ #define PBUF_POOL_BUFSIZE 2048 /* PBUF_LINK_HLEN: the number of bytes that should be allocated for a link level header. */ #define PBUF_LINK_HLEN 16 /** SYS_LIGHTWEIGHT_PROT * define SYS_LIGHTWEIGHT_PROT in lwipopts.h if you want inter-task protection * for certain critical regions during buffer allocation, deallocation and memory * allocation and deallocation. */ #define SYS_LIGHTWEIGHT_PROT 1 /* ---------- TCP options ---------- */ #define LWIP_TCP 1 #define TCP_TTL 255 /* Controls if TCP should queue segments that arrive out of order. Define to 0 if your device is low on memory. */ #define TCP_QUEUE_OOSEQ 1 /* TCP Maximum segment size. */ #define TCP_MSS 1024 /* TCP sender buffer space (bytes). */ #define TCP_SND_BUF 65534 /* Match TCP_WND. */ /* TCP sender buffer space (pbufs). This must be at least = 2 * TCP_SND_BUF/TCP_MSS for things to work. */ #define TCP_SND_QUEUELEN (4 * TCP_SND_BUF/TCP_MSS) /* TCP writable space (bytes). This must be less than or equal to TCP_SND_BUF. It is the amount of space which must be available in the tcp snd_buf for select to return writable */ #define TCP_SNDLOWAT (TCP_SND_BUF/8) /* TCP receive window. */ #define TCP_WND 65534 /* Avoid wrap. */ /* Maximum number of retransmissions of data segments. */ #define TCP_MAXRTX 12 /* Maximum number of retransmissions of SYN segments. */ #define TCP_SYNMAXRTX 4 #define LWIP_TCPIP_CORE_LOCKING 1 /* ---------- ARP options ---------- */ #define LWIP_ARP 0 #undef ARP_QUEUEING /* ---------- IP options ---------- */ /* Define IP_FORWARD to 1 if you wish to have the ability to forward IP packets across network interfaces. If you are going to run lwIP on a device with only one network interface, define this to 0. */ #define IP_FORWARD 0 /* IP reassembly and segmentation.These are orthogonal even * if they both deal with IP fragments */ #define IP_REASSEMBLY 1 #define IP_REASS_MAX_PBUFS 10 #define MEMP_NUM_REASSDATA 10 #define IP_FRAG 1 /* ---------- ICMP options ---------- */ #define ICMP_TTL 255 /* ---------- DHCP options ---------- */ /* Define LWIP_DHCP to 1 if you want DHCP configuration of interfaces. */ #define LWIP_DHCP 0 /* ---------- AUTOIP options ------- */ #define LWIP_AUTOIP 0 /* ---------- SNMP options ---------- */ /** @todo SNMP is experimental for now @note UDP must be available for SNMP transport */ #define LWIP_SNMP 0 /* ---------- UDP options ---------- */ #define LWIP_UDP 1 #define UDP_TTL 255 /* ---------- RAW options ---------- */ #define LWIP_RAW 0 #define RAW_TTL 255 /* ---------- Statistics options ---------- */ /* individual STATS options can be turned off by defining them to 0 * (e.g #define TCP_STATS 0). All of them are turned off if LWIP_STATS * is 0 * */ #define LWIP_STATS 1 #define LWIP_STATS_DISPLAY 1 /* Include DNS support. */ #define LWIP_DNS 1 #define DNS_TABLE_SIZE 128 /* ---------- PPP options ---------- */ #define PPP_SUPPORT 0 #endif /* __LWIPOPTS_H__ */ ocproxy-1.60/src/ocproxy.c000066400000000000000000000563501303453231400156100ustar00rootroot00000000000000/* * Copyright (c) 2012-2014 David Edmondson * Copyright (c) 2012-2014 Kevin Cernekee * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "lwip/opt.h" #include "lwip/debug.h" #include "lwip/err.h" #include "lwip/init.h" #include "lwip/ip_addr.h" #include "lwip/dns.h" #include "lwip/netif.h" #include "lwip/stats.h" #include "lwip/sys.h" #include "lwip/tcp_impl.h" #include "netif/tcpdump.h" enum { STATE_NEW = 0, STATE_SOCKS_AUTH, STATE_SOCKS_CMD, STATE_DNS, STATE_CONNECTING, STATE_DATA, STATE_DEAD, STATE_MAX }; #define CONN_TYPE_REDIR 0 #define CONN_TYPE_SOCKS 1 #define SOCKBUF_LEN 2048 #define FL_ACTIVATE 1 #define FL_DIE_ON_ERROR 2 #define MAX_IOVEC 128 #define MAX_CONN 1024 #define SOCKS_VER 0x05 #define SOCKS_CMD_CONNECT 0x01 #define SOCKS_CMD_BIND 0x02 #define SOCKS_CMD_UDP_ASSOCIATE 0x03 #define SOCKS_OK 0x00 #define SOCKS_GEN_FAILURE 0x01 #define SOCKS_NOT_ALLOWED 0x02 #define SOCKS_NET_UNREACHABLE 0x03 #define SOCKS_HOST_UNREACHABLE 0x04 #define SOCKS_CONNREFUSED 0x05 #define SOCKS_TTLEXPIRED 0x06 #define SOCKS_CMDNOTSUPP 0x07 #define SOCKS_ADDRNOTSUPP 0x08 #define SOCKS_ATYP_IPV4 0x01 #define SOCKS_ATYP_DOMAIN 0x03 #define SOCKS_ATYP_IPV6 0x04 struct ocp_sock { /* general */ int fd; struct evconnlistener *listener; struct event *ev; struct tcp_pcb *tpcb; int state; int conn_type; struct ocp_sock *next; /* for TCP send/receive */ int done_len; int lwip_blocked; int sock_pos; int sock_total; char sockbuf[SOCKBUF_LEN]; /* for all listeners */ int lport; char *bind_addr; evconnlistener_cb listen_cb; /* for port forwarding */ char *rhost_name; ip_addr_t rhost; int rport; /* for lwip_data_cb() */ struct netif *netif; }; struct socks_auth { u8_t ver; u8_t n_methods; u8_t methods; } PACK_STRUCT_STRUCT; struct socks_req { u8_t ver; u8_t cmd; u8_t rsv; u8_t atyp; union { struct { u32_t dst_addr; u16_t dst_port; u8_t end; } ipv4; struct { u8_t fqdn_len; u8_t fqdn_name[255]; /* variable length */ u16_t port; } fqdn; } u; } PACK_STRUCT_STRUCT; struct socks_reply { u8_t ver; u8_t rep; u8_t rsv; u8_t atyp; u32_t bnd_addr; u16_t bnd_port; } PACK_STRUCT_STRUCT; static struct event_base *event_base; static struct ocp_sock ocp_sock_pool[MAX_CONN]; static struct ocp_sock *ocp_sock_free_list; static struct ocp_sock *ocp_sock_bind_list; static int ocp_sock_used; static int ocp_sock_max; /* nonstatic debug cmd option, exported in lwipopts.h */ unsigned char debug_flags = 0; static int allow_remote; static int tcpdump_enabled; static int keep_intvl; static int got_sighup; static int got_sigusr1; static char *dns_domain; static void start_connection(struct ocp_sock *s, ip_addr_t *ipaddr); static void start_resolution(struct ocp_sock *s, const char *hostname); /********************************************************************** * Utility functions / libevent wrappers **********************************************************************/ static void die(const char *fmt, ...) { va_list ap; va_start(ap, fmt); fflush(stdout); vfprintf(stderr, fmt, ap); va_end(ap); exit(1); } static void warn(const char *fmt, ...) { va_list ap; va_start(ap, fmt); fflush(stdout); fprintf(stderr, "warning: "); vfprintf(stderr, fmt, ap); va_end(ap); } static char *xstrdup(const char *s) { char *ret = strdup(s); if (!ret) die("out of memory\n"); return ret; } static int ocp_atoi(const char *s) { char *p; long val = strtol(s, &p, 0); if (!*s || *p) die("invalid integer: '%s'\n", s); return val; } static struct ocp_sock *ocp_sock_new(int fd, event_callback_fn cb, int flags) { struct ocp_sock *s; s = ocp_sock_free_list; if (!s) { if (flags & FL_DIE_ON_ERROR) die("%s: ran out of ocp_socks\n", __func__); return NULL; } ocp_sock_free_list = s->next; memset(s, 0, sizeof(*s)); ocp_sock_used++; if (ocp_sock_used > ocp_sock_max) ocp_sock_max = ocp_sock_used; s->next = ocp_sock_bind_list; ocp_sock_bind_list = s; if (fd < 0) return s; s->fd = fd; s->ev = event_new(event_base, fd, EV_READ, cb, s); if (flags & FL_ACTIVATE) event_add(s->ev, NULL); return s; } static void ocp_sock_del(struct ocp_sock *s) { if (s->state == STATE_DNS) { s->state = STATE_DEAD; return; } close(s->fd); if (s->tpcb) { tcp_arg(s->tpcb, NULL); tcp_close(s->tpcb); } event_free(s->ev); memset(s, 0xdd, sizeof(*s)); s->next = ocp_sock_free_list; ocp_sock_free_list = s; ocp_sock_used--; } /********************************************************************** * lwIP TCP<->socket TCP traffic **********************************************************************/ /* Called when the local TCP socket has data available (or hung up) */ static void local_data_cb(evutil_socket_t fd, short what, void *ctx) { struct ocp_sock *s = ctx; ssize_t len; int try_len; err_t err; try_len = tcp_sndbuf(s->tpcb); if (try_len > SOCKBUF_LEN) try_len = SOCKBUF_LEN; if (!try_len || tcp_sndqueuelen(s->tpcb) > (TCP_SND_QUEUELEN/2)) { s->lwip_blocked = 1; return; } len = read(s->fd, s->sockbuf, try_len); if (len <= 0) { ocp_sock_del(s); return; } err = tcp_write(s->tpcb, s->sockbuf, len, TCP_WRITE_FLAG_COPY); if (err == ERR_MEM) die("%s: out of memory\n", __func__); else if (err != ERR_OK) warn("tcp_write returned %d\n", (int)err); tcp_output(s->tpcb); event_add(s->ev, NULL); } /* Called when lwIP has sent data to the VPN */ static err_t sent_cb(void *ctx, struct tcp_pcb *tpcb, u16_t len) { struct ocp_sock *s = ctx; if (!s) return ERR_OK; if (s->lwip_blocked) { s->lwip_blocked = 0; event_add(s->ev, NULL); } return ERR_OK; } /* Called when lwIP has new TCP data from the VPN */ static err_t recv_cb(void *ctx, struct tcp_pcb *tpcb, struct pbuf *p, err_t err) { struct ocp_sock *s = ctx; struct pbuf *first = p; int offset; ssize_t wlen; if (!s) return ERR_ABRT; if (!p) { ocp_sock_del(s); return ERR_OK; } /* * tcp_tmr() will call this function every 250ms with the same pbuf, * if we refused data during the previous attempt. s->done_len * will reflect the number of bytes we were able to send to the socket * so far (if any). */ for (offset = s->done_len; p && offset >= p->len; offset -= p->len) p = p->next; for (; p; p = p->next) { int try_len = p->len - offset; wlen = write(s->fd, (char *)p->payload + offset, try_len); offset = 0; if (wlen < 0) { ocp_sock_del(s); return ERR_ABRT; } s->done_len += wlen; tcp_recved(tpcb, wlen); if (wlen < try_len) return ERR_WOULDBLOCK; } /* if we got here, then the whole pbuf is done */ s->done_len = 0; pbuf_free(first); return ERR_OK; } /********************************************************************** * SOCKS protocol **********************************************************************/ static void socks_reply(struct ocp_sock *s, int rep) { struct socks_reply rsp; memset(&rsp, 0, sizeof(rsp)); rsp.ver = SOCKS_VER; rsp.rep = rep; rsp.atyp = SOCKS_ATYP_IPV4; if (rep == 0 && s->tpcb) { rsp.bnd_addr = htonl(s->tpcb->local_ip.addr); rsp.bnd_port = htons(s->tpcb->local_port); } if (write(s->fd, &rsp, sizeof(rsp)) != sizeof(rsp)) rep = -1; if (rep != 0) ocp_sock_del(s); } static void socks_cmd_cb(evutil_socket_t fd, short what, void *ctx) { struct ocp_sock *s = ctx; ssize_t ret; struct socks_auth *auth = (void *)s->sockbuf; struct socks_req *req = (void *)s->sockbuf; ip_addr_t ip; if (s->state == STATE_DATA) { /* we're done with the SOCKS negotiation so just pass data */ local_data_cb(fd, what, ctx); return; } ret = read(s->fd, s->sockbuf + s->sock_pos, SOCKBUF_LEN - s->sock_pos); if (ret <= 0) goto disconnect; s->sock_pos += ret; if (req->ver != SOCKS_VER) goto disconnect; if (s->state == STATE_SOCKS_AUTH) { if (s->sock_pos <= offsetof(struct socks_auth, n_methods)) goto req_more; else if (s->sock_pos <= auth->n_methods + offsetof(struct socks_auth, n_methods)) goto req_more; /* reply: SOCKS5, no auth needed */ if (write(s->fd, "\x05\x00", 2) != 2) goto disconnect; s->state = STATE_SOCKS_CMD; s->sock_pos = 0; goto req_more; } else if (s->state == STATE_SOCKS_CMD) { /* read cmd, atyp */ if (s->sock_pos <= offsetof(struct socks_req, atyp)) goto req_more; if (req->cmd != SOCKS_CMD_CONNECT) { socks_reply(s, SOCKS_CMDNOTSUPP); return; } if (req->atyp == SOCKS_ATYP_IPV4) { if (s->sock_pos < offsetof(struct socks_req, u.ipv4.end)) goto req_more; ip.addr = req->u.ipv4.dst_addr; s->rport = ntohs(req->u.ipv4.dst_port); start_connection(s, &ip); return; } else if (req->atyp == SOCKS_ATYP_DOMAIN) { u8_t *name = req->u.fqdn.fqdn_name; u16_t namelen = req->u.fqdn.fqdn_len; if (s->sock_pos <= offsetof(struct socks_req, u.fqdn.fqdn_len)) goto req_more; if (s->sock_pos <= (offsetof(struct socks_req, u.fqdn.fqdn_len) + req->u.fqdn.fqdn_len)) goto req_more; s->rport = (name[namelen] << 8) | name[namelen + 1]; name[namelen] = 0; start_resolution(s, (char *)name); return; } else { socks_reply(s, SOCKS_ADDRNOTSUPP); return; } } req_more: event_add(s->ev, NULL); return; disconnect: ocp_sock_del(s); } /********************************************************************** * Connection setup **********************************************************************/ /* Called on lwIP TCP errors; used to detect connection failure */ static void tcp_err_cb(void *arg, err_t err) { struct ocp_sock *s = arg; if (s) { s->tpcb = NULL; if (s->state == STATE_CONNECTING && s->conn_type == CONN_TYPE_SOCKS) socks_reply(s, SOCKS_CONNREFUSED); else ocp_sock_del(s); } } /* Called when lwIP tcp_connect() is successful */ static err_t connect_cb(void *arg, struct tcp_pcb *tpcb, err_t err) { struct ocp_sock *s = arg; if (s->conn_type == CONN_TYPE_SOCKS) socks_reply(s, SOCKS_OK); s->state = STATE_DATA; event_add(s->ev, NULL); tcp_recv(tpcb, recv_cb); tcp_sent(tpcb, sent_cb); return ERR_OK; } static void start_connection(struct ocp_sock *s, ip_addr_t *ipaddr) { struct tcp_pcb *tpcb; err_t err; s->state = STATE_CONNECTING; tpcb = tcp_new(); if (!tpcb) die("%s: out of memory\n", __func__); tcp_nagle_disable(tpcb); tcp_arg(tpcb, s); tcp_recv(tpcb, NULL); tcp_err(tpcb, tcp_err_cb); s->tpcb = tpcb; if (keep_intvl) { tpcb->so_options |= SOF_KEEPALIVE; tpcb->keep_intvl = keep_intvl * 1000; tpcb->keep_idle = tpcb->keep_intvl; } err = tcp_connect(tpcb, ipaddr, s->rport, connect_cb); if (err != ERR_OK) warn("%s: tcp_connect() returned %d\n", __func__, (int)err); } static void finish_resolution(const char *hostname, ip_addr_t *ipaddr, void *arg) { struct ocp_sock *s = arg; /* * We can't abort the DNS lookup, but we can kill the connection when * it returns (if needed) */ if (s->state == STATE_DEAD) { ocp_sock_del(s); return; } if (ipaddr) { /* success */ start_connection(s, ipaddr); return; } /* DNS resolution failed */ if (s->conn_type == CONN_TYPE_SOCKS) socks_reply(s, SOCKS_HOST_UNREACHABLE); else ocp_sock_del(s); } static void enqueue_dns_req(struct ocp_sock *s, const char *hostname, const char *domain, dns_found_callback found) { err_t err; if (!domain) err = dns_gethostbyname(hostname, &s->rhost, found, s); else { /* sockbuf is just scratch space */ snprintf(s->sockbuf, SOCKBUF_LEN, "%s.%s", hostname, dns_domain); err = dns_gethostbyname(s->sockbuf, &s->rhost, found, s); } if (err == ERR_INPROGRESS) return; else if (err == ERR_OK) start_connection(s, &s->rhost); else if (err == ERR_MEM) { warn("%s: DNS table full, aborting lookup\n", __func__); found(hostname, NULL, s); } else { warn("%s: invalid hostname '%s'\n", __func__, hostname); found(hostname, NULL, s); } } static void retry_resolution(const char *hostname, ip_addr_t *ipaddr, void *arg) { struct ocp_sock *s = arg; /* first attempt at DNS resolution succeeded */ if (ipaddr != NULL || !dns_domain) { finish_resolution(hostname, ipaddr, arg); return; } /* no dice; try again with . */ enqueue_dns_req(s, hostname, dns_domain, finish_resolution); } static void start_resolution(struct ocp_sock *s, const char *hostname) { s->state = STATE_DNS; /* * Looking up an unqualified hostname can take a few seconds * to time out, so just look up the FQDN right away if it's * obvious. */ if (strchr(hostname, '.')) enqueue_dns_req(s, hostname, NULL, retry_resolution); else enqueue_dns_req(s, hostname, dns_domain, finish_resolution); } /* Called upon connection to a local TCP socket */ static void new_conn_cb(struct evconnlistener *listener, evutil_socket_t fd, struct sockaddr *address, int socklen, void *ctx) { struct ocp_sock *lsock = ctx, *s; s = ocp_sock_new(fd, lsock->conn_type == CONN_TYPE_REDIR ? local_data_cb : socks_cmd_cb, 0); if (!s) { warn("too many connections\n"); return; } s->conn_type = lsock->conn_type; s->rport = lsock->rport; if (s->conn_type == CONN_TYPE_REDIR) { s->rport = lsock->rport; start_resolution(s, lsock->rhost_name); } else { s->state = STATE_SOCKS_AUTH; event_add(s->ev, NULL); } } /********************************************************************** * lwIP<->VPN traffic **********************************************************************/ static void vpn_conn_down(void) { printf("ocproxy: VPN connection has terminated\n"); event_base_loopbreak(event_base); } /* Called when the VPN sends us a raw IP packet destined for lwIP */ static void lwip_data_cb(evutil_socket_t fd, short what, void *ctx) { struct ocp_sock *s = ctx; ssize_t len; struct pbuf *p; len = read(s->fd, s->sockbuf, SOCKBUF_LEN); if (len <= 0) { /* This might never happen, because s->fd is a DGRAM socket */ vpn_conn_down(); } if ((p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL)) != NULL) { char *bufptr; struct pbuf *q; bufptr = s->sockbuf; q = p; while (len > 0) { int copy = (len > q->len) ? q->len : len; memcpy(q->payload, bufptr, copy); len -= copy; bufptr += copy; q = q->next; } LINK_STATS_INC(link.recv); if (tcpdump_enabled) tcpdump(p); s->netif->input(p, s->netif); } else warn("%s: could not allocate pbuf\n", __func__); event_add(s->ev, NULL); } /* Called when lwIP has data to send up to the VPN */ static err_t lwip_data_out(struct netif *netif, struct pbuf *p, ip_addr_t *ipaddr) { struct ocp_sock *s = netif->state; int i = 0, total = 0; ssize_t ret; struct iovec iov[MAX_IOVEC]; if (tcpdump_enabled) tcpdump(p); for (; p; p = p->next) { if (i >= MAX_IOVEC) { warn("%s: too many chunks, dropping packet\n", __func__); return ERR_OK; } iov[i].iov_base = p->payload; iov[i++].iov_len = p->len; total += p->len; } ret = writev(s->fd, iov, i); if (ret < 0) { if (errno == ECONNREFUSED || errno == ENOTCONN) vpn_conn_down(); else LINK_STATS_INC(link.drop); } else if (ret != total) LINK_STATS_INC(link.lenerr); else LINK_STATS_INC(link.xmit); return ERR_OK; } /********************************************************************** * Periodic tasks **********************************************************************/ static void handle_sig(int sig) { if (sig == SIGHUP) got_sighup = 1; else if (sig == SIGUSR1) got_sigusr1 = 1; } static void new_periodic_event(event_callback_fn cb, void *arg, int timeout_ms) { struct timeval tv; struct event *ev; tv.tv_sec = timeout_ms / 1000; tv.tv_usec = 1000 * (timeout_ms % 1000); ev = event_new(event_base, -1, EV_PERSIST, cb, arg); if (!ev) die("can't create new periodic event\n"); evtimer_add(ev, &tv); } static void cb_tcp_tmr(evutil_socket_t fd, short what, void *ctx) { tcp_tmr(); } static void cb_dns_tmr(evutil_socket_t fd, short what, void *ctx) { dns_tmr(); } static void cb_housekeeping(evutil_socket_t fd, short what, void *ctx) { int *vpnfd = ctx; /* * OpenConnect will ignore 0-byte datagrams if it's alive, but * we'll get ECONNREFUSED if the peer has died. */ if (write(*vpnfd, vpnfd, 0) < 0 && (errno == ECONNREFUSED || errno == ENOTCONN)) vpn_conn_down(); else if (got_sighup) vpn_conn_down(); if (got_sigusr1) { LINK_STATS_DISPLAY(); MEM_STATS_DISPLAY(); printf("open connections: %d / %d, max %d\n", ocp_sock_used, MAX_CONN, ocp_sock_max); got_sigusr1 = 0; } } /********************************************************************** * Program initialization **********************************************************************/ static err_t init_oc_netif(struct netif *netif) { netif->name[0] = 'u'; netif->name[1] = 'n'; netif->output = lwip_data_out; return ERR_OK; } static void bind_all_listeners(void) { struct ocp_sock *s; struct sockaddr_in sock; for (s = ocp_sock_bind_list; s; s = s->next) { if (!s->listen_cb) continue; if (s->lport < 1 || s->lport > 65535) die("invalid port number: %d\n", s->lport); memset(&sock, 0, sizeof(sock)); sock.sin_port = htons(s->lport); sock.sin_family = AF_INET; if (s->bind_addr) { /* * TODO: support IPv6 and multiple listening sockets * per hostname */ if (!inet_aton(s->bind_addr, &sock.sin_addr)) die("can't parse IP: '%s'\n", s->bind_addr); } else { sock.sin_addr.s_addr = htonl(allow_remote ? INADDR_ANY : INADDR_LOOPBACK); } s->listener = evconnlistener_new_bind(event_base, s->listen_cb, s, LEV_OPT_CLOSE_ON_FREE|LEV_OPT_REUSEABLE, -1, (struct sockaddr *)&sock, sizeof(sock)); if (!s->listener) die("can't set up listener on port %d/tcp\n", s->lport); } } static struct ocp_sock *new_listener(int port, evconnlistener_cb cb) { struct ocp_sock *s; s = ocp_sock_new(-1, NULL, FL_DIE_ON_ERROR); s->lport = port; s->listen_cb = cb; return s; } static void fwd_add(const char *opt) { char *str = xstrdup(opt), *tmp = str, *p; int lport; struct ocp_sock *s; p = strsep(&str, ":"); if (!str) goto bad; lport = ocp_atoi(p); p = strsep(&str, ":"); if (!str) goto bad; s = new_listener(lport, new_conn_cb); s->rhost_name = xstrdup(p); s->rport = ocp_atoi(str); s->conn_type = CONN_TYPE_REDIR; if (s->rport <= 0) die("Remote port must be a positive integer\n"); free(tmp); return; bad: die("Invalid port forward specifier: '%s'\n", opt); } static struct ocp_sock *dyn_fwd(const char *arg) { struct ocp_sock *s; const char *sep = strrchr(arg, ':'); if (sep) { /* : format */ s = new_listener(ocp_atoi(sep + 1), new_conn_cb); s->bind_addr = xstrdup(arg); s->bind_addr[sep - arg] = 0; } else { /* only */ s = new_listener(ocp_atoi(arg), new_conn_cb); } s->conn_type = CONN_TYPE_SOCKS; return s; } static struct option longopts[] = { { "ip", 1, NULL, 'I' }, { "mtu", 1, NULL, 'M' }, { "dns", 1, NULL, 'd' }, { "domain", 1, NULL, 'o' }, { "localfw", 1, NULL, 'L' }, { "dynfw", 1, NULL, 'D' }, { "keepalive", 1, NULL, 'k' }, { "allow-remote", 0, NULL, 'g' }, { "verbose", 0, NULL, 'v' }, { "tcpdump", 0, NULL, 'T' }, { NULL } }; int main(int argc, char **argv) { int opt, i, vpnfd; char *str; char *ip_str, *mtu_str, *dns_str; ip_addr_t ip, netmask, gw, dns; struct ocp_sock *s; struct netif netif; ip_str = mtu_str = dns_str = NULL; ocp_sock_free_list = &ocp_sock_pool[0]; for (i = 1; i < MAX_CONN; i++) ocp_sock_pool[i - 1].next = &ocp_sock_pool[i]; event_base = event_base_new(); if (!event_base) die("can't initialize libevent\n"); str = getenv("VPNFD"); if (!str) die("VPNFD is not set, aborting\n"); vpnfd = ocp_atoi(str); /* try to set the IP configuration from the environment, first */ ip_str = getenv("INTERNAL_IP4_ADDRESS"); mtu_str = getenv("INTERNAL_IP4_MTU"); dns_domain = getenv("CISCO_DEF_DOMAIN"); str = getenv("INTERNAL_IP4_DNS"); if (str) { char *p; /* this could contain many addresses; just use the first one */ dns_str = xstrdup(str); p = strchr(dns_str, ' '); if (p) *p = 0; } /* override with command line options */ while ((opt = getopt_long(argc, argv, "I:M:d:o:D:k:gL:vT", longopts, NULL)) != -1) { switch (opt) { case 'I': ip_str = optarg; break; case 'M': mtu_str = optarg; break; case 'd': dns_str = optarg; break; case 'o': dns_domain = optarg; break; case 'D': s = dyn_fwd(optarg); break; case 'k': keep_intvl = ocp_atoi(optarg); break; case 'g': allow_remote = 1; break; case 'L': fwd_add(optarg); break; case 'v': debug_flags = LWIP_DBG_ON | LWIP_DBG_TRACE | LWIP_DBG_STATE | LWIP_DBG_FRESH | LWIP_DBG_HALT; break; case 'T': tcpdump_enabled = 1; break; default: die("unknown option: %c\n", opt); } } if (!ip_str || !mtu_str) die("missing -I or -M\n"); if (!ipaddr_aton(ip_str, &ip)) die("Invalid IP address: '%s'\n", ip_str); /* Debugging help. */ signal(SIGHUP, handle_sig); signal(SIGUSR1, handle_sig); signal(SIGPIPE, SIG_IGN); setlinebuf(stdout); setlinebuf(stderr); /* Set up lwIP interface */ s = ocp_sock_new(vpnfd, lwip_data_cb, FL_ACTIVATE | FL_DIE_ON_ERROR); memset(&netif, 0, sizeof(netif)); s->netif = &netif; lwip_init(); dns_init(); if (dns_str) { if (!ipaddr_aton(dns_str, &dns)) die("Invalid DNS IP: '%s'\n", dns_str); /* this replaces the default opendns server */ dns_setserver(0, &dns); } ip_addr_set_zero(&netmask); ip_addr_set_zero(&gw); netif_add(&netif, &ip, &netmask, &gw, s, init_oc_netif, ip_input); netif.mtu = ocp_atoi(mtu_str); netif_set_default(&netif); netif_set_up(&netif); /* bind after all options have been parsed (especially -g) */ bind_all_listeners(); if (tcpdump_enabled) tcpdump_init(); new_periodic_event(cb_tcp_tmr, NULL, 250); new_periodic_event(cb_dns_tmr, NULL, 1000); new_periodic_event(cb_housekeeping, &vpnfd, 1000); event_base_dispatch(event_base); return 0; } ocproxy-1.60/src/vpnns.c000066400000000000000000000424141303453231400152450ustar00rootroot00000000000000/* * Copyright (c) 2016 Google Inc. * Author: Kevin Cernekee * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define DEFAULT_NAME "default" #define DEFAULT_DNS_LIST "8.8.8.8 8.8.4.4" struct packet_loop_ctx { struct event_base *event_base; struct event *tun_event; struct event *vpn_event; struct event *sig_event; int vpn_fd; int tun_fd; }; struct watcher_ctx { struct event_base *event_base; int refcount; }; static void die(const char *fmt, ...) { va_list ap; va_start(ap, fmt); vprintf(fmt, ap); va_end(ap); exit(1); } static pid_t read_pid(const char *statedir) { char *pidfile; if (asprintf(&pidfile, "%s/vpnns.pid", statedir) < 0) die("can't allocate memory\n"); FILE *f = fopen(pidfile, "r"); int pid = 0; free(pidfile); if (!f) { struct stat st; if (stat(statedir, &st) == 0 && !S_ISDIR(st.st_mode)) { printf("'%s' is an old-style pidfile which is unsupported.\n", statedir); die("Exit all running vpnns instances and remove the file.\n"); } return -1; } if (fscanf(f, "%d", &pid) != 1 || pid <= 0) { fclose(f); return -1; } fclose(f); return pid; } static void write_pid(const char *statedir, pid_t pid) { char *pidfile; if (asprintf(&pidfile, "%s/vpnns.pid", statedir) < 0) die("can't allocate memory\n"); unlink(pidfile); if (pid > 0) { mkdir(statedir, 0755); FILE *f = fopen(pidfile, "w"); if (!f || fprintf(f, "%d\n", (int)pid) < 0) die("error writing to '%s'\n", pidfile); fclose(f); } free(pidfile); } static void write_file(const char *file, const char *data) { FILE *f = fopen(file, "w"); if (!f) die("can't open '%s' for writing\n", file); if (fputs(data, f) == EOF || fclose(f) != 0) die("error writing to '%s'\n", file); } static int enter_ns(pid_t pid, const char *ns_str, int nstype) { char *nsfile; int fd; if (asprintf(&nsfile, "/proc/%d/ns/%s", pid, ns_str) < 0) die("can't allocate memory\n"); fd = open(nsfile, O_RDONLY); free(nsfile); if (fd < 0) return -1; if (setns(fd, nstype) < 0) { close(fd); return -1; } close(fd); return 0; } static void enter_all(pid_t pid) { char *pwd; pwd = get_current_dir_name(); if (!pwd) die("can't get current directory: %s\n", strerror(errno)); if (enter_ns(pid, "user", CLONE_NEWUSER) || enter_ns(pid, "uts", CLONE_NEWUTS) || enter_ns(pid, "net", CLONE_NEWNET) || enter_ns(pid, "mnt", CLONE_NEWNS)) die("can't set namespace with pid %d: %s\n", (int)pid, strerror(errno)); if (chdir(pwd) < 0) die("can't set current directory: %s\n", strerror(errno)); free(pwd); } static void setup_ipv4(const char *ifname, const char *addr, const char *mask, bool default_route, int mtu) { struct ifreq ifr; struct sockaddr_in *sin = (struct sockaddr_in *)&ifr.ifr_addr; struct rtentry route; int fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); if (fd < 0) die("socket() failed: %s\n", strerror(errno)); memset(&ifr, 0, sizeof(ifr)); memset(&route, 0, sizeof(route)); strncpy(ifr.ifr_name, ifname, IFNAMSIZ); ifr.ifr_addr.sa_family = AF_INET; if (inet_pton(AF_INET, addr, &sin->sin_addr) != 1) die("invalid IPv4 address '%s'\n", addr); if (ioctl(fd, SIOCSIFADDR, &ifr) < 0) { die("can't set IPv4 address on %s: %s\n", ifname, strerror(errno)); } memcpy(&route.rt_gateway, sin, sizeof(*sin)); if (inet_pton(AF_INET, mask, &sin->sin_addr) != 1) die("invalid IPv4 netmask '%s'\n", mask); if (ioctl(fd, SIOCSIFNETMASK, &ifr) < 0) { die("can't set IPv4 netmask on %s: %s\n", ifname, strerror(errno)); } if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) die("SIOCGIFFLAGS failed\n"); ifr.ifr_flags |= IFF_UP; if (ioctl(fd, SIOCSIFFLAGS, &ifr) < 0) die("SIOCGIFFLAGS failed\n"); if (default_route) { sin = (struct sockaddr_in *)&route.rt_dst; sin->sin_family = AF_INET; sin = (struct sockaddr_in *)&route.rt_genmask; sin->sin_family = AF_INET; route.rt_flags = RTF_UP | RTF_GATEWAY; if (ioctl(fd, SIOCADDRT, &route) < 0) die("can't add default route: %s\n", strerror(errno)); } if (mtu) { memset(&ifr, 0, sizeof(ifr)); strncpy(ifr.ifr_name, ifname, IFNAMSIZ); ifr.ifr_mtu = mtu; if (ioctl(fd, SIOCSIFMTU, &ifr) < 0) die("can't set up MTU: %s\n", strerror(errno)); } close(fd); } static char *populate_statedir(const char *statedir, const char *file, bool is_directory) { char *path; if (asprintf(&path, "%s/%s", statedir, file) < 0) die("can't allocate memory\n"); if (is_directory) { struct stat st; if (mkdir(path, 0755) < 0 && stat(path, &st) == 0 && !S_ISDIR(st.st_mode)) { die("can't create directory '%s': %s\n", path, strerror(errno)); } } else { unlink(path); int fd = open(path, O_WRONLY | O_CREAT, 0644); if (fd < 0) die("can't create '%s': %s\n", path, strerror(errno)); close(fd); } return path; } static void watcher_conn_closed(struct bufferevent *bev, short events, void *vctx) { struct watcher_ctx *ctx = vctx; bufferevent_free(bev); if (--ctx->refcount == 0) event_base_loopexit(ctx->event_base, NULL); } static void watcher_new_conn(struct evconnlistener *listener, evutil_socket_t fd, struct sockaddr *address, int socklen, void *vctx) { struct watcher_ctx *ctx = vctx; struct bufferevent *bev; ctx->refcount++; bev = bufferevent_socket_new(ctx->event_base, fd, BEV_OPT_CLOSE_ON_FREE); bufferevent_setcb(bev, NULL, NULL, watcher_conn_closed, vctx); bufferevent_enable(bev, EV_READ | EV_WRITE); } static void write_socket_path(const char *statedir, struct sockaddr_un *sockaddr) { memset(sockaddr, 0, sizeof(*sockaddr)); sockaddr->sun_family = AF_UNIX; if (snprintf(sockaddr->sun_path, sizeof(sockaddr->sun_path), "%s/watcher", statedir) >= sizeof(sockaddr->sun_path)) die("path too long: '%s'\n", statedir); } static pid_t create_watcher(const char *statedir) { pid_t pid = fork(); if (pid < 0) die("fork failed: %s\n", strerror(errno)); else if (pid > 0) return pid; /* Daemonize */ int i, fd_max = getdtablesize(); for (i = 0; i < fd_max; i++) close(i); open("/dev/null", O_RDONLY); open("/dev/null", O_RDONLY); open("/dev/null", O_RDONLY); setsid(); setpgid(0, 0); if (chdir("/") < 0) { /* ignore */ } /* * The process that started the watcher is the first "client." * Increment the refcount on every SIGUSR1; decrement on SIGUSR2. * If we reach 0 clients, delete the pidfile and exit. */ struct watcher_ctx ctx = {0}; ctx.event_base = event_base_new(); if (!ctx.event_base) die("can't initialize libevent\n"); struct sockaddr_un sockaddr; write_socket_path(statedir, &sockaddr); unlink(sockaddr.sun_path); struct evconnlistener *listener; listener = evconnlistener_new_bind(ctx.event_base, watcher_new_conn, &ctx, LEV_OPT_CLOSE_ON_FREE | LEV_OPT_REUSEABLE, -1, (struct sockaddr *)&sockaddr, sizeof(sockaddr)); if (!listener) die("cannot create socket listener\n"); /* Wait for refcount to reach 0 */ event_base_dispatch(ctx.event_base); /* Delete pidfile */ write_pid(statedir, 0); event_base_free(ctx.event_base); _exit(0); } static int connect_to_watcher(const char *statedir) { struct sockaddr_un sockaddr; write_socket_path(statedir, &sockaddr); int fd = socket(AF_UNIX, SOCK_STREAM, 0); if (fd < 0) die("socket() failed: %s\n", strerror(errno)); int i; for (i = 0; i < 5; i++) { if (connect(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr)) == 0) { return fd; } /* * Try again; we might be racing with the child process. * (This could be fixed, but it's probably more trouble * than it's worth.) */ sleep(1); } die("can't connect to watcher in '%s'\n", statedir); } static void create_ns(const char *statedir, const char *name) { char str[64]; uid_t uid = getuid(); gid_t gid = getgid(); if (unshare(CLONE_NEWNS | CLONE_NEWNET | CLONE_NEWUTS | CLONE_NEWUSER) < 0) die("can't unshare namespaces: %s\n", strerror(errno)); if (access("/proc/self/setgroups", O_RDONLY) == 0) write_file("/proc/self/setgroups", "deny"); snprintf(str, sizeof(str), "0 %d 1", uid); write_file("/proc/self/uid_map", str); snprintf(str, sizeof(str), "0 %d 1", gid); write_file("/proc/self/gid_map", str); write_pid(statedir, create_watcher(statedir)); if (sethostname(name, strlen(name)) < 0) die("can't set hostname: %s\n", strerror(errno)); setup_ipv4("lo", "127.0.0.1", "255.0.0.0", false, 0); char *local_etc = populate_statedir(statedir, "etc", true); char *workdir = populate_statedir(statedir, "workdir", true); char *resolv = populate_statedir(statedir, "etc/resolv.conf", false); char *mount_opts; if (asprintf(&mount_opts, "lowerdir=/etc,upperdir=%s,workdir=%s", local_etc, workdir) < 0) { die("can't allocate memory\n"); } if (mount("overlay", "/etc", "overlay", 0, mount_opts) < 0 && mount(resolv, "/etc/resolv.conf", NULL, MS_BIND, NULL) < 0) { printf("warning: unable to bind mount '%s'\n", resolv); } free(mount_opts); free(resolv); free(workdir); free(local_etc); } static int enter_or_create_ns(const char *statedir, const char *name) { int fd; pid_t pid = read_pid(statedir); if (pid <= 0 || kill(pid, 0)) { create_ns(statedir, name); fd = connect_to_watcher(statedir); } else { /* Prevent destroy/join races by connecting first */ fd = connect_to_watcher(statedir); enter_all(pid); } return fd; } static int run(char *file, char **argv) { pid_t pid = fork(); int rv = 0; if (pid < 0) die("can't fork: %s\n", strerror(errno)); else if (pid > 0) waitpid(pid, &rv, 0); else { if (argv) execvp(file, argv); else { char *arg[2] = { file, NULL }; execvp(file, arg); } die("can't exec '%s': %s\n", file, strerror(errno)); } if (!WIFEXITED(rv)) return 1; else return WEXITSTATUS(rv); } static int do_app(const char *statedir, const char *name, int argc, char **argv) { int watcher_conn = enter_or_create_ns(statedir, name); int rv; if (argc == 0) { char *shell = getenv("SHELL"); if (shell) rv = run(shell, NULL); else rv = run("/bin/sh", NULL); } else { rv = run(argv[0], argv); } close(watcher_conn); return rv == -1 ? 1 : WEXITSTATUS(rv); } static void write_pkt(evutil_socket_t in_fd, short what, void *vctx) { struct packet_loop_ctx *ctx = vctx; char buffer[2048]; int out_fd = (in_fd == ctx->tun_fd) ? ctx->vpn_fd : ctx->tun_fd; ssize_t len = read(in_fd, buffer, sizeof(buffer)); if (len < 0) { fprintf(stderr, "bad read on fd %d->%d\n", in_fd, out_fd); return; } if (write(out_fd, buffer, len) != len) fprintf(stderr, "bad write on fd %d->%d\n", in_fd, out_fd); } static void pkt_loop_signal(evutil_socket_t in_fd, short what, void *vctx) { struct packet_loop_ctx *ctx = vctx; event_base_loopexit(ctx->event_base, NULL); } static void do_packet_loop(int vpn_fd, int tun_fd) { struct packet_loop_ctx ctx; if (fcntl(vpn_fd, F_SETFL, O_RDWR | O_NONBLOCK) < 0) die("can't set O_NONBLOCK on VPN fd: %s\n", strerror(errno)); if (fcntl(tun_fd, F_SETFL, O_RDWR | O_NONBLOCK) < 0) die("can't set O_NONBLOCK on tun fd: %s\n", strerror(errno)); ctx.vpn_fd = vpn_fd; ctx.tun_fd = tun_fd; ctx.event_base = event_base_new(); if (!ctx.event_base) die("can't initialize libevent\n"); ctx.vpn_event = event_new(ctx.event_base, vpn_fd, EV_READ | EV_PERSIST, &write_pkt, &ctx); ctx.tun_event = event_new(ctx.event_base, tun_fd, EV_READ | EV_PERSIST, &write_pkt, &ctx); ctx.sig_event = event_new(ctx.event_base, SIGHUP, EV_SIGNAL, &pkt_loop_signal, &ctx); if (!ctx.vpn_event || !ctx.tun_event || !ctx.sig_event) die("can't create event structs\n"); if (event_add(ctx.vpn_event, NULL) || event_add(ctx.tun_event, NULL) || event_add(ctx.sig_event, NULL)) die("can't register event structs\n"); event_base_dispatch(ctx.event_base); event_del(ctx.sig_event); event_free(ctx.sig_event); event_del(ctx.tun_event); event_free(ctx.tun_event); event_del(ctx.vpn_event); event_free(ctx.vpn_event); event_base_free(ctx.event_base); } static void setup_ip_from_env(const char *ifname) { char *val; int mtu = 0; val = getenv("INTERNAL_IP4_MTU"); if (val) mtu = atoi(val); val = getenv("INTERNAL_IP4_ADDRESS"); if (!val) die("missing IPv4 address\n"); setup_ipv4(ifname, val, "255.255.255.255", true, mtu); val = getenv("INTERNAL_IP4_DNS"); if (!val) val = DEFAULT_DNS_LIST; FILE *f = fopen("/etc/resolv.conf", "w"); if (!f) die("can't open /etc/resolv.conf for writing\n"); val = strdup(val); char *p = val; while (1) { char *s = strtok(p, " "); if (!s) break; p = NULL; if (fprintf(f, "nameserver %s\n", s) < 0) die("error writing to resolv.conf\n"); } free(val); val = getenv("CISCO_DEF_DOMAIN"); if (val) { if (fprintf(f, "search %s\n", val) < 0) die("error writing to resolv.conf\n"); } if (fclose(f) != 0) die("error writing to resolv.conf\n"); } static int do_attach(const char *statedir, const char *name, const char *script) { int watcher_conn = enter_or_create_ns(statedir, name); int tun_fd = open("/dev/net/tun", O_RDWR); if (tun_fd < 0) die("can't open /dev/net/tun: %s\n", strerror(errno)); struct ifreq ifr; memset(&ifr, 0, sizeof(ifr)); ifr.ifr_flags = IFF_TUN | IFF_NO_PI; if (ioctl(tun_fd, TUNSETIFF, (void *)&ifr) < 0) die("can't bind tun device: %s\n", strerror(errno)); if (script) { setenv("reason", "connect", 1); setenv("TUNDEV", ifr.ifr_name, 1); if (system(script)) { /* ignore */ } } else { setup_ip_from_env(ifr.ifr_name); } char *vpn_fd_str = getenv("VPNFD"); if (!vpn_fd_str) die("$VPNFD is not set\n"); int vpn_fd = atoi(vpn_fd_str); do_packet_loop(vpn_fd, tun_fd); if (script) { setenv("reason", "disconnect", 1); if (system(script)) { /* ignore */ } } /* This automatically deletes the tun0 device. */ close(tun_fd); close(watcher_conn); return 0; } static void show_version(void) { puts("vpnns - per-app VPN using Linux namespaces"); puts("Copyright (C) 2016 Google Inc."); puts("This program is part of the " PACKAGE_STRING " package."); puts(""); puts("This is free software with ABSOLUTELY NO WARRANTY."); puts("For details see the LICENSE file in the source distribution."); } static void show_help(void) { puts("Create a new namespace and run COMMAND:"); puts(" vpnns [ --name ] -- [args...]"); puts(""); puts("Attach to an existing namespace and bring up IP networking:"); puts(" vpnns --attach [ --script ]"); puts(""); puts("Options:"); puts(""); puts(" --name Namespace identifier (default: 'default')"); puts(" --script Use vpnc-script PATH to set up IP configuration"); puts(""); } static struct option longopts[] = { { "attach", 0, NULL, 'a' }, { "name", 1, NULL, 'n' }, { "script", 1, NULL, 's' }, { "help", 0, NULL, 'h' }, { "version", 0, NULL, 'v' }, { NULL } }; int main(int argc, char **argv) { int rv; char *name = DEFAULT_NAME, *statedir; char *script = NULL; bool attach = false; while (1) { rv = getopt_long(argc, argv, "an:s:hv", longopts, NULL); if (rv == -1) break; switch (rv) { case 'a': attach = true; break; case 'n': name = optarg; break; case 's': script = optarg; break; case 'h': case '?': show_help(); return 1; case 'v': show_version(); return 0; } } if (asprintf(&statedir, "%s/.vpnns-%s", getenv("HOME"), name) < 0) die("can't allocate memory\n"); if (attach) return do_attach(statedir, name, script); else return do_app(statedir, name, argc - optind, &argv[optind]); } ocproxy-1.60/vpnns.1000066400000000000000000000067251303453231400144010ustar00rootroot00000000000000.TH VPNNS 1 "January 8, 2017" .SH NAME vpnns \- per\-app VPN using namespaces .SH SYNOPSIS \fBvpnns\fP [\fB\-\-name\fP=\fIidentifier\fP] \fB\-\-\fP \fIcommand\fP .PP \fBvpnns\fP [\fB\-\-name\fP=\fIidentifier\fP] [\fB\-\-script\fP=\fIpath\fP] \fB\-\-attach\fP .SH DESCRIPTION .PP \fBvpnns\fP isolates VPN\-related network traffic and applications inside a separate network namespace. Applications intended to be used with the VPN cannot bypass the VPN to access the internet directly, and applications not intended to be used with the VPN cannot send traffic through the VPN tunnel. .SH USAGE .PP This starts up an application in a fresh user/net/uts/mount namespace: .RS .PP vpnns \-\- google\-chrome \-\-user\-data\-dir=/tmp/vpntest .PP vpnns \-\- firefox \-no\-remote \-P vpn .PP vpnns \-\- transmission\-gtk .RE .PP Initially it will not have any network access as the only interface present in the netns is the loopback device. The application should still be able to talk to Xorg through UNIX sockets in \fI/tmp\fP. .PP The next step is to connect to a VPN and invoke \fBvpnns \-\-attach\fP to pass the VPN traffic back and forth: .RS .PP openconnect \-\-script "vpnns \-\-attach" \-\-script\-tun vpn.example.com .PP openvpn \-\-script\-security 2 \-\-config example.ovpn \-\-dev "|HOME=$HOME vpnns \-\-attach" .RE .PP These commands connect to an ocserv or openvpn gateway, then tell \fBvpnns\fP to set up a tunnel device, default route, and resolv.conf inside the namespace created above. On success, the web browser will have connectivity. When the VPN disconnects, the browser will lose all connectivity, preventing leaks. .PP \fBvpnns\fP can be rerun multiple times if the connection fails or if the VPN client crashes. If run without arguments, it will open a shell inside the namespace. .PP .SH OPTIONS .TP \fB\-n, \-\-name\fP \fIidentifier\fP \fBvpnns\fP is designed to allow multiple instances to coexist on the same system. This feature could be useful for connecting to multiple VPNs at the same time. \fIidentifier\fP defaults to "default" but can be overridden through the \fB\-\-name\fP option. .TP \fB\-s, \-\-script\fP \fIpath\fP Invoke the program at \fIpath\fP to set up and tear down the tunnel device's IP configuration, instead of letting \fBvpnns\fP handle it internally. \fB$TUNDEV\fP will be set to the device name (e.g. \fItun0\fP). \fB$reason\fP will be set to either \fBconnect\fP or \fBdisconnect\fP. Any IP configuration variables such as \fB$INTERNAL_IP4_ADDRESS\fP set by the VPN client will be inherited, so it is possible for a modified \fBvpnc\-script\fP to be used. This option only has an effect if \fB\-\-attach\fP is also specified. .SH CAVEATS .PP \fBvpnns\fP is not a security tool. It cannot prevent malicious applications from bypassing the namespace restrictions. .PP While OpenConnect works with \fBvpnns\fP out of the box, OpenVPN currently (as of 2017\-01\-08) requires out\-of\-tree patches to support non\-root operation. .PP If \fI/etc/resolv.conf\fP is a symbolic link to a file that is regenerated on network connection changes, the bind mount used by \fBvpnns\fP to override the DNS configuration can be inadvertently deleted. \fBvpnns\fP attempts to work around this by using overlayfs to override \fI/etc/resolv.conf\fP, but that does not work on all systems. .SH FILES .TP ~/.vpnns\-\fIidentifier\fP State directory for a given \fBvpnns\fP instance. By default, \fBvpnns\fP uses \fI~/.vpnns\-default\fP. .SH SEE ALSO .BR ocproxy (1), .BR openconnect (8), .BR openvpn (8)