pax_global_header00006660000000000000000000000064137446046460014530gustar00rootroot0000000000000052 comment=1ef2a025981223c1e16fc833bef226c86ff8c295 xl2tpd-1.3.16/000077500000000000000000000000001374460464600130355ustar00rootroot00000000000000xl2tpd-1.3.16/.gitignore000066400000000000000000000000621374460464600150230ustar00rootroot00000000000000*.o *~ *.bak *.sw? tags xl2tpd xl2tpd-control pfc xl2tpd-1.3.16/.travis.yml000066400000000000000000000011721374460464600151470ustar00rootroot00000000000000language: c jobs: include: - os: linux dist: xenial compiler: gcc - os: linux dist: xenial compiler: clang - os: linux dist: bionic compiler: gcc - os: linux dist: bionic compiler: clang - os: linux dist: focal compiler: gcc - os: linux dist: focal compiler: clang sudo: false addons: apt: packages: - make - gcc-multilib - libpcap0.8 - libpcap0.8-dev cache: directories: - $HOME/.ccache before_script: - make clean script: - make - ./xl2tpd-control --version - ./xl2tpd-control --help xl2tpd-1.3.16/BUGS000066400000000000000000000001131374460464600135130ustar00rootroot00000000000000Please see (and report) bugs at https://github.com/xelerance/xl2tpd/issues xl2tpd-1.3.16/CHANGES000066400000000000000000000557601374460464600140450ustar00rootroot00000000000000v1.3.16 (October 23, 2020) * Re-add braces for if-else that have only statement [Samir Hussain] * xl2tpd-control refactoring [Alexander Naumov] * fix travis 'script' syntax [Alexander Naumov] * adding xl2tpd-control tests to travis [Alexander Naumov] * Re-adding text giving more inofrmation about using ipsec with xl2tpd [Samir Hussain] * Update README: typo, links to RFC, link to travis [Alexander Naumov] * Travis will test different compiler on linux distro [Samir Hussain] * Update travis for proper matrix [Samir Hussain] * Add Focal to travis testing [Samir Hussain] * yet another man-page update [Alexander Naumov] * update man-pages, fix typo [Alexander Naumov] * set_flow: result of operation is garbage or undefined [Alexander Naumov] * Update README [Alexander Naumov] * adding xl2tpd.init.patch [Alexander Naumov] * adding Makefile.patch [Alexander Naumov] * moving changes to separate file [Alexander Naumov] * sync/update spec file with official SUSE version [Alexander Naumov] * Set IP_PKTINFO even if setting of IPPROTO_IP fails (as it was in 1.3.9) [shadyhh] * Update .gitignore vim swap file [Samir Hussain] * Travis will test supported Ubuntu LTS distros [Samir Hussain] * Updating COMPATABILITY_ISSUES with info on Miktrotik servers [Samir Hussain] * Add work around for Android 10 maxium retries in COMPATIBILITY_ISSUES [Samir Hussain] * Add compatability issues with Ciso ASA [Samir Hussain] v1.3.15 (October 13, 2019) * Fix spacing of CONTRIBUTION.md [Samir Hussain] * Add CONTRIBUTION.md [Samir Hussain] * Specify missing log arguments [Patch by github user: 川島和津実] * Use matrix for .travis.yaml to test for multiple Linux distro [Samir Hussain] * Fixing .travis.yaml spacing warning [Samir Hussain] * Sockopt bug fix for multiple IP's [JDTX] * Add Clang as compiler test for travis [Samir Hussain] * Add info on building and installing xl2tpd [Samir Hussain] v1.3.14 (April 17, 2019) * osport.h: replace SUSv3-specific functions by POSIX variants [Fabrice Fontaine] * avp: Error Code field in Result Code AVP is optional [Pau Espin Pedrol] * network_thread: Early continue in loop to remove huge indented block [Pau Espin Pedrol] * network_thread: Simplify while loop using for loop [Pau Espin Pedrol] * network: connect_pppol2tp: early return to avoid huge indentation block [Pau Espin Pedrol] * xl2tpd: start_pppd: Fix truncation of last character [Pau Espin Pedrol] * handle_packet: Remove unneded else clause when handling payload [Pau Espin Pedrol] * control: Split control message handling into its own function [Pau Espin Pedrol] * handle_packet: Rearrange code flow to simplify it [Pau Espin Pedrol] * avp: Early failure if no handler to remove indent block [Pau Espin Pedrol] * xl2tpd: Mark internal symbols as static [Pau Espin Pedrol] * Fix indentation and whitespace in code block [Pau Espin Pedrol] * xl2tpd: Remove unused variable [Pau Espin Pedrol] * network: Add missing close(kernel_fd) on init network failure [Pau Espin Pedrol] * network: Add missing close(server_fd) on init network failure [Pau Espin Pedrol] * Add 'cap backoff' option, limiting exponential backoff retries will be delayed by exponentially longer time, unless that time is capped by configuration. [Bart Trojanowski] * Add program to show status icon in system tray. [Github user: username34] * Add info on building and installing xl2tpd [Samir Hussain] * Update formatting of README.md [Samir Hussain] * Rename README.xl2tpd to README.md [Samir Hussain] * Update Debian changelog [Samir Hussain] v1.3.13 (December 3, 2018) * Specify email address for reporting security vulnerabilities [Samir Hussain] * Fix compile warning with USE_KERNEL in xl2tpd.c [Samir Hussain] * Applying patch that reduces compile warnings and fixes warnings from gcc and clang. [Gareth Ansell] * Fix compiler warnings in network.c [Gareth Ansell] * Add a make command for packaging's prep work [Samir Hussain] * Add Makefile directive for getting version [Samir Hussain] * Add a preproc for Watchguard firewall (Github issue #136) [daniel1111] * Convert from ISO-8859 to UTF-8 [Simon Deziel] * Update README to provide latest info on xl2tpd + Linux kernel 4.15+ [Samir Hussain] * Use dh_auto_build in order to allow cross compiles [Helmut Grohne] v1.3.12 (May 18, 2018) * TOS value to copy to the tunnel header (Yurkovskyy) * Fix for ENODEV (No such device) error with Linux kernel 4.15 (Douglas Kosovic) * Update xl2tpd.init (bogdik) * fix version number and upload (Samuel Thibault) * import wheezy changes (Samuel Thibault) v1.3.11 (March 7, 2018) * Build packages for Xenial by default (Simon Deziel) * Bump d/compat to 9 (Simon Deziel) * Drop d/repack.sh script and refresh d/watch (Simon Deziel) * Refresh d/control by partly sync'ing from Debian (Simon Deziel) * Use HTTPS URL in d/copyright (Simon Deziel) v1.3.10.1 (November 16, 2017) * Have max retries as a configuration [Samir Hussain] * Add more into to "select timeout" debug message [Samir Hussain] v1.3.10 (August 2, 2017) * Update STRLEN in file.h to 100 (from 80) [Samir Hussain] * xl2tpd-control: fix xl2tpd hanged up in "fopen" [wendy2001011] * Update version in spec and opewnrt Makefile. [Samir Hussain] v1.3.9 (February 8, 2017) * Add xl2tpd-control man pages (Samir Hussain) * Update spec file with newest Soure0 and version (Samir Hussain) * Update License file (Samir Hussain) * Display PID for call in the logs (Samir Hussain) * Use left shift rather than pow() function. (Samir Hussain) * Enable Travis integration (Samir Hussain) * Remove unnecessary casting of malloc() results (Andrew Clayton) * Remove an unused line of code in init_config() (Andrew Clayton) * Fix some undefined behaviour in read_result() (Andrew Clayton) * Fix feature test macro deprecation warnings (Andrew Clayton) v1.3.8 (August 11, 2016) * Another one fix for control buf handling in udp_xmit (Sergey Ryazanov) * Fixing minor bug in Linux that was introduced by 90368 (Samir Hussain) * Fix control buffer handling in udp_xmit (rsa9000) * Avoid using IP_PKTINFO with non-Linux systems (Sergey Ryazanov) * Remove duplicated UDP checksum disabling (Sergey Ryazanov) * Handle LDLIBS carefully (Sergey Ryazanov) * Avoid false-positive warning message from not smart compilers (Sergey Ryazanov) * Correctly activate XPG4v2 support (Sergey Ryazanov) * Simplify signal header inclusion (Sergey Ryazanov) * Adding info on the mailing lists (Samir Hussain) * Fixing minor spelling typo in code. (Samir Hussain) * Fixing minor spelling mistakes in xl2tpd.conf.5 and l2tpd.conf.sample (Samir Hussain) * Removing -fno-builtin from CFLAGS (Samir Hussain) v1.3.7 (March 29, 2016) * Adding defensive code to deal with error when pppd exits (Samir Hussain) * Minor compilation fixes (Yousong Zhou) * Refresh debian/ from Debian. Thanks! (Simon Deziel) * Update URL (Simon Deziel) * Update copyright year (Simon Deziel) * Add local ip range option. (Patch by by Peter W Morreale) * Drop RFC 2661 copy. (Simon Deziel) * debian/control drop legacy Replaces (Simon Deziel) * Typo fix (Simon Deziel) * Fix #98 by checking if a valid PID is being killed (Pieter Jordaan) * Avoid problems with bad avp lengths and remaining hidlen from previous iteration (Cristi Cimpianu) * Fix minor grammar issues in xl2tpd.conf(5) (kballou) * Fix possible NULL reference when removing lac (Yousong Zhou) * Describe autodial option in xl2tpd.conf manpage (Anton Leontiev) * Update URL in BUGS file (Anton Leontiev) * Add size optimization (Cristi Cimpianu) * Remove useless returns from magic_lac_tunnel (Cristi Cimpianu) * Remove duplicate xmit for ZLBs (Cristi Cimpianu) * Fix segfault on lac remove (Cristi Cimpianu) * Fix paths in man pages (Taiki Sugawara) * Stop sending ZLB in response to out of order ZLB from check_control (Cristi Cimpianu) * Add exponential backoff retransmits (Pieter Willem Jordaan) * Fix build errors caused by inline function with gcc 5 (Kai Kang) * Fix memory leaks and accessing free'd memory (Yousong Zhou) * Fix double-free on dial_no_tmp; (Yousong Zhou) * Change handle_special to return a value indicating if it frees the buffer (Cristi Cimpianu) * Remove unnecessary NULL check on lac. (Yousong Zhou) * xl2tpd-control: show all available commands in --help. (Yousong Zhou) * Ignore SIGPIPE signal. (Yousong Zhou) * Unlink result file to prevent leftover a regular file. (Yousong Zhou) * Introduce new option -l for using syslog as the logging facility. (Yousong Zhou) * start_pppd: place opts after "plugin pppol2tp.so". (Yousong Zhou) * Fix typo in reporting available lns count. (Yousong Zhou) * xl2tpd-control: enhance output of print_error(). (Yousong Zhou) * xl2tpd-control: cleaup result file atexit(). (Yousong Zhou) * xl2tpd-control: open control file with O_NONBLOCK. (Yousong Zhou) * xl2tpd-control: define _GNU_SOURCE to use fmemopen() and friends. (Yousong Zhou) * xl2tpd-control: check end-of-file when reading pipe to avoid dead loop. (Yousong Zhou) * Correct CDN message result range (Constantin Calotescu) * place the PPP frame buffer to the call structure (rsa9000) * Place the pty read buffer to the call structure (rsa9000) * Pass pointer to call structure to read_packet() (rsa9000) * Remove convert arg of read_packet() function (rsa9000) * Remove dead code (rsa9000) * Fix the list of ignored files (rsa9000) * Add checks before closing sockets (Cristi Cimpianu) * Add a bit more info about existing tunnels and calls (Cristi Cimpianu) * Fix endless loop (Cristi Cimpianu) * Add fix for socket leak to fork children (Cristi Cimpianu) * Random fixes (Constantin Calotescu) * Solve some memory leaks that show up after several days of running with flapping tunnels and calls. (Cristi Cimpianu) * Fix for avoiding xltpd occasionally going into an endless loop. (Damian Ivereigh) * Fixed issue with strtok modifying contents when pushing details for ppd plugins (Michael Lawson) * Added the ability to add a pppd plugin and params to an lns (Michael Lawson) * Modified lns_remove to close each call rather than just calling destroy_tunnel() (Michael Lawson) * Added control method to remove an lns (Michael Lawson) * Refactored the do_control() method to use a handler approach for processing (Michael Lawson) * Fixed potential null pointer when creating a new lns (Michael Lawson) * Added status control command for lns, this returns tunnel and call information via the control socket (Michael Lawson) * Added control support for adding lns and status command in xl2tp-control (Michael Lawson) * Added control pipe method CONTROL_PIPE_REQ_LNS_ADD_MODIFY to modify LNS configuration (Michael Lawson) * Introduced shared control request types (Michael Lawson) * Fixed typo in xl2tpd.conf.5 (paina) * Some malloc/free sanity patches. (Patrick Naubert) * Better NETBSD support. (Patrick Naubert) * Prevent a DEBUG message from being sent to syslog when not debugging. (Patrick Naubert) v1.3.6 (Jan 15, 2014) * I keep screwing up the version number. Changes to CHANGES and l2tp.h * Fix the size of the lenght param for AVP headers. This should fix Android support no matter how the compiler optimizes. v1.3.5 (Jan 15, 2014) * Re-define the add_header() function as the compiler was screwing up the lenght|MBIT logic. THIS RE-ENABLES ANDROID SUPPORT which had been broken since 1.2.7 v1.3.4 (Jan 13, 2014) * Revert "Patches from Fedora to use Openssl MD5 instead of our own" This patch forced us to ask for a license exception, which we cannot do. * Revert "Add a license exception to link xl2tpd with OpenSSL" Without the OpenSSL MD5 requirement, we no longer need to ask for a license exception. v1.3.3 (Jan 3, 2014) * License exception for linking with OpenSSL (this is because we do not use our MD5 anymore) * Check write return code on control socket (fixes FTBFS with -Wall) [Simon Deziel] v1.3.2 (Nov 15, 2013) * Remove unused variables reported by gcc -Wunused [Paul Wouters] * Retain password when redial is enabled [Ted Phelps] * Respect LDFLAGS, original author unknown [Jeremy Olexa] * Turn off UDP checksums [mcr] * Respect CFLAGS for xl2tpd-control [Mike Gilbert] * Patches from Fedora to use Openssl MD5 instead of our own [Patrick Naubert] * Cosmetic fix log warning about IPsec SAref kernel mod support [Pavel Kopchyk] * Upgrade options (in global contex) according to their keyword words in 'file.c' [Pavel Kopchyk] * Actually force userspace when using SAref [Sergey Fionov] * Enable kernel-mode by default [Sergey Fionov] * Fix kernel support for 2.6.23+ [Sergey Fionov] * Remove if_pppol2tp.h header [Sergey Fionov] * Tell pppd to set LNS mode flag on kernel pppol2tp session socket. [Sergey Fionov] * Wrap connect_pppol2tp() with ifdef [Sergey Fionov] * Check for existence of SO_NO_CHECK before using it [Stuart Henderson] * Check that argv[1] isn't null before strncmp() [Stuart Henderson] * Set a valid msg_controllen, OpenBSD needs it [Stuart Henderson] * Avoid type punning: it makes gcc grumpy. [Ted Phelps] * Cope with comment lines that extend beyond 120 characters. BZ#806963. [Ted Phelps] * Document the default duration of the redial timeout option. [Ted Phelps] * Don't call grantpt(). [Ted Phelps] * Fix an uninitialize memory access. [Ted Phelps] * Fix udp_xmit to work on Linux *and* OpenBSD [Ted Phelps] * Increase the size of the buffer used to read config file lines. [Ted Phelps] * Make it possible to prevent xl2tpd from overwriting ppp's ipparam [Ted Phelps] * Quash more valgrind warnings. [Ted Phelps] * Set msgh.msg_controllen before calling CMSG_FIRSTHDR [Ted Phelps] * + use address from the last received UDP packet in UDP messages response [Tomas Chmelar] * Clean up samples [Tuomo] * Don't mark some AVPs as mandatory [wangxiaoguang] http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=680146 * Remove a 'sleep' in control_finish [wangxiaoguang] v1.3.1 (Oct 6, 2011) * Suse updated to spec and init files [Shinichi Furuso] * SAREF: Changed IP_IPSEC_REFINFO to global option "saref refinfo" [Paul] * Updated configuration examples with SAref [Paul] * samples: cleaned up samples and removed broken ones [Tuomo] v1.3.0 (July 23, 2011) * Added xl2tpd-control [Alexander Dorokhov] * Added 'a' (add) and 'd' (delete) control options [Alexander Dorokhov] * Refresh debian/ from Debian. [Roberto C. Snchez] * Buffer overrun in reading >16 char l2tp-secrets [Matt Domsch] (https://bugzilla.redhat.com/show_bug.cgi?id=689178) * xl2tpd may leaks file descriptors [Steve Barth] * xl2tpd: field o_pad in "struct payload_hdr" unnecessary. RFC 2661 [Ilya] * Fix logging in write_packet() [Ilya] * Bug tracker bugs fixed: #1119 Segfault upon config error [Andrey Cherny] #1223 Gentoo QA warning: dereferencing pointer [Andrey Cherny] #1236 xl2tpd hungs and wont redial after communication fail [Andrey Cherny] #1237 delayed null pointer check [Andrey Cherny] v1.2.8 * Makefile: fix compilation with --as-needed linker flag [Vladimir V. Kamarzin] * Workaround for apple clients missing htons() [Brian Mastenbrook] * Log destination ip and port in case of send failure [Mika Ilmaranta] * Added Default-Stop: to fedora initscript [Paul] * Bug tracker bugs fixed: #1078 xl2tpd doesn't pass 'ipparam' to pppd and pppd won't get client ip (Xiaoguang WANG) v1.2.7 * Reduce time in signal handlers where we cannot log [Shinichi Furuso] * Add rx/tx bps speed setting options [Tony Hoyle] (http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=578070) * Rename FFLAGS to IPFLAGS to avoid clashing on debian [Paul] * spelling fix (dont -> don't) [Paul] v1.2.6 * Partial fix for compiling on OpenBSD [synapse] * add missing setting of logopen=1 in init_log() [Shingo Yamawaki] * xltpd could deadlock on syslog() call in signal handler [Bart Trojanowski] * fix fedora/centos spec file [Paul] v1.2.5 * Fix initscript for https://bugzilla.redhat.com/show_bug.cgi?id=247100 * Fix for two Windows machines behind the same NAT with the samed number of l2tp connection attempts since boot [Shinichi Furuso] v1.2.4 * Fixes to Suse spec file [Shingo Yamawaki] * unclutter logs for 'select timeout' [Shingo Yamawaki] * Make sure child_handler and destroy_call won't conflict when pppd is killed [Mika Ilmaranta/ Tuomo] * Workaround for broken kernels that send duplicate pids to waitpid() See: https://bugzilla.redhat.com/show_bug.cgi?id=486945 [Mika / Tuomo] * Fix pppd option from legacy -detach to nodetach [Tuomo] v1.2.3 * Fixes for prefix/destdir and spec files [paul/tuomo] * Use pcap not pcap-devel on suse, rhel and centos [paul/tuomo/shingo] * Added pfc to contrib. pfc is a tool to compile active-filters for pppd, which can be used for dial-on-demand filters [paul/roberto] * Bug tracker bugs fixed # 998: xl2tpd-1.2.2 Makefile sets wrong path for mandir v1.2.2 * PPP CHAP authentication using plugin passwordfd.so failed [tgohad@mvista.com] * Use SIGALRM only in select(). This prevents a problem where a pppd child (eg ntpd via ppp-up.d/ script) is using signaling too. [Shingo Yamawaki] * A file descriptor is left opened when exec'ing pppd. [Shingo Yamawaki] * When select() is interrupted, readfds should not be used. [Shingo Yamawaki] * Modifications to Makefile to support DESTDIR [paul] * Modifications to compile on OpenBSD [Stephen Ayotte] * Bug tracker bugs fixed #955: refuse authentication is backward for LAC sections [Dean Scarff] v1.2.1 * Fixes to Suse init file and spec file [paul] * Changed some build defaults in Makefile [paul] v1.2.0 * Synchronised IP_IPSEC_REFINFO define with KLIPSNG patch [paul] * Fixed versioning and bumped to 1.2.0 [paul] v1.1.12 * Fix for dropped packets and wrong disconnects. [Ray Overland / Tuomo] * Included debian directory from Roberto C. Sanchez v1.1.11 * Support for passwordfd when using xl2tpd as client. Patch by David MacKinnon * Add DEBUG_AUTH comments to the Makefile [paul] * Workaround for Cisco routers that do not send transmit speed or framing type [paul] * Fix two old l2tpd references to xl2tpd (syslog used wrong name) [paul] v1.1.10 * add pid to pppd logging [tuomo] * don't specify compiler flags (overrides packaging flags in rpm) [tuomo] * minor documentation fixes [tuomo/paul] v1.1.09 * Forgot to bump version number, so to avoid confusing, I bumped everything to 1.1.09 v1.1.08 * Confirmed pppd bug of not always terminating on SIGTERM. The new define TRUST_PPPD_TO_DIE determins whether we send SIGTERM or SIGKILL, with SIGKILL being the (new) default. (ppp-2.4.2-6.4.RHEL4 is known to be broken) v1.1.07 * Fix for unaligned header field accesses crashes on RISC by Dave S. Miller (# 735) * Added and enabled pppd debugging code to assist locating a serious xl2tpd infinite loop when pppd does not die after a SIGTERM. * Complete support for pppol2tp's kernel mode L2TP. Patch by Cedric * Make spec file Fedora Extras compliant * Added pppol2tp-linux-2.4.27.patch to contrib/ * Pidfile fixes (by Tuomo) * Fix creation of pid file if /var/run/xl2tpd does not exist. * Fix compile without SANITY defined (Charlie Brady ) * Fix configuration filename for the ppp options file (#725 by Tuomo) * Fixes to compile with all DEBUG_* statements enabled * Documented all DEBUG_* statements in Makefile v1.1.06 * Build xl2tpd and use /etc/xl2tpd/xl2tpd.* configuration files with fallback to /etc/l2tpd/l2tpd.* configuration files. * Support for pppol2tp's kernel mode L2TP. Patch by Cedric Schieli * Documented IPsec SA reference tracking for use with Openswan * Added patents documentation. * Migration support on xl2tpd.spec for l2tpd -> xl2tpd v1.1.05 * Changed versioning scheme to match Xelerance standards * IPsec SA reference tracking added (used with Openswan's IPsec transport mode) This adds support for multiple clients behind the same NAT router, and multiple clients on the same internal IP behind different NAT routers. * Fix for Windows clients that send the wrong tunnel ID for closing tunnels v1.04 * actually, 1.03 tag in GIT was in the wrong place. This is the right release. v1.03 * fixes for gcc 4.xx compilation v1.02 * udpated CHNANGELOG v1.01 * various debugging added, but debugging should not be on by default * async/sync conversion routines must be ready for possibility that the read will block due to routing loops * refactored control socket handling. * use man page in doc/ * move all logic about pty usage to pty.c try ptmx first. if it fails try legacy ptys * rename log() to l2tp_log(), as "log" is a math function. v1.00 * First version managed by Xelerance, called xl2tpd. * If we aren't deamonized, then log to stderr. * added install: and DESTDIR support 0.70 -- Change path for config files from /etc/l2tp to /etc/l2tpd (jacco2@dds.nl) Turn of echo no ptys to pppd (Damien de Soto) Add pty name to command line passed to pppd (Chris Wilson) Added listen-addr parameter to l2tpd.conf (jacco2@dds.nl) Close stdin when in daemon mode (jacco2@dds.nl) Improve interoperability with MSL2TP (jacco2@dds.nl) Eliminate some warnings (jacco2@dds.nl) 0.69 -- Edited l2tpd.conf.5 man page to correct some information Added l2tpd.8 and l2tp-secrets.5 man pages Zero'ed out memory malloced to hold challenge, otherwise we may pass wrong challenge to md5 code 0.68 -- Updated copyright notice on all relevent files Changed vendor name as it appears in AVP's Add new sources of randomness, reading /dev/urandom Seed rand() with time() Stubs available for egd randomness source, not implemented yet though Don't close fd 0 as workaround for signal problems in daemon mode Fix some off by 6 errors in avp handling 0.67 -- close pty connecting to pppd in child_handler() Add code to daemonize correctly Add command line options -D to not daemonize -p to specify a pidfile -c to specify a config file -s to specify a secrets file Catch a SIGHUP that's coming from who-knows-where and do nothing 0.66 -- Fixed tunnel authentication mechanism so that it works! Fixed several segfaults...some in debugging code 0.65.1 -- Reformatted all .c and .h files using GNU indent 0.65 -- Fix to handling SLI packets reformatted some code in a few small places Added valid, new (since L2TP draft days) result codes autodialed calls switched to be "Incoming calls" rather than "Outgoing" Re-arranged some header declarations Remote systems may use the same Tunnel ID...this is OK Look for l2tpd.conf in /etc/l2tp and in /etc/l2tpd...look for l2tp-secrets int he same directory Portability enhancement (act.sa_restorer only used on i386?) (Jean-Francois Dive) 0.64 -- Too many that I lost track... Scaleability improvements from Huiban Yoann at Siemens Rudimentary Outgoing Call Request system As in CREDITS, "an uncountable amount of little bug fixes" 0.63 -- Syslog support added!!! Improved data sequencing & flow control serial number checking Removed call flow/session control serial number checking in ICRQ -- Did we do this already and we're going mindless? :D Removed checking of now-defunct R bit Changed PPP framing to always sync Various and asundry other fixes NOW OPERABLE WITH CISCO IOS 12.1 Continued interoperability improvements with Windows 2000 clients 0.62 -- Removed call flow/session control (inapplicable as of RFC spec draft 13) Corrected invalid Receive Window Size AVP in ICCN Corrected Bearer Capabilities non-requirement in SCCRQ & SCCRP Verified operability with Cisco 3000 series 0.61 -- Fixed shutdown of PPPd from SIGKILL to SIGTERM Beginning code cleanup and interoperability testing xl2tpd-1.3.16/COMPATIBILITY_ISSUES000066400000000000000000000022741374460464600160710ustar00rootroot00000000000000* Android 9 & 10 fails on maximum retries exceeded for tunnel There are reports that with Android 9 & 10, some users are getting "Maximum retries" error messages. It seems to related to some of the phones not responding to L2TP keepalive heartbeats A possible work around is to use the max_retries option. Using "max retries" in the xl2tpd.conf (e.g. max retries = 100) has known to work for some users. Alternatively, another works around is to not to enable L2TP keepalive on the VPN servers. For more information, please refer to: https://github.com/xelerance/xl2tpd/issues/191 * Issues with Cisco ASA Some users are reporting that newer version of xl2tpd (1.310 onward) are not able to connect to Cisco ASA. A possible work around is to use x2ltpd 1.39 and disable use of kernel module (comment out the directive OSFLAGS+= -DUSE_KERNEL -D in the Makefile) For more information, please refer to: https://github.com/xelerance/xl2tpd/issues/187 * AVP is incorrect size issues with Miktrotik server There are reports of problems connecting to Miktrotik server. Github user reported that the following configuration works for them: https://github.com/xelerance/xl2tpd/issues/156#issuecomment-678674101 xl2tpd-1.3.16/CONTRIBUTION.md000066400000000000000000000035041374460464600153000ustar00rootroot00000000000000# Contributing to xl2tpd First of, thank you for taking the time to contribute. *Before spending a lot of time on something, please ask for feedback on your idea first!* You can ask in the [mailing list](https://lists.openswan.org/cgi-bin/mailman/listinfo/xl2tpd) or create an [issue](https://github.com/xelerance/xl2tpd/issues). This project welcomes contribution from the community! Here are a few suggestions: * Update the [ipv6 branch](https://github.com/xelerance/xl2tpd/tree/ipv6). It needs to be tested and updated (it has diverged from master quite a bit). * Test and fix up the [libevent branch](https://github.com/xelerance/xl2tpd/tree/libevent). There have been reports of crashes. They need to be investigated. User can get more information with the custom *--debug-signals* and *--debug-libevent* option (which is only in this branch) ## **Did you find a bug?** To report a security issue please send an e-mail to security@xelerance.com For non-security problems, ensure the bug was not already reported by searching on GitHub under "[Issues](https://github.com/xelerance/xl2tpd/issues)" and "[Pull requests](https://github.com/xelerance/xl2tpd/pulls)". When reporting an issue, please provide output and the content of the logs. ## **Did you write a patch that fixes a bug?** * Open a new GitHub pull request with the patch. * Ensure the PR description clearly describes the problem and solution. Include the relevant issue number if applicable. * Always write a clear log message for your commits. One-line messages are fine for small changes, but bigger changes should look like this: $ git commit -m "A brief summary of the commit > > A paragraph describing what changed and its impact." $ git commit -m "A brief summary of the commit > > A paragraph describing what changed and its impact." xl2tpd-1.3.16/CREDITS000066400000000000000000000036261374460464600140640ustar00rootroot00000000000000* Xelerance has forked l2tpd into xl2tpd. * Michael Richardson , for adding IPsec SAref tracking * Paul Wouters , for packaging, debugging and support. * Tuomo Soini for various packaging and initscript patches * Shingo Yamawaki & Shinichi Furuso for SAref related patches. Thanks to Jacco de Leeuw for his maintenance of the 0.69 version of l2tpd. Original credits follow. Mark Spencer was the primary author of this work. He would like to thank the following people for their contributions: * Peter Brackett, Adtran, for supporting the creation of this free software * Alan Cox, RedHat, for architectural suggestions and moral support :) * Kyle Farnsworth, Adtran, for helping me get started and for providing me with the Adtran LAC for initial testing * Ashish Lal, Midnight Networks, for thorughly evaluating compliance of l2tpd to the published l2tp specification * Rich Martin, Deltacom, for loaning me a Cisco 3000 router for interoperability testing * Kevin Schneider, Adtran, for initially pointing me in the direction of doing l2tp support for Linux * Mark Townsley, Cisco Systems, for helping answer a variety of questions (particularly relating to authentication) and for aiding with interoperability testing with Cisco l2tp software. The MD5 code was written by Colin Plumb, and is without copyright (public domain). This project was forked January 12, 2001 by Scott Balmos and David Stipp due to the apparent inactivity of the project. We also would like to thank the following people who helped us after the fork: * Jeff McAdams, IgLou Internet Services, for being our own Alan Cox clone. * Huiban Yoann, Siemens, for some scaleability improvements. * Jens Zerbst, for initial implementation of a rudimentary Outgoing Call Request system * Everyone out there who have submitted an uncountable amount of little bug fixes. Thanks all!!! xl2tpd-1.3.16/LICENSE000066400000000000000000000432541374460464600140520ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. xl2tpd-1.3.16/Makefile000066400000000000000000000126711374460464600145040ustar00rootroot00000000000000# # Layer Two Tunneling Protocol Daemon # Copyright (C)1998 Adtran, Inc. # # Mark Spencer # # This is free software. You may distribute it under # the terms of the GNU General Public License, # version 2, or at your option any later version. include Makefile.ver # # Note on debugging flags: # -DDEBUG_ZLB shows all ZLB exchange traffic # -DDEBUG_HELLO debugs when hello messages are sent # -DDEBUG_CLOSE debugs call and tunnel closing # -DDEBUG_FLOW debugs flow control system # -DDEBUG_FILE debugs file format # -DDEBUG_AAA debugs authentication, accounting, and access control # -DDEBUG_PAYLOAD shows info on every payload packet # -DDEBUG_CONTROL shows info on every control packet and the l2tp-control pipe # -DDEBUG_PPPD shows the command line of pppd and how we signal pppd (see below) # -DDEBUG_HIDDEN debugs hidden AVP's # -DDEBUG_ENTROPY debug entropy generation # -DDEBUG_CONTROL_XMIT # -DDEBUG_MAGIC # -DDEBUG_FLOW_MORE # -DDEBUG_AUTH # # -DTEST_HIDDEN makes Assigned Call ID sent as a hidden AVP # # -DTRUST_PPPD_TO_DIE # # Defining TRUST_PPPD_TO_DIE disables a workaround for broken pppds. Do NOT # define this unless you fully trust your version of pppd to honour SIGTERM. # However, if you experience hanging pppd's, which cause xl2tpd to also hang, # enable this. # The cost of not trusting pppd to die (and shoot it down hard), is that your # pppd's ip-down scripts will not have a chance to run. # # For more details see: http://bugs.xelerance.com/view.php?id=739 # # Confirmed bad versions of pppd: # - ppp-2.4.2-6.4.RHEL4 # Confirmed good version of pppd: # - recent Ubuntu/Debian pppd's # # ppp 2.4.3 sends a SIGTERM after 5 seconds, so it should be safe to # trust pppd. This work around will be removed in the near future. # DFLAGS= -g -DDEBUG_HELLO -DDEBUG_CLOSE -DDEBUG_FLOW -DDEBUG_PAYLOAD -DDEBUG_CONTROL -DDEBUG_CONTROL_XMIT -DDEBUG_FLOW_MORE -DDEBUG_MAGIC -DDEBUG_ENTROPY -DDEBUG_HIDDEN -DDEBUG_PPPD -DDEBUG_AAA -DDEBUG_FILE -DDEBUG_FLOW -DDEBUG_HELLO -DDEBUG_CLOSE -DDEBUG_ZLB -DDEBUG_AUTH DFLAGS?= -DDEBUG_PPPD -DTRUST_PPPD_TO_DIE # Uncomment the next line for Linux. KERNELSRC is needed for if_pppol2tp.h, # but we use a local copy if we don't find it. # #KERNELSRC=/lib/modules/`uname -r`/build/ KERNELSRC?=./linux OSFLAGS?= -DLINUX -I$(KERNELSRC)/include/ # # Uncomment the following to use the kernel interface under Linux # This requires the pppol2tp-linux-2.4.27.patch patch from contrib # or a 2.6.23+ kernel. On some distributions kernel include files # are packages seperately (eg kernel-headers on Fedora) # Note: 2.6.23+ support still needs some changes in the xl2tpd source # OSFLAGS+= -DUSE_KERNEL # # # Uncomment the next line for FreeBSD # #OSFLAGS?= -DFREEBSD # # Uncomment the next three lines for NetBSD # #OSFLAGS?= -DNETBSD #CFLAGS+= -D_NETBSD_SOURCE #LDLIBS?= -lutil # # Uncomment the next line for Solaris. For solaris, at least, # we don't want to specify -I/usr/include because it is in # the basic search path, and will over-ride some gcc-specific # include paths and cause problems. # #CC?=gcc # Change /opt/sfw/ to whereever your pcap library/include files are #OSFLAGS?= -DSOLARIS -DPPPD=\"/usr/bin/pppd\" -std=c99 -pedantic -D__EXTENSIONS__ -D_XPG4_2 -D_XPG6 -I/opt/sfw/include #OSLIBS?= -lnsl -lsocket # Uncomment the next two lines for OpenBSD # #OSFLAGS?= -DOPENBSD #LDLIBS?= -lutil # Feature flags # # Comment the following line to disable xl2tpd maintaining IP address # pools to pass to pppd to control IP address allocation IPFLAGS?= -DIP_ALLOCATION CFLAGS+= $(DFLAGS) -Os -Wall -Wextra -DSANITY $(OSFLAGS) $(IPFLAGS) HDRS=l2tp.h avp.h misc.h control.h call.h scheduler.h file.h aaa.h md5.h OBJS=xl2tpd.o pty.o misc.o control.o avp.o call.o network.o avpsend.o scheduler.o file.o aaa.o md5.o SRCS=${OBJS:.o=.c} ${HDRS} CONTROL_SRCS=xl2tpd-control.c #LIBS= $(OSLIBS) # -lefence # efence for malloc checking EXEC=xl2tpd CONTROL_EXEC=xl2tpd-control PREFIX?=/usr/local SBINDIR?=$(DESTDIR)${PREFIX}/sbin BINDIR?=$(DESTDIR)${PREFIX}/bin MANDIR?=$(DESTDIR)${PREFIX}/share/man all: $(EXEC) pfc $(CONTROL_EXEC) clean: rm -f $(OBJS) $(EXEC) pfc.o pfc $(CONTROL_EXEC) $(EXEC): $(OBJS) $(HDRS) $(CC) $(LDFLAGS) -o $@ $(OBJS) $(LDLIBS) $(CONTROL_EXEC): $(CONTROL_SRCS) $(CC) $(CFLAGS) $(LDFLAGS) $(CONTROL_SRCS) -o $@ pfc: $(CC) $(CFLAGS) -c contrib/pfc.c $(CC) $(LDFLAGS) -o pfc pfc.o -lpcap $(LDLIBS) romfs: $(ROMFSINST) /bin/$(EXEC) version: @echo ${XL2TPDVERSION} packagingprep: sed -i "s/XL2TPDVERSION=.*/XL2TPDVERSION=${XL2TPDBASEVERSION}/" Makefile.ver sed -i "s/#define SERVER_VERSION .*/#define SERVER_VERSION \"xl2tpd-${XL2TPDBASEVERSION}\"/" l2tp.h sed -i "s/Version: .*/Version: ${XL2TPDBASEVERSION}/" packaging/*/*.spec sed -i "s/PKG_VERSION:=.*/PKG_VERSION:=${XL2TPDBASEVERSION}/" packaging/openwrt/Makefile install: ${EXEC} pfc ${CONTROL_EXEC} install -d -m 0755 ${SBINDIR} install -m 0755 $(EXEC) ${SBINDIR}/$(EXEC) install -d -m 0755 ${MANDIR}/man5 install -d -m 0755 ${MANDIR}/man8 install -m 0644 doc/xl2tpd.8 ${MANDIR}/man8/ install -m 0644 doc/xl2tpd-control.8 ${MANDIR}/man8/ install -m 0644 doc/xl2tpd.conf.5 doc/l2tp-secrets.5 \ ${MANDIR}/man5/ # pfc install -d -m 0755 ${BINDIR} install -m 0755 pfc ${BINDIR}/pfc install -d -m 0755 ${MANDIR}/man1 install -m 0644 contrib/pfc.1 ${MANDIR}/man1/ # control exec install -d -m 0755 ${SBINDIR} install -m 0755 $(CONTROL_EXEC) ${SBINDIR}/$(CONTROL_EXEC) # openbsd # install -d -m 0755 /var/run/xl2tpd # mkfifo /var/run/l2tp-control TAGS: ${SRCS} etags ${SRCS} xl2tpd-1.3.16/Makefile.ver000066400000000000000000000000251374460464600152650ustar00rootroot00000000000000XL2TPDVERSION=1.3.16 xl2tpd-1.3.16/README.md000066400000000000000000000035021374460464600143140ustar00rootroot00000000000000# xl2tpd [![Build Status](https://travis-ci.org/xelerance/xl2tpd.svg?branch=1.3.16dev)](https://travis-ci.org/xelerance/xl2tpd) xl2tpd is a **FREE** implementation of the Layer 2 Tunneling Protocol as defined by [RFC 2661](https://tools.ietf.org/rfc/rfc2661.txt). L2TP allows you to tunnel PPP over UDP. Some ISPs use L2TP to tunnel user sessions from dial-in servers (modem banks, ADSL DSLAMs) to back-end PPP servers. Another important application is Virtual Private Networks where the IPsec protocol is used to secure the L2TP connection (L2TP/IPsec is defined by [RFC 3193](https://tools.ietf.org/rfc/rfc3193.txt). xl2tpd can be used in combination with IPsec implementations such as Openswan. Example configuration files for such a setup are included in the examples directory. xl2tpd uses a pseudo-tty to communicate with pppd. It runs in userspace but supports kernel mode L2TP. xl2tpd supports IPsec SA Reference tracking to enable overlapping internal NAT'ed IP's by different clients (eg all clients connecting from their linksys internal IP 192.168.1.101) as well as multiple clients behind the same NAT router. Xl2tpd is based on the L2TP code base of Jeff McAdams . It was de-facto maintained by Jacco de Leeuw in 2002 and 2003. NOTE: In Linux kernel 4.15+ there is a kernel bug with ancillary IP_PKTINFO. As such, for Linux kernel 4.15+ we recommend the community use xl2tpd 1.3.12+ ## Build and install make sudo make install The xl2tpd.conf(5) man page has details on how to configure xl2tpd. ## Mailing Lists https://lists.openswan.org/cgi-bin/mailman/listinfo/xl2tpd is home of the mailing list. Note: This is a closed list - you **must** be subscribed to be able to post mails. ## Security Vulnerability Security vulnerabilities can be e-mailed to: security@xelerance.com xl2tpd-1.3.16/TODO000066400000000000000000000013651374460464600135320ustar00rootroot00000000000000Critical: * Improved performance * Rate Adaptive Timeouts * Fork processing code into a kernel module(?) * Fix protocol correctness issues * Are we sending valid and no invalid AVPs in various message types Other: * Support tie breakers * Support proxy authentication * Support LCP initial/final states * Maybe do something with private groups * Tunnel and call lookups should be hashes, not lists * Meaningful error message about pppd problems...for either not installed, or no kernel support (if possible) Niceties: * Improve success/fail result codes for some commands of xl2tpd-control * Extend xl2tpd-control to support all available commands * Add xl2tpd-control status command to see/watch tunnel status Way-down-the-line: * GUI configuration xl2tpd-1.3.16/aaa.c000066400000000000000000000353601374460464600137320ustar00rootroot00000000000000/* * Layer Two Tunnelling Protocol Daemon * Copyright (C) 1998 Adtran, Inc. * Copyright (C) 2002 Jeff McAdams * * Mark Spencer * * This software is distributed under the terms * of the GPL, which you should have received * along with this source. * * Authorization, Accounting, and Access control * */ #include #include #include #include #include #include #include "l2tp.h" extern void bufferDump (char *, int); /* FIXME: Accounting? */ struct addr_ent *uaddr[ADDR_HASH_SIZE]; void init_addr () { int x; for (x = 0; x < ADDR_HASH_SIZE; x++) uaddr[x] = NULL; } static int ip_used (unsigned int addr) { struct addr_ent *tmp; tmp = uaddr[addr % ADDR_HASH_SIZE]; while (tmp) { if (tmp->addr == addr) return -1; tmp = tmp->next; } return 0; } void mk_challenge (unsigned char *c, int length) { get_entropy(c, length); /* int x; int *s = (int *) c; for (x = 0; x < length / sizeof (int); x++) s[x] = rand (); */ } void reserve_addr (unsigned int addr) { /* Mark this address as in use */ struct addr_ent *tmp, *tmp2; addr = ntohl (addr); if (ip_used (addr)) return; tmp = uaddr[addr % ADDR_HASH_SIZE]; tmp2 = malloc (sizeof (struct addr_ent)); uaddr[addr % ADDR_HASH_SIZE] = tmp2; tmp2->next = tmp; tmp2->addr = addr; } void unreserve_addr (unsigned int addr) { struct addr_ent *tmp, *last = NULL, *z; addr = ntohl (addr); tmp = uaddr[addr % ADDR_HASH_SIZE]; while (tmp) { if (tmp->addr == addr) { if (last) { last->next = tmp->next; } else { uaddr[addr % ADDR_HASH_SIZE] = tmp->next; } z = tmp; tmp = tmp->next; free (z); } else { last = tmp; tmp = tmp->next; } } } unsigned int get_addr (struct iprange *ipr) { unsigned int x, y; int status; struct iprange *ipr2; while (ipr) { if (ipr->sense == SENSE_ALLOW) for (x = ntohl (ipr->start); x <= ntohl (ipr->end); x++) { /* Found an IP in an ALLOW range, check to be sure it is consistent through the remaining regions */ if (!ip_used (x)) { status = SENSE_ALLOW; ipr2 = ipr->next; while (ipr2) { if ((x >= ntohl (ipr2->start)) && (x <= ntohl (ipr2->end))) status = ipr2->sense; ipr2 = ipr2->next; } y = htonl (x); if (status == SENSE_ALLOW) return y; } }; ipr = ipr->next; } return 0; } static int get_secret (char *us, char *them, unsigned char *secret, int size) { FILE *f; char buf[STRLEN]; char *u, *t, *s; int num = 0; f = fopen (gconfig.authfile, "r"); if (!f) { l2tp_log (LOG_WARNING, "%s : Unable to open '%s' for authentication\n", __FUNCTION__, gconfig.authfile); return 0; } while (!feof (f)) { num++; if (NULL == fgets (buf, sizeof (buf), f)) { /* Error or EOF */ break; } /* Strip comments */ for (t = buf; *t; t++) *t = ((*t == '#') || (*t == ';')) ? 0 : *t; /* Strip trailing whitespace */ for (t = buf + strlen (buf) - 1; (t >= buf) && (*t < 33); t--) *t = 0; if (!strlen (buf)) continue; /* Empty line */ u = buf; while (*u && (*u < 33)) u++; /* us */ if (!*u) { l2tp_log (LOG_WARNING, "%s: Invalid authentication info (no us), line %d\n", __FUNCTION__, num); continue; } t = u; while (*t > 32) t++; *(t++) = 0; while (*t && (*t < 33)) t++; /* them */ if (!*t) { l2tp_log (LOG_WARNING, "%s: Invalid authentication info (nothem), line %d\n", __FUNCTION__, num); continue; } s = t; while (*s > 33) s++; *(s++) = 0; while (*s && (*s < 33)) s++; if (!*s) { l2tp_log (LOG_WARNING, "%s: Invalid authentication info (no secret), line %d\n", __FUNCTION__, num); continue; } if ((!strcasecmp (u, us) || !strcasecmp (u, "*")) && (!strcasecmp (t, them) || !strcasecmp (t, "*"))) { #ifdef DEBUG_AUTH l2tp_log (LOG_DEBUG, "%s: we are '%s', they are '%s', secret is '%s'\n", __FUNCTION__, u, t, s); #endif strncpy ((char *)secret, s, size); fclose(f); return -1; } } fclose(f); return 0; } int handle_challenge (struct tunnel *t, struct challenge *chal) { char *us; char *them; if (!t->lns && !t->lac) { l2tp_log (LOG_DEBUG, "%s: No LNS or LAC to handle challenge!\n", __FUNCTION__); return -1; } #ifdef DEBUG_AUTH l2tp_log (LOG_DEBUG, "%s: making response for tunnel: %d\n", __FUNCTION__, t->ourtid); #endif if (t->lns) { if (t->lns->hostname[0]) us = t->lns->hostname; else us = hostname; if (t->lns->peername[0]) them = t->lns->peername; else them = t->hostname; } else { if (t->lac->hostname[0]) us = t->lac->hostname; else us = hostname; if (t->lac->peername[0]) them = t->lac->peername; else them = t->hostname; } if (!get_secret (us, them, chal->secret, sizeof (chal->secret))) { l2tp_log (LOG_DEBUG, "%s: no secret found for us='%s' and them='%s'\n", __FUNCTION__, us, them); return -1; } #if DEBUG_AUTH l2tp_log (LOG_DEBUG, "*%s: Here comes the chal->ss:\n", __FUNCTION__); bufferDump (&chal->ss, 1); l2tp_log (LOG_DEBUG, "%s: Here comes the secret\n", __FUNCTION__); bufferDump (chal->secret, strlen (chal->secret)); l2tp_log (LOG_DEBUG, "%s: Here comes the challenge\n", __FUNCTION__); bufferDump (chal->challenge, chal->chal_len); #endif memset (chal->response, 0, MD_SIG_SIZE); MD5Init (&chal->md5); MD5Update (&chal->md5, &chal->ss, 1); MD5Update (&chal->md5, chal->secret, strlen ((char *)chal->secret)); MD5Update (&chal->md5, chal->challenge, chal->chal_len); MD5Final (chal->response, &chal->md5); #ifdef DEBUG_AUTH l2tp_log (LOG_DEBUG, "response is %X%X%X%X to '%s' and %X%X%X%X, %d\n", *((int *) &chal->response[0]), *((int *) &chal->response[4]), *((int *) &chal->response[8]), *((int *) &chal->response[12]), chal->secret, *((int *) &chal->challenge[0]), *((int *) &chal->challenge[4]), *((int *) &chal->challenge[8]), *((int *) &chal->challenge[12]), chal->ss); #endif chal->state = STATE_CHALLENGED; return 0; } struct lns *get_lns (struct tunnel *t) { /* * Look through our list of LNS's and * find a reasonable LNS for this call * if one is available */ struct lns *lns; struct iprange *ipr; int allow, checkdefault = 0; /* If access control is disabled, we give the default otherwise, we give nothing */ allow = 0; lns = lnslist; if (!lns) { lns = deflns; checkdefault = -1; } while (lns) { ipr = lns->lacs; while (ipr) { if ((ntohl (t->peer.sin_addr.s_addr) >= ntohl (ipr->start)) && (ntohl (t->peer.sin_addr.s_addr) <= ntohl (ipr->end))) { #ifdef DEBUG_AAA l2tp_log (LOG_DEBUG, "$s: Rule %s to %s, sense %s matched %s\n", __FUNCTION__, IPADDY (ipr->start), IPADDY (ipr->end), (ipr->sense ? "allow" : "deny"), IPADDY (t->peer.sin_addr.s_addr)); #endif allow = ipr->sense; } ipr = ipr->next; } if (allow) return lns; lns = lns->next; if (!lns && !checkdefault) { lns = deflns; checkdefault = -1; } } if (gconfig.accesscontrol) return NULL; else return deflns; } #ifdef DEBUG_HIDDEN static void print_md5 (void * const md5) { int *i = (int *) md5; l2tp_log (LOG_DEBUG, "%X%X%X%X\n", i[0], i[1], i[2], i[3], i[4]); } static inline void print_challenge (struct challenge *chal) { l2tp_log (LOG_DEBUG, "vector: "); print_md5 (chal->vector); l2tp_log (LOG_DEBUG, "secret: %s\n", chal->secret); } #endif void encrypt_avp (struct buffer *buf, _u16 len, struct tunnel *t) { /* Encrypts an AVP of len, at data. We assume there are two "spare bytes" before the data pointer,l but otherwise this is just a normal AVP that is about to be returned from an avpsend routine */ struct avp_hdr *new_hdr = (struct avp_hdr *) (buf->start + buf->len - len); struct avp_hdr *old_hdr = (struct avp_hdr *) (buf->start + buf->len - len + 2); _u16 length, flags, attr; /* New length, old flags */ unsigned char *ptr, *end; int cnt; unsigned char digest[MD_SIG_SIZE]; unsigned char *previous_segment; /* FIXME: Should I pad more randomly? Right now I pad to nearest 16 bytes */ length = ((len - sizeof (struct avp_hdr) + 1) / 16 + 1) * 16 + sizeof (struct avp_hdr); flags = htons (old_hdr->length) & 0xF000; new_hdr->length = htons (length | flags | HBIT); new_hdr->vendorid = old_hdr->vendorid; new_hdr->attr = attr = old_hdr->attr; /* This is really the length field of the hidden sub-format */ old_hdr->attr = htons (len - sizeof (struct avp_hdr)); /* Okay, now we've rewritten the header, as it should be. Let's start encrypting the actual data now */ buf->len -= len; buf->len += length; /* Back to the beginning of real data, including the original length AVP */ MD5Init (&t->chal_them.md5); MD5Update (&t->chal_them.md5, (void *) &attr, 2); MD5Update (&t->chal_them.md5, t->chal_them.secret, strlen ((char *)t->chal_them.secret)); MD5Update (&t->chal_them.md5, t->chal_them.vector, VECTOR_SIZE); MD5Final (digest, &t->chal_them.md5); /* Though not a "MUST" in the spec, our subformat length is always a multiple of 16 */ ptr = ((unsigned char *) new_hdr) + sizeof (struct avp_hdr); end = ((unsigned char *) new_hdr) + length; previous_segment = ptr; while (ptr < end) { #if DEBUG_HIDDEN l2tp_log (LOG_DEBUG, "%s: The digest to be XOR'ed\n", __FUNCTION__); bufferDump (digest, MD_SIG_SIZE); l2tp_log (LOG_DEBUG, "%s: The plaintext to be XOR'ed\n", __FUNCTION__); bufferDump (ptr, MD_SIG_SIZE); #endif for (cnt = 0; cnt < MD_SIG_SIZE; cnt++, ptr++) { *ptr = *ptr ^ digest[cnt]; } #if DEBUG_HIDDEN l2tp_log (LOG_DEBUG, "%s: The result of XOR\n", __FUNCTION__); bufferDump (previous_segment, MD_SIG_SIZE); #endif if (ptr < end) { MD5Init (&t->chal_them.md5); MD5Update (&t->chal_them.md5, t->chal_them.secret, strlen ((char *)t->chal_them.secret)); MD5Update (&t->chal_them.md5, previous_segment, MD_SIG_SIZE); MD5Final (digest, &t->chal_them.md5); } previous_segment = ptr; } } int decrypt_avp (char *buf, struct tunnel *t) { /* Decrypts a hidden AVP pointed to by buf. The new header will be expected to be two characters offset from the old */ int cnt = 0; int len, olen, flags; unsigned char digest[MD_SIG_SIZE]; char *ptr, *end; _u16 attr; struct avp_hdr *old_hdr = (struct avp_hdr *) buf; struct avp_hdr *new_hdr = (struct avp_hdr *) (buf + 2); int saved_segment_len; /* maybe less 16; may be used if the cipher is longer than 16 octets */ unsigned char saved_segment[MD_SIG_SIZE]; ptr = ((char *) old_hdr) + sizeof (struct avp_hdr); olen = old_hdr->length & 0x0FFF; end = buf + olen; if (!t->chal_us.vector) { l2tp_log (LOG_DEBUG, "%s: Hidden bit set, but no random vector specified!\n", __FUNCTION__); return -EINVAL; } /* First, let's decrypt all the data. We're not guaranteed that it will be padded to a 16 byte boundary, so we have to be more careful than when encrypting */ attr = ntohs (old_hdr->attr); MD5Init (&t->chal_us.md5); MD5Update (&t->chal_us.md5, (void *) &attr, 2); MD5Update (&t->chal_us.md5, t->chal_us.secret, strlen ((char *)t->chal_us.secret)); MD5Update (&t->chal_us.md5, t->chal_us.vector, t->chal_us.vector_len); MD5Final (digest, &t->chal_us.md5); #ifdef DEBUG_HIDDEN l2tp_log (LOG_DEBUG, "attribute is %d and challenge is: ", attr); print_challenge (&t->chal_us); l2tp_log (LOG_DEBUG, "md5 is: "); print_md5 (digest); #endif while (ptr < end) { if (cnt >= MD_SIG_SIZE) { MD5Init (&t->chal_us.md5); MD5Update (&t->chal_us.md5, t->chal_us.secret, strlen ((char *)t->chal_us.secret)); MD5Update (&t->chal_us.md5, saved_segment, MD_SIG_SIZE); MD5Final (digest, &t->chal_us.md5); cnt = 0; } /* at the beginning of each segment, we save the current segment (16 octets or less) of cipher * so that the next round of MD5 (if there is a next round) hash could use it */ if (cnt == 0) { saved_segment_len = (end - ptr < MD_SIG_SIZE) ? (end - ptr) : MD_SIG_SIZE; memcpy (saved_segment, ptr, saved_segment_len); } *ptr = *ptr ^ digest[cnt++]; ptr++; } /* Hopefully we're all nice and decrypted now. Let's rewrite the header. First save the old flags, and get the new stuff */ flags = old_hdr->length & 0xF000 & ~HBIT; len = ntohs (new_hdr->attr) + sizeof (struct avp_hdr); if (len > olen - 2) { l2tp_log (LOG_DEBUG, "%s: Decrypted length is too long (%d > %d)\n", __FUNCTION__, len, olen - 2); return -EINVAL; } new_hdr->attr = old_hdr->attr; new_hdr->vendorid = old_hdr->vendorid; new_hdr->length = len | flags; return 0; } xl2tpd-1.3.16/aaa.h000066400000000000000000000027741374460464600137420ustar00rootroot00000000000000/* * Layer Two Tunnelling Protocol Daemon * Copyright (C) 1998 Adtran, Inc. * Copyright (C) 2002 Jeff McAdams * * Mark Spencer * * This software is distributed under the terms * of the GPL, which you should have received * along with this source. * * Authorization, Accounting, and Access control * */ #ifndef _AAA_H #define _AAA_H #include "md5.h" #define ADDR_HASH_SIZE 256 #define MD_SIG_SIZE 16 #define MAX_VECTOR_SIZE 1024 #define VECTOR_SIZE 16 #define STATE_NONE 0 #define STATE_CHALLENGED 1 #define STATE_COMPLETE 2 struct addr_ent { unsigned int addr; struct addr_ent *next; }; struct challenge { struct MD5Context md5; unsigned char ss; /* State we're sending in */ unsigned char secret[MAXSTRLEN]; /* The shared secret */ unsigned char *challenge; /* The original challenge */ unsigned int chal_len; /* The length of the original challenge */ unsigned char response[MD_SIG_SIZE]; /* What we expect as a respsonse */ unsigned char reply[MD_SIG_SIZE]; /* What the peer sent */ unsigned char *vector; unsigned int vector_len; int state; /* What state is challenge in? */ }; extern struct lns *get_lns (struct tunnel *); extern unsigned int get_addr (struct iprange *); extern void reserve_addr (unsigned int); extern void unreserve_addr (unsigned int); extern void init_addr (); extern int handle_challenge (struct tunnel *, struct challenge *); extern void mk_challenge (unsigned char *, int); #endif xl2tpd-1.3.16/avp.c000066400000000000000000001456711374460464600140050ustar00rootroot00000000000000/* * Layer Two Tunnelling Protocol Daemon * Copyright (C) 1998 Adtran, Inc. * Copyright (C) 2002 Jeff McAdams * * Mark Spencer * * This software is distributed under the terms * of the GPL, which you should have received * along with this source. * * Attribute Value Pair handler routines */ #include #include #include #include #include #include "l2tp.h" #define AVP_MAX 39 struct avp avps[] = { {0, 1, &message_type_avp, "Message Type"}, {1, 1, &result_code_avp, "Result Code"}, {2, 1, &protocol_version_avp, "Protocol Version"}, {3, 1, &framing_caps_avp, "Framing Capabilities"}, {4, 1, &bearer_caps_avp, "Bearer Capabilities"}, {5, 0, NULL, "Tie Breaker"}, {6, 0, &firmware_rev_avp, "Firmware Revision"}, {7, 0, &hostname_avp, "Host Name"}, {8, 1, &vendor_avp, "Vendor Name"}, {9, 1, &assigned_tunnel_avp, "Assigned Tunnel ID"}, {10, 1, &receive_window_size_avp, "Receive Window Size"}, {11, 1, &challenge_avp, "Challenge"}, {12, 0, NULL, "Q.931 Cause Code"}, {13, 1, &chalresp_avp, "Challenge Response"}, {14, 1, &assigned_call_avp, "Assigned Call ID"}, {15, 1, &call_serno_avp, "Call Serial Number"}, {16, 1, NULL, "Minimum BPS"}, {17, 1, NULL, "Maximum BPS"}, {18, 1, &bearer_type_avp, "Bearer Type"}, {19, 1, &frame_type_avp, "Framing Type"}, {20, 1, &packet_delay_avp, "Packet Processing Delay"}, {21, 1, &dialed_number_avp, "Dialed Number"}, {22, 1, &dialing_number_avp, "Dialing Number"}, {23, 1, &sub_address_avp, "Sub-Address"}, {24, 1, &tx_speed_avp, "Transmit Connect Speed"}, {25, 1, &call_physchan_avp, "Physical channel ID"}, {26, 0, NULL, "Initial Received LCP Confreq"}, {27, 0, NULL, "Last Sent LCP Confreq"}, {28, 0, NULL, "Last Received LCP Confreq"}, {29, 1, &ignore_avp, "Proxy Authen Type"}, {30, 0, &ignore_avp, "Proxy Authen Name"}, {31, 0, &ignore_avp, "Proxy Authen Challenge"}, {32, 0, &ignore_avp, "Proxy Authen ID"}, {33, 1, &ignore_avp, "Proxy Authen Response"}, {34, 1, NULL, "Call Errors"}, {35, 1, &ignore_avp, "ACCM"}, {36, 1, &rand_vector_avp, "Random Vector"}, {37, 1, NULL, "Private Group ID"}, {38, 0, &rx_speed_avp, "Receive Connect Speed"}, {39, 1, &seq_reqd_avp, "Sequencing Required"} }; char *msgtypes[] = { NULL, "Start-Control-Connection-Request", "Start-Control-Connection-Reply", "Start-Control-Connection-Connected", "Stop-Control-Connection-Notification", NULL, "Hello", "Outgoing-Call-Request", "Outgoing-Call-Reply", "Outgoing-Call-Connected", "Incoming-Call-Request", "Incoming-Call-Reply", "Incoming-Call-Connected", NULL, "Call-Disconnect-Notify", "WAN-Error-Notify", "Set-Link-Info" }; char *stopccn_result_codes[] = { "Reserved", "General request to clear control connection", "General error--Error Code indicates the problem", "Control channel already exists", "Requester is not authorized to establish a control channel", "The protocol version of the requester is not supported--Error Code indicates the highest version supported", "Requester is being shut down", "Finite State Machine error" }; char *cdn_result_codes[] = { "Reserved", "Call disconnected due to loss of carrier", "Call disconnected for the reason indicated in error code", "Call disconnected for administrative reasons", "Call failed due to lack of appropriate facilities being available (temporary condition)", "Call failed due to lack of appropriate facilities being available (permanent condition)", "Invalid destination", "Call failed due to no carrier detected", "Call failed due to detection of a busy signal", "Call failed due to lack of a dial tone", "Call was no established within time allotted by LAC", "Call was connected but no appropriate framing was detect" }; void wrong_length (struct call *c, char *field, int expected, int found, int min) { if (min) snprintf (c->errormsg, sizeof (c->errormsg), "%s: expected at least %d, got %d", field, expected, found); else snprintf (c->errormsg, sizeof (c->errormsg), "%s: expected %d, got %d", field, expected, found); c->error = ERROR_LENGTH; c->result = RESULT_ERROR; c->needclose = -1; } struct unaligned_u16 { _u16 s; } __attribute__((packed)); /* * t, c, data, and datalen may be assumed to be defined for all AVP's */ int message_type_avp (struct tunnel *t, struct call *c, void *data, int datalen) { /* * This will be with every control message. It is critical that this * procedure check for the validity of sending this kind of a message * (assuming sanity check) */ struct unaligned_u16 *raw = data; c->msgtype = ntohs (raw[3].s); if (datalen != 8) { if (DEBUG) l2tp_log (LOG_DEBUG, "%s: wrong size (%d != 8)\n", __FUNCTION__, datalen); wrong_length (c, "Message Type", 8, datalen, 0); return -EINVAL; } if ((c->msgtype > MAX_MSG) || (!msgtypes[c->msgtype])) { if (DEBUG) l2tp_log (LOG_DEBUG, "%s: unknown message type %d\n", __FUNCTION__, c->msgtype); return -EINVAL; } if (gconfig.debug_avp) if (DEBUG) l2tp_log (LOG_DEBUG, "%s: message type %d (%s)\n", __FUNCTION__, c->msgtype, msgtypes[c->msgtype]); #ifdef SANITY if (t->sanity) { /* * Look out our state for each message and make sure everything * make sense... */ if ((c != t->self) && (c->msgtype < Hello)) { if (DEBUG) l2tp_log (LOG_DEBUG, "%s: attempting to negotiate tunnel inside a call!\n", __FUNCTION__); return -EINVAL; } switch (c->msgtype) { case SCCRQ: if ((t->state != 0) && (t->state != SCCRQ)) { /* * When we handle tie breaker AVP's, then we'll check * to see if we've both requested tunnels */ if (DEBUG) l2tp_log (LOG_DEBUG, "%s: attempting to negotiate SCCRQ with state != 0\n", __FUNCTION__); return -EINVAL; } break; case SCCRP: if (t->state != SCCRQ) { if (DEBUG) l2tp_log (LOG_DEBUG, "%s: attempting to negotiate SCCRP with state != SCCRQ!\n", __FUNCTION__); return -EINVAL; } break; case SCCCN: if (t->state != SCCRP) { if (DEBUG) l2tp_log (LOG_DEBUG, "%s: attempting to negotiate SCCCN with state != SCCRP!\n", __FUNCTION__); return -EINVAL; } break; case ICRQ: if (t->state != SCCCN) { if (DEBUG) l2tp_log (LOG_DEBUG, "%s: attempting to negotiate ICRQ when state != SCCCN\n", __FUNCTION__); return -EINVAL; } if (c != t->self) { if (DEBUG) l2tp_log (LOG_DEBUG, "%s: attempting to negotiate ICRQ on a call!\n", __FUNCTION__); return -EINVAL; } break; case ICRP: if (t->state != SCCCN) { if (DEBUG) l2tp_log (LOG_DEBUG, "%s: attempting to negotiate ICRP on tunnel!=SCCCN\n", __FUNCTION__); return -EINVAL; } if (c->state != ICRQ) { if (DEBUG) l2tp_log (LOG_DEBUG, "%s: attempting to negotiate ICRP when state != ICRQ\n", __FUNCTION__); return -EINVAL; } break; case ICCN: if (c->state != ICRP) { if (DEBUG) l2tp_log (LOG_DEBUG, "%s: attempting to negotiate ICCN when state != ICRP\n", __FUNCTION__); return -EINVAL; } break; case SLI: if (c->state != ICCN) { if (DEBUG) l2tp_log (LOG_DEBUG, "%s: attempting to negotiate SLI when state != ICCN\n", __FUNCTION__); return -EINVAL; } break; case OCRP: /* jz: case for ORCP */ if (t->state != SCCCN) { if (DEBUG) l2tp_log (LOG_DEBUG, "%s: attempting to negotiate OCRP on tunnel!=SCCCN\n", __FUNCTION__); return -EINVAL; } if (c->state != OCRQ) { if (DEBUG) l2tp_log (LOG_DEBUG, "%s: attempting to negotiate OCRP when state != OCRQ\n", __FUNCTION__); return -EINVAL; } break; case OCCN: /* jz: case for OCCN */ if (c->state != OCRQ) { if (DEBUG) l2tp_log (LOG_DEBUG, "%s: attempting to negotiate OCCN when state != OCRQ\n", __FUNCTION__); return -EINVAL; } break; case StopCCN: case CDN: case Hello: break; default: l2tp_log (LOG_WARNING, "%s: i don't know how to handle %s messages\n", __FUNCTION__, msgtypes[c->msgtype]); return -EINVAL; } } #endif if (c->msgtype == ICRQ) { struct call *tmp; if (gconfig.debug_avp) { if (DEBUG) l2tp_log (LOG_DEBUG, "%s: new incoming call\n", __FUNCTION__); } tmp = new_call (t); if (!tmp) { l2tp_log (LOG_WARNING, "%s: unable to create new call\n", __FUNCTION__); return -EINVAL; } tmp->next = t->call_head; t->call_head = tmp; t->count++; /* * Is this still safe to assume that the head will always * be the most recent call being negotiated? * Probably... FIXME anyway... */ } return 0; } int rand_vector_avp (struct tunnel *t, struct call *c, void *data, int datalen) { int size; struct unaligned_u16 *raw = data; size = raw[0].s & 0x03FF; size -= sizeof (struct avp_hdr); #ifdef SANITY if (t->sanity) { if (size < 0) { if (DEBUG) l2tp_log (LOG_DEBUG, "%s: Random vector too small (%d < 0)\n", __FUNCTION__, size); wrong_length (c, "Random Vector", 6, datalen, 1); return -EINVAL; } if (size > MAX_VECTOR_SIZE) { if (DEBUG) l2tp_log (LOG_DEBUG, "%s: Random vector too large (%d > %d)\n", __FUNCTION__, datalen, MAX_VECTOR_SIZE); wrong_length (c, "Random Vector", 6, datalen, 1); return -EINVAL; } } #endif if (gconfig.debug_avp) l2tp_log (LOG_DEBUG, "%s: Random Vector of %d octets\n", __FUNCTION__, size); t->chal_us.vector = (unsigned char *) &raw[3].s; t->chal_us.vector_len = size; return 0; } int ignore_avp (struct tunnel *t, struct call *c, void *data, int datalen) { /* * The spec says we have to accept authentication information * even if we just ignore it, so that's exactly what * we're going to do at this point. Proxy authentication is such * a ridiculous security threat anyway except from local * controlled machines. * * FIXME: I need to handle proxy authentication as an option. * One option is to simply change the options we pass to pppd. * */ UNUSED(data); UNUSED(datalen); if (gconfig.debug_avp) { if (DEBUG) l2tp_log (LOG_DEBUG, "%s : Ignoring AVP\n", __FUNCTION__); } return 0; } int seq_reqd_avp (struct tunnel *t, struct call *c, void *data, int datalen) { UNUSED(data); #ifdef SANITY if (t->sanity) { if (datalen != 6) { if (DEBUG) l2tp_log (LOG_DEBUG, "%s: avp is incorrect size. %d != 6\n", __FUNCTION__, datalen); wrong_length (c, "Sequencing Required", 6, datalen, 1); return -EINVAL; } switch (c->msgtype) { case ICCN: break; default: if (DEBUG) l2tp_log (LOG_DEBUG, "%s: sequencing required not appropriate for %s!\n", __FUNCTION__, msgtypes[c->msgtype]); return -EINVAL; } } #endif if (gconfig.debug_avp) { if (DEBUG) l2tp_log (LOG_DEBUG, "%s: peer requires sequencing.\n", __FUNCTION__); } c->seq_reqd = -1; return 0; } int result_code_avp (struct tunnel *t, struct call *c, void *data, int datalen) { /* * Find out what version of L2TP the other side is using. * I'm not sure what we're supposed to do with this but whatever.. */ int error = -1; /* error code unset */ int result; struct unaligned_u16 *raw = data; #ifdef SANITY if (t->sanity) { if (datalen < 8) { if (DEBUG) l2tp_log (LOG_DEBUG, "%s: avp is incorrect size. %d < 8\n", __FUNCTION__, datalen); wrong_length (c, "Result Code", 8, datalen, 1); return -EINVAL; } switch (c->msgtype) { case CDN: case StopCCN: break; default: if (DEBUG) l2tp_log (LOG_DEBUG, "%s: result code not appropriate for %s. Ignoring.\n", __FUNCTION__, msgtypes[c->msgtype]); return 0; } } #endif result = ntohs (raw[3].s); /* * from prepare_StopCCN and prepare_CDN, note missing htons() call * http://www.opensource.apple.com/source/ppp/ppp-412.3/Drivers/L2TP/L2TP-plugin/l2tp.c */ if (((result & 0xFF) == 0) && (result >> 8 != 0)) { if (DEBUG) l2tp_log (LOG_DEBUG, "%s: result code endianness fix for buggy Apple client. network=%d, le=%d\n", __FUNCTION__, result, result >> 8); result >>= 8; } if ((c->msgtype == StopCCN) && ((result > 7) || (result < 1))) { if (DEBUG) l2tp_log (LOG_DEBUG, "%s: result code out of range (%d %d %d). Ignoring.\n", __FUNCTION__, result, error, datalen); return 0; } if ((c->msgtype == CDN) && ((result > 11) || (result < 1))) { if (DEBUG) l2tp_log (LOG_DEBUG, "%s: result code out of range (%d %d %d). Ignoring.\n", __FUNCTION__, result, error, datalen); return 0; } if (datalen >= 10) { error = ntohs (raw[4].s); if (((error & 0xFF) == 0) && (error >> 8 != 0)) { if (DEBUG) l2tp_log (LOG_DEBUG, "%s: error code endianness fix for buggy Apple client. network=%d, le=%d\n", __FUNCTION__, error, error >> 8); error >>= 8; } } c->error = error; c->result = result; if (datalen > 10) safe_copy (c->errormsg, (char *) &raw[5].s, datalen - 10); else c->errormsg[0] = 0; if (gconfig.debug_avp) { if (DEBUG && (c->msgtype == StopCCN)) { l2tp_log (LOG_DEBUG, "%s: peer closing for reason %d (%s), error = %d (%s)\n", __FUNCTION__, result, stopccn_result_codes[result], error, c->errormsg); } else { l2tp_log (LOG_DEBUG, "%s: peer closing for reason %d (%s), error = %d (%s)\n", __FUNCTION__, result, cdn_result_codes[result], error, c->errormsg); } } return 0; } int protocol_version_avp (struct tunnel *t, struct call *c, void *data, int datalen) { /* * Find out what version of L2TP the other side is using. * I'm not sure what we're supposed to do with this but whatever.. */ int ver; struct unaligned_u16 *raw = data; #ifdef SANITY if (t->sanity) { if (datalen != 8) { if (DEBUG) l2tp_log (LOG_DEBUG, "%s: avp is incorrect size. %d != 8\n", __FUNCTION__, datalen); wrong_length (c, "Protocol Version", 8, datalen, 1); return -EINVAL; } switch (c->msgtype) { case SCCRP: case SCCRQ: break; default: if (DEBUG) l2tp_log (LOG_DEBUG, "%s: protocol version not appropriate for %s. Ignoring.\n", __FUNCTION__, msgtypes[c->msgtype]); return 0; } } #endif ver = ntohs (raw[3].s); if (gconfig.debug_avp) { if (DEBUG) l2tp_log (LOG_DEBUG, "%s: peer is using version %d, revision %d.\n", __FUNCTION__, (ver >> 8), ver & 0xFF); } return 0; } int framing_caps_avp (struct tunnel *t, struct call *c, void *data, int datalen) { /* * Retrieve the framing capabilities * from the peer */ int caps; struct unaligned_u16 *raw = data; #ifdef SANITY if (t->sanity) { switch (c->msgtype) { case SCCRP: case SCCRQ: break; default: if (DEBUG) l2tp_log (LOG_DEBUG, "%s: framing capabilities not appropriate for %s. Ignoring.\n", __FUNCTION__, msgtypes[c->msgtype]); return 0; } if (datalen != 10) { if (DEBUG) l2tp_log (LOG_DEBUG, "%s: avp is incorrect size. %d != 10\n", __FUNCTION__, datalen); wrong_length (c, "Framming Capabilities", 10, datalen, 0); return -EINVAL; } } #endif caps = ntohs (raw[4].s); if (gconfig.debug_avp) if (DEBUG) l2tp_log (LOG_DEBUG, "%s: supported peer frames:%s%s\n", __FUNCTION__, caps & ASYNC_FRAMING ? " async" : "", caps & SYNC_FRAMING ? " sync" : ""); t->fc = caps & (ASYNC_FRAMING | SYNC_FRAMING); return 0; } int bearer_caps_avp (struct tunnel *t, struct call *c, void *data, int datalen) { /* * What kind of bearer channels does our peer support? */ int caps; struct unaligned_u16 *raw = data; #ifdef SANITY if (t->sanity) { switch (c->msgtype) { case SCCRP: case SCCRQ: break; default: if (DEBUG) l2tp_log (LOG_DEBUG, "%s: bearer capabilities not appropriate for message %s. Ignoring.\n", __FUNCTION__, msgtypes[c->msgtype]); return 0; } if (datalen != 10) { if (DEBUG) l2tp_log (LOG_DEBUG, "%s: avp is incorrect size. %d != 10\n", __FUNCTION__, datalen); wrong_length (c, "Bearer Capabilities", 10, datalen, 0); return -EINVAL; } } #endif caps = ntohs (raw[4].s); if (gconfig.debug_avp) { if (DEBUG) { l2tp_log (LOG_DEBUG, "%s: supported peer bearers:%s%s\n", __FUNCTION__, caps & ANALOG_BEARER ? " analog" : "", caps & DIGITAL_BEARER ? " digital" : ""); } } t->bc = caps & (ANALOG_BEARER | DIGITAL_BEARER); return 0; } /* FIXME: I need to handle tie breakers eventually */ int firmware_rev_avp (struct tunnel *t, struct call *c, void *data, int datalen) { /* * Report and record remote firmware version */ int ver; struct unaligned_u16 *raw = data; #ifdef SANITY if (t->sanity) { switch (c->msgtype) { case SCCRP: case SCCRQ: break; default: if (DEBUG) l2tp_log (LOG_DEBUG, "%s: firmware revision not appropriate for message %s. Ignoring.\n", __FUNCTION__, msgtypes[c->msgtype]); return 0; } if (datalen != 8) { if (DEBUG) l2tp_log (LOG_DEBUG, "%s: avp is incorrect size. %d != 8\n", __FUNCTION__, datalen); wrong_length (c, "Firmware Revision", 8, datalen, 0); return -EINVAL; } } #endif ver = ntohs (raw[3].s); if (gconfig.debug_avp) { if (DEBUG) l2tp_log (LOG_DEBUG, "%s: peer reports firmware version %d (0x%.4x)\n", __FUNCTION__, ver, ver); } t->firmware = ver; return 0; } int bearer_type_avp (struct tunnel *t, struct call *c, void *data, int datalen) { /* * What kind of bearer channel is the call on? */ int b; struct unaligned_u16 *raw = data; #ifdef SANITY if (t->sanity) { switch (c->msgtype) { case ICRQ: case OCRQ: break; default: if (DEBUG) l2tp_log (LOG_DEBUG, "%s: bearer type not appropriate for message %s. Ignoring.\n", __FUNCTION__, msgtypes[c->msgtype]); return 0; } if (datalen != 10) { if (DEBUG) l2tp_log (LOG_DEBUG, "%s: avp is incorrect size. %d != 10\n", __FUNCTION__, datalen); wrong_length (c, "Bearer Type", 10, datalen, 0); return -EINVAL; } } #endif b = ntohs (raw[4].s); if (gconfig.debug_avp) { if (DEBUG) l2tp_log (LOG_DEBUG, "%s: peer bears:%s\n", __FUNCTION__, b & ANALOG_BEARER ? " analog" : "digital"); } t->call_head->bearer = b; return 0; } int frame_type_avp (struct tunnel *t, struct call *c, void *data, int datalen) { /* * What kind of frame channel is the call on? */ int b; struct unaligned_u16 *raw = data; #ifdef SANITY if (t->sanity) { switch (c->msgtype) { case ICCN: case OCRQ: case OCCN: break; default: if (DEBUG) l2tp_log (LOG_DEBUG, "%s: frame type not appropriate for message %s. Ignoring.\n", __FUNCTION__, msgtypes[c->msgtype]); return 0; } if (datalen != 10) { if (DEBUG) l2tp_log (LOG_DEBUG, "%s: avp is incorrect size. %d != 10\n", __FUNCTION__, datalen); wrong_length (c, "Frame Type", 10, datalen, 0); return -EINVAL; } } #endif b = ntohs (raw[4].s); if (gconfig.debug_avp) { if (DEBUG) l2tp_log (LOG_DEBUG, "%s: peer uses:%s frames\n", __FUNCTION__, b & ASYNC_FRAMING ? " async" : "sync"); } c->frame = b; return 0; } int hostname_avp (struct tunnel *t, struct call *c, void *data, int datalen) { /* * What is the peer's name? */ int size; struct unaligned_u16 *raw = data; #ifdef SANITY if (t->sanity) { switch (c->msgtype) { case SCCRP: case SCCRQ: break; default: if (DEBUG) l2tp_log (LOG_DEBUG, "%s: hostname not appropriate for message %s. Ignoring.\n", __FUNCTION__, msgtypes[c->msgtype]); return 0; } if (datalen < 6) { if (DEBUG) l2tp_log (LOG_DEBUG, "%s: avp is too small. %d < 6\n", __FUNCTION__, datalen); wrong_length (c, "Hostname", 6, datalen, 1); return -EINVAL; } } #endif size = raw[0].s & 0x03FF; size -= sizeof (struct avp_hdr); if (size > MAXSTRLEN - 1) { if (DEBUG) l2tp_log (LOG_DEBUG, "%s: truncating reported hostname (size is %d)\n", __FUNCTION__, size); size = MAXSTRLEN - 1; } safe_copy (t->hostname, (char *) &raw[3].s, size); if (gconfig.debug_avp) { if (DEBUG) l2tp_log (LOG_DEBUG, "%s: peer reports hostname '%s'\n", __FUNCTION__, t->hostname); } return 0; } int dialing_number_avp (struct tunnel *t, struct call *c, void *data, int datalen) { /* * What is the peer's name? */ int size; struct unaligned_u16 *raw = data; #ifdef SANITY if (t->sanity) { switch (c->msgtype) { case ICRQ: break; default: if (DEBUG) l2tp_log (LOG_DEBUG, "%s: dialing number not appropriate for message %s. Ignoring.\n", __FUNCTION__, msgtypes[c->msgtype]); return 0; } if (datalen < 6) { if (DEBUG) l2tp_log (LOG_DEBUG, "%s: avp is too small. %d < 6\n", __FUNCTION__, datalen); wrong_length (c, "Dialing Number", 6, datalen, 1); return -EINVAL; } } #endif size = raw[0].s & 0x03FF; size -= sizeof (struct avp_hdr); if (size > MAXSTRLEN - 1) { if (DEBUG) l2tp_log (LOG_DEBUG, "%s: truncating reported dialing number (size is %d)\n", __FUNCTION__, size); size = MAXSTRLEN - 1; } safe_copy (t->call_head->dialing, (char *) &raw[3].s, size); if (gconfig.debug_avp) { if (DEBUG) l2tp_log (LOG_DEBUG, "%s: peer reports dialing number '%s'\n", __FUNCTION__, t->call_head->dialing); } return 0; } int dialed_number_avp (struct tunnel *t, struct call *c, void *data, int datalen) { /* * What is the peer's name? */ int size; struct unaligned_u16 *raw = data; #ifdef SANITY if (t->sanity) { switch (c->msgtype) { case OCRQ: case ICRQ: break; default: if (DEBUG) l2tp_log (LOG_DEBUG, "%s: dialed number not appropriate for message %s. Ignoring.\n", __FUNCTION__, msgtypes[c->msgtype]); return 0; } if (datalen < 6) { if (DEBUG) l2tp_log (LOG_DEBUG, "%s: avp is too small. %d < 6\n", __FUNCTION__, datalen); wrong_length (c, "Dialed Number", 6, datalen, 1); return -EINVAL; } } #endif size = raw[0].s & 0x03FF; size -= sizeof (struct avp_hdr); if (size > MAXSTRLEN - 1) { if (DEBUG) l2tp_log (LOG_DEBUG, "%s: truncating reported dialed number (size is %d)\n", __FUNCTION__, size); size = MAXSTRLEN - 1; } safe_copy (t->call_head->dialed, (char *) &raw[3].s, size); if (gconfig.debug_avp) { if (DEBUG) l2tp_log (LOG_DEBUG, "%s: peer reports dialed number '%s'\n", __FUNCTION__, t->call_head->dialed); } return 0; } int sub_address_avp (struct tunnel *t, struct call *c, void *data, int datalen) { /* * What is the peer's name? */ int size; struct unaligned_u16 *raw = data; #ifdef SANITY if (t->sanity) { switch (c->msgtype) { case OCRP: case ICRQ: break; default: if (DEBUG) l2tp_log (LOG_DEBUG, "%s: sub_address not appropriate for message %s. Ignoring.\n", __FUNCTION__, msgtypes[c->msgtype]); return 0; } if (datalen < 6) { if (DEBUG) l2tp_log (LOG_DEBUG, "%s: avp is too small. %d < 6\n", __FUNCTION__, datalen); wrong_length (c, "Sub-address", 6, datalen, 1); return -EINVAL; } } #endif size = raw[0].s & 0x03FF; size -= sizeof (struct avp_hdr); if (size > MAXSTRLEN - 1) { if (DEBUG) l2tp_log (LOG_DEBUG, "%s: truncating reported sub address (size is %d)\n", __FUNCTION__, size); size = MAXSTRLEN - 1; } safe_copy (t->call_head->subaddy, (char *) &raw[3].s, size); if (gconfig.debug_avp) { if (DEBUG) l2tp_log (LOG_DEBUG, "%s: peer reports subaddress '%s'\n", __FUNCTION__, t->call_head->subaddy); } return 0; } int vendor_avp (struct tunnel *t, struct call *c, void *data, int datalen) { /* * What vendor makes the other end? */ int size; struct unaligned_u16 *raw = data; #ifdef SANITY if (t->sanity) { switch (c->msgtype) { case SCCRP: case SCCRQ: break; default: if (DEBUG) l2tp_log (LOG_DEBUG, "%s: vendor not appropriate for message %s. Ignoring.\n", __FUNCTION__, msgtypes[c->msgtype]); return 0; } if (datalen < 6) { if (DEBUG) l2tp_log (LOG_DEBUG, "%s: avp is too small. %d < 6\n", __FUNCTION__, datalen); wrong_length (c, "Vendor", 6, datalen, 1); return -EINVAL; } } #endif size = raw[0].s & 0x03FF; size -= sizeof (struct avp_hdr); if (size > MAXSTRLEN - 1) { if (DEBUG) l2tp_log (LOG_DEBUG, "%s: truncating reported vendor (size is %d)\n", __FUNCTION__, size); size = MAXSTRLEN - 1; } safe_copy (t->vendor, (char *) &raw[3].s, size); if (gconfig.debug_avp) { if (DEBUG) l2tp_log (LOG_DEBUG, "%s: peer reports vendor '%s'\n", __FUNCTION__, t->vendor); } return 0; } int challenge_avp (struct tunnel *t, struct call *c, void *data, int datalen) { /* * We are sent a challenge */ struct unaligned_u16 *raw = data; int size; #ifdef SANITY if (t->sanity) { switch (c->msgtype) { case SCCRP: case SCCRQ: break; default: if (DEBUG) l2tp_log (LOG_DEBUG, "%s: challenge not appropriate for message %s. Ignoring.\n", __FUNCTION__, msgtypes[c->msgtype]); return 0; } if (datalen < 6) { if (DEBUG) l2tp_log (LOG_DEBUG, "%s: avp is too small. %d < 6\n", __FUNCTION__, datalen); wrong_length (c, "challenge", 6, datalen, 1); return -EINVAL; } } #endif /* size = raw[0].s & 0x0FFF; */ /* length field of AVP's is only 10 bits long, not 12 */ size = raw[0].s & 0x03FF; size -= sizeof (struct avp_hdr); /* if (size != MD_SIG_SIZE) { l2tp_log (LOG_DEBUG, "%s: Challenge is not the right length (%d != %d)\n", __FUNCTION__, size, MD_SIG_SIZE); return -EINVAL; } */ if (t->chal_us.challenge) free(t->chal_us.challenge); t->chal_us.challenge = malloc(size); if (t->chal_us.challenge == NULL) { return -ENOMEM; } bcopy (&raw[3].s, (t->chal_us.challenge), size); t->chal_us.chal_len = size; t->chal_us.state = STATE_CHALLENGED; if (gconfig.debug_avp) { l2tp_log (LOG_DEBUG, "%s: challenge avp found\n", __FUNCTION__); } return 0; } int chalresp_avp (struct tunnel *t, struct call *c, void *data, int datalen) { /* * We are sent a challenge */ struct unaligned_u16 *raw = data; int size; #ifdef SANITY if (t->sanity) { switch (c->msgtype) { case SCCRP: case SCCCN: break; default: if (DEBUG) l2tp_log (LOG_DEBUG, "%s: challenge response not appropriate for message %s. Ignoring.\n", __FUNCTION__, msgtypes[c->msgtype]); return 0; } if (datalen < 6) { if (DEBUG) l2tp_log (LOG_DEBUG, "%s: avp is too small. %d < 6\n", __FUNCTION__, datalen); wrong_length (c, "challenge", 6, datalen, 1); return -EINVAL; } } #endif size = raw[0].s & 0x03FF; size -= sizeof (struct avp_hdr); if (size != MD_SIG_SIZE) { l2tp_log (LOG_DEBUG, "%s: Challenge is not the right length (%d != %d)\n", __FUNCTION__, size, MD_SIG_SIZE); return -EINVAL; } bcopy (&raw[3].s, t->chal_them.reply, MD_SIG_SIZE); if (gconfig.debug_avp) { l2tp_log (LOG_DEBUG, "%s: Challenge reply found\n", __FUNCTION__); } return 0; } int assigned_tunnel_avp (struct tunnel *t, struct call *c, void *data, int datalen) { /* * What is their TID that we must use from now on? */ struct unaligned_u16 *raw = data; #ifdef SANITY if (t->sanity) { switch (c->msgtype) { case SCCRP: case SCCRQ: case StopCCN: break; default: if (DEBUG) l2tp_log (LOG_DEBUG, "%s: tunnel ID not appropriate for message %s. Ignoring.\n", __FUNCTION__, msgtypes[c->msgtype]); return 0; } if (datalen != 8) { if (DEBUG) l2tp_log (LOG_DEBUG, "%s: avp is wrong size. %d != 8\n", __FUNCTION__, datalen); wrong_length (c, "Assigned Tunnel ID", 8, datalen, 0); return -EINVAL; } } #endif if (c->msgtype == StopCCN) { t->qtid = ntohs (raw[3].s); } else { t->tid = ntohs (raw[3].s); } if (gconfig.debug_avp) { if (DEBUG) l2tp_log (LOG_DEBUG, "%s: using peer's tunnel %d\n", __FUNCTION__, ntohs (raw[3].s)); } return 0; } int assigned_call_avp (struct tunnel *t, struct call *c, void *data, int datalen) { /* * What is their CID that we must use from now on? */ struct unaligned_u16 *raw = data; #ifdef SANITY if (t->sanity) { switch (c->msgtype) { case CDN: case ICRP: case ICRQ: case OCRP: /* jz: deleting the debug message */ break; case OCRQ: default: if (DEBUG) l2tp_log (LOG_DEBUG, "%s: call ID not appropriate for message %s. Ignoring.\n", __FUNCTION__, msgtypes[c->msgtype]); return 0; } if (datalen != 8) { if (DEBUG) l2tp_log (LOG_DEBUG, "%s: avp is wrong size. %d != 8\n", __FUNCTION__, datalen); wrong_length (c, "Assigned Call ID", 8, datalen, 0); return -EINVAL; } } #endif if (c->msgtype == CDN) { c->qcid = ntohs (raw[3].s); } else if (c->msgtype == ICRQ) { t->call_head->cid = ntohs (raw[3].s); } else if (c->msgtype == ICRP) { c->cid = ntohs (raw[3].s); } else if (c->msgtype == OCRP) { /* jz: copy callid to c->cid */ c->cid = ntohs (raw[3].s); } else { l2tp_log (LOG_DEBUG, "%s: Dunno what to do when it's state %s!\n", __FUNCTION__, msgtypes[c->msgtype]); } if (gconfig.debug_avp) { if (DEBUG) l2tp_log (LOG_DEBUG, "%s: using peer's call %d\n", __FUNCTION__, ntohs (raw[3].s)); } return 0; } int packet_delay_avp (struct tunnel *t, struct call *c, void *data, int datalen) { /* * What is their CID that we must use from now on? */ struct unaligned_u16 *raw = data; #ifdef SANITY if (t->sanity) { switch (c->msgtype) { case ICRP: case OCRQ: case ICCN: case OCRP: case OCCN: break; default: if (DEBUG) l2tp_log (LOG_DEBUG, "%s: packet delay not appropriate for message %s. Ignoring.\n", __FUNCTION__, msgtypes[c->msgtype]); return 0; } if (datalen != 8) { if (DEBUG) l2tp_log (LOG_DEBUG, "%s: avp is wrong size. %d != 8\n", __FUNCTION__, datalen); wrong_length (c, "Assigned Call ID", 8, datalen, 0); return -EINVAL; } } #endif c->ppd = ntohs (raw[3].s); if (gconfig.debug_avp) { if (DEBUG) l2tp_log (LOG_DEBUG, "%s: peer's delay is %d 1/10's of a second\n", __FUNCTION__, ntohs (raw[3].s)); } return 0; } int call_serno_avp (struct tunnel *t, struct call *c, void *data, int datalen) { /* * What is the serial number of the call? */ struct unaligned_u16 *raw = data; #ifdef SANITY if (t->sanity) { switch (c->msgtype) { case ICRQ: case OCRQ: break; default: if (DEBUG) l2tp_log (LOG_DEBUG, "%s: call ID not appropriate for message %s. Ignoring.\n", __FUNCTION__, msgtypes[c->msgtype]); return 0; } if (datalen != 10) { #ifdef STRICT if (DEBUG) l2tp_log (LOG_DEBUG, "%s: avp is wrong size. %d != 10\n", __FUNCTION__, datalen); wrong_length (c, "Serial Number", 10, datalen, 0); return -EINVAL; #else l2tp_log (LOG_DEBUG, "%s: peer is using old style serial number. Will be invalid.\n", __FUNCTION__); #endif } } #endif t->call_head->serno = (((unsigned int) ntohs (raw[3].s)) << 16) | ((unsigned int) ntohs (raw[4].s)); if (gconfig.debug_avp) { if (DEBUG) l2tp_log (LOG_DEBUG, "%s: serial number is %d\n", __FUNCTION__, t->call_head->serno); } return 0; } int rx_speed_avp (struct tunnel *t, struct call *c, void *data, int datalen) { /* * What is the received baud rate of the call? */ struct unaligned_u16 *raw = data; #ifdef SANITY if (t->sanity) { switch (c->msgtype) { case ICCN: case OCCN: case OCRP: break; default: if (DEBUG) l2tp_log (LOG_DEBUG, "%s: rx connect speed not appropriate for message %s. Ignoring.\n", __FUNCTION__, msgtypes[c->msgtype]); return 0; } if (datalen != 10) { if (DEBUG) l2tp_log (LOG_DEBUG, "%s: avp is wrong size. %d != 10\n", __FUNCTION__, datalen); wrong_length (c, "Connect Speed (RX)", 10, datalen, 0); return -EINVAL; } } #endif c->rxspeed = (((unsigned int) ntohs (raw[3].s)) << 16) | ((unsigned int) ntohs (raw[4].s)); if (gconfig.debug_avp) { if (DEBUG) l2tp_log (LOG_DEBUG, "%s: receive baud rate is %d\n", __FUNCTION__, c->rxspeed); } return 0; } int tx_speed_avp (struct tunnel *t, struct call *c, void *data, int datalen) { /* * What is the transmit baud rate of the call? */ struct unaligned_u16 *raw = data; #ifdef SANITY if (t->sanity) { switch (c->msgtype) { case ICCN: case OCCN: case OCRP: break; default: if (DEBUG) l2tp_log (LOG_DEBUG, "%s: tx connect speed not appropriate for message %s. Ignoring.\n", __FUNCTION__, msgtypes[c->msgtype]); return 0; } if (datalen != 10) { if (DEBUG) l2tp_log (LOG_DEBUG, "%s: avp is wrong size. %d != 10\n", __FUNCTION__, datalen); wrong_length (c, "Connect Speed (tx)", 10, datalen, 0); return -EINVAL; } } #endif c->txspeed = (((unsigned int) ntohs (raw[3].s)) << 16) | ((unsigned int) ntohs (raw[4].s)); if (gconfig.debug_avp) { if (DEBUG) l2tp_log (LOG_DEBUG, "%s: transmit baud rate is %d\n", __FUNCTION__, c->txspeed); } return 0; } int call_physchan_avp (struct tunnel *t, struct call *c, void *data, int datalen) { /* * What is the physical channel? */ struct unaligned_u16 *raw = data; #ifdef SANITY if (t->sanity) { switch (c->msgtype) { case ICRQ: case OCRQ: case OCRP: case OCCN: break; default: if (DEBUG) l2tp_log (LOG_DEBUG, "%s: physical channel not appropriate for message %s. Ignoring.\n", __FUNCTION__, msgtypes[c->msgtype]); return 0; } if (datalen != 10) { if (DEBUG) l2tp_log (LOG_DEBUG, "%s: avp is wrong size. %d != 10\n", __FUNCTION__, datalen); wrong_length (c, "Physical Channel", 10, datalen, 0); return -EINVAL; } } #endif t->call_head->physchan = (((unsigned int) ntohs (raw[3].s)) << 16) | ((unsigned int) ntohs (raw[4].s)); if (gconfig.debug_avp) { if (DEBUG) l2tp_log (LOG_DEBUG, "%s: physical channel is %d\n", __FUNCTION__, t->call_head->physchan); } return 0; } int receive_window_size_avp (struct tunnel *t, struct call *c, void *data, int datalen) { /* * What is their RWS? */ struct unaligned_u16 *raw = data; #ifdef SANITY if (t->sanity) { switch (c->msgtype) { case SCCRP: case SCCRQ: case OCRP: /* jz */ case OCCN: /* jz */ case StopCCN: /* case ICRP: case ICCN: */ break; default: if (DEBUG) l2tp_log (LOG_DEBUG, "%s: RWS not appropriate for message %s. Ignoring.\n", __FUNCTION__, msgtypes[c->msgtype]); return 0; } if (datalen != 8) { if (DEBUG) l2tp_log (LOG_DEBUG, "%s: avp is wrong size. %d != 8\n", __FUNCTION__, datalen); wrong_length (c, "Receive Window Size", 8, datalen, 0); return -EINVAL; } } #endif t->rws = ntohs (raw[3].s); /* if (c->rws >= 0) c->fbit = FBIT; */ if (gconfig.debug_avp) { if (DEBUG) l2tp_log (LOG_DEBUG, "%s: peer wants RWS of %d. Will use flow control.\n", __FUNCTION__, t->rws); } return 0; } int handle_avps (struct buffer *buf, struct tunnel *t, struct call *c) { /* * buf's start should point to the beginning of a packet. We assume it's * a valid packet and has had check_control done to it, so no error * checking is done at this point. */ /* TODO: Refactor function to not use "goto next" */ struct avp_hdr *avp; int len = buf->len - sizeof (struct control_hdr); int firstavp = -1; int hidlen = 0; char *data = buf->start + sizeof (struct control_hdr); avp = (struct avp_hdr *) data; /* I had to comment out the following since Valgrind tells me it leaks like my bathroom faucet if (gconfig.debug_avp) l2tp_log (LOG_DEBUG, "%s: handling avp's for tunnel %d, call %d\n", __FUNCTION__, t->ourtid, c->ourcid); */ while (len > 0) { hidlen = 0; /* Go ahead and byte-swap the header */ swaps (avp, sizeof (struct avp_hdr)); if (avp->attr > AVP_MAX) { if (AMBIT (avp->length)) { l2tp_log (LOG_WARNING, "%s: don't know how to handle mandatory attribute %d. Closing %s.\n", __FUNCTION__, avp->attr, (c != t->self) ? "call" : "tunnel"); set_error (c, VENDOR_ERROR, "mandatory attribute %d cannot be handled", avp->attr); c->needclose = -1; return -EINVAL; } else { if (DEBUG) l2tp_log (LOG_WARNING, "%s: don't know how to handle attribute %d.\n", __FUNCTION__, avp->attr); goto next; } } if (ALENGTH (avp->length) > len) { l2tp_log (LOG_WARNING, "%s: AVP received with length > remaining packet length!\n", __FUNCTION__); set_error (c, ERROR_LENGTH, "Invalid AVP length"); c->needclose = -1; return -EINVAL; } if (avp->attr && firstavp) { l2tp_log (LOG_WARNING, "%s: First AVP was not message type.\n", __FUNCTION__); set_error (c, VENDOR_ERROR, "First AVP must be message type"); c->needclose = -1; return -EINVAL; } if (ALENGTH (avp->length) < sizeof (struct avp_hdr)) { l2tp_log (LOG_WARNING, "%s: AVP with too small of size (%d).\n", __FUNCTION__, ALENGTH (avp->length)); set_error (c, ERROR_LENGTH, "AVP too small"); c->needclose = -1; return -EINVAL; } if (AZBITS (avp->length)) { l2tp_log (LOG_WARNING, "%s: %sAVP has reserved bits set.\n", __FUNCTION__, AMBIT (avp->length) ? "Mandatory " : ""); if (AMBIT (avp->length)) { set_error (c, ERROR_RESERVED, "reserved bits set in AVP"); c->needclose = -1; return -EINVAL; } goto next; } if (AHBIT (avp->length)) { #ifdef DEBUG_HIDDEN l2tp_log (LOG_DEBUG, "%s: Hidden bit set on AVP.\n", __FUNCTION__); #endif /* We want to rewrite the AVP as an unhidden AVP and then pass it along as normal. Remember how long the AVP was in the first place though! */ hidlen = avp->length; if (decrypt_avp (data, t)) { if (gconfig.debug_avp) l2tp_log (LOG_WARNING, "%s: Unable to handle hidden %sAVP\n:", __FUNCTION__, (AMBIT (avp->length) ? "mandatory " : "")); if (AMBIT (avp->length)) { set_error (c, VENDOR_ERROR, "Invalid Hidden AVP"); c->needclose = -1; return -EINVAL; } goto next; }; len -= 2; hidlen -= 2; data += 2; avp = (struct avp_hdr *) data; /* Now we should look like a normal AVP */ } else hidlen = 0; if (!avps[avp->attr].handler) { if (AMBIT (avp->length)) { l2tp_log (LOG_WARNING, "%s: No handler for mandatory attribute %d (%s). Closing %s.\n", __FUNCTION__, avp->attr, avps[avp->attr].description, (c != t->self) ? "call" : "tunnel"); set_error (c, VENDOR_ERROR, "No handler for attr %d (%s)\n", avp->attr, avps[avp->attr].description); return -EINVAL; } else { if (DEBUG) l2tp_log (LOG_WARNING, "%s: no handler for attribute %d (%s).\n", __FUNCTION__, avp->attr, avps[avp->attr].description); goto next; } } if (avps[avp->attr].handler (t, c, avp, ALENGTH (avp->length))) { if (AMBIT (avp->length)) { l2tp_log (LOG_WARNING, "%s: Bad exit status handling attribute %d (%s) on mandatory packet.\n", __FUNCTION__, avp->attr, avps[avp->attr].description); c->needclose = -1; return -EINVAL; } else { if (DEBUG) l2tp_log (LOG_DEBUG, "%s: Bad exit status handling attribute %d (%s).\n", __FUNCTION__, avp->attr, avps[avp->attr].description); } } next: if (hidlen && ALENGTH(hidlen)) { /* Skip over the complete length of the hidden AVP */ len -= ALENGTH (hidlen); data += ALENGTH (hidlen); } else if (ALENGTH(avp->length)) { len -= ALENGTH (avp->length); data += ALENGTH (avp->length); /* Next AVP, please */ } else { l2tp_log (LOG_WARNING, "%s: broken avp->length zero %d\n", __FUNCTION__,avp->length); break; } avp = (struct avp_hdr *) data; firstavp = 0; } if (len != 0) { l2tp_log (LOG_WARNING, "%s: negative overall packet length\n", __FUNCTION__); return -EINVAL; } return 0; } xl2tpd-1.3.16/avp.h000066400000000000000000000136021374460464600137760ustar00rootroot00000000000000/* * Layer Two Tunnelling Protocol Daemon * Copyright (C) 1998 Adtran, Inc. * Copyright (C) 2002 Jeff McAdams * * Mark Spencer * * This software is distributed under the terms * of the GPL, which you should have received * along with this source. * * Attribute Value Pair structures and * definitions */ #include "common.h" struct avp_hdr { _u16 length; _u16 vendorid; _u16 attr; } __attribute__((packed)); struct avp { int num; /* Number of AVP */ int m; /* Set M? */ int (*handler) (struct tunnel *, struct call *, void *, int); /* This should handle the AVP taking a tunnel, call, the data, and the length of the AVP as parameters. Should return 0 upon success */ char *description; /* A name, for debugging */ }; extern int handle_avps (struct buffer *buf, struct tunnel *t, struct call *c); extern char *msgtypes[]; #define VENDOR_ID 0 /* We don't have any extensions so we shoouldn't have to worry about this */ /* * Macros to extract information from length field of AVP */ #define AMBIT(len) (len & 0x8000) /* Mandatory bit: If this is set on an unknown AVP, we MUST terminate */ #define AHBIT(len) (len & 0x4000) /* Hidden bit: Specifies information hiding */ #define AZBITS(len) (len & 0x3C00) /* Reserved bits: We must drop anything with any of these set. */ #define ALENGTH(len) (len & 0x03FF) /* Length: Lenth of AVP */ #define MAXAVPSIZE 1023 #define MAXTIME 300 /* time to wait before checking Ns and Nr, in ms */ #define MBIT 0x8000 /* for setting */ #define HBIT 0x4000 /* Set on hidden avp's */ #define ASYNC_FRAMING 2 #define SYNC_FRAMING 1 #define ANALOG_BEARER 2 #define DIGITAL_BEARER 1 #define VENDOR_ERROR 6 #define ERROR_RESERVED 3 #define ERROR_LENGTH 2 #define ERROR_NOTEXIST 1 #define ERROR_NORES 4 #define ERROR_INVALID 6 #define RESULT_CLEAR 1 #define RESULT_ERROR 2 #define RESULT_EXISTS 3 extern void encrypt_avp (struct buffer *, _u16, struct tunnel *); extern int decrypt_avp (char *, struct tunnel *); extern int message_type_avp (struct tunnel *, struct call *, void *, int); extern int protocol_version_avp (struct tunnel *, struct call *, void *, int); extern int framing_caps_avp (struct tunnel *, struct call *, void *, int); extern int bearer_caps_avp (struct tunnel *, struct call *, void *, int); extern int firmware_rev_avp (struct tunnel *, struct call *, void *, int); extern int hostname_avp (struct tunnel *, struct call *, void *, int); extern int vendor_avp (struct tunnel *, struct call *, void *, int); extern int assigned_tunnel_avp (struct tunnel *, struct call *, void *, int); extern int receive_window_size_avp (struct tunnel *, struct call *, void *, int); extern int result_code_avp (struct tunnel *, struct call *, void *, int); extern int assigned_call_avp (struct tunnel *, struct call *, void *, int); extern int call_serno_avp (struct tunnel *, struct call *, void *, int); extern int bearer_type_avp (struct tunnel *, struct call *, void *, int); extern int call_physchan_avp (struct tunnel *, struct call *, void *, int); extern int dialed_number_avp (struct tunnel *, struct call *, void *, int); extern int dialing_number_avp (struct tunnel *, struct call *, void *, int); extern int sub_address_avp (struct tunnel *, struct call *, void *, int); extern int frame_type_avp (struct tunnel *, struct call *, void *, int); extern int rx_speed_avp (struct tunnel *, struct call *, void *, int); extern int tx_speed_avp (struct tunnel *, struct call *, void *, int); extern int packet_delay_avp (struct tunnel *, struct call *, void *, int); extern int ignore_avp (struct tunnel *, struct call *, void *, int); extern int seq_reqd_avp (struct tunnel *, struct call *, void *, int); extern int challenge_avp (struct tunnel *, struct call *, void *, int); extern int chalresp_avp (struct tunnel *, struct call *, void *, int); extern int rand_vector_avp (struct tunnel *, struct call *, void *, int); extern int add_challenge_avp (struct buffer *, unsigned char *, int); extern int add_avp_rws (struct buffer *, _u16); extern int add_tunnelid_avp (struct buffer *, _u16); extern int add_vendor_avp (struct buffer *); extern int add_hostname_avp (struct buffer *, const char *); extern int add_firmware_avp (struct buffer *); extern int add_bearer_caps_avp (struct buffer *buf, _u16 caps); extern int add_frame_caps_avp (struct buffer *buf, _u16 caps); extern int add_protocol_avp (struct buffer *buf); extern int add_message_type_avp (struct buffer *buf, _u16 type); extern int add_result_code_avp (struct buffer *buf, _u16, _u16, char *, int); extern int add_bearer_avp (struct buffer *, int); extern int add_frame_avp (struct buffer *, int); extern int add_rxspeed_avp (struct buffer *, int); extern int add_txspeed_avp (struct buffer *, int); extern int add_serno_avp (struct buffer *, unsigned int); #ifdef TEST_HIDDEN extern int add_callid_avp (struct buffer *, _u16, struct tunnel *); #else extern int add_callid_avp (struct buffer *, _u16); #endif extern int add_ppd_avp (struct buffer *, _u16); extern int add_seqreqd_avp (struct buffer *); extern int add_chalresp_avp (struct buffer *, unsigned char *, int); extern int add_randvect_avp (struct buffer *, unsigned char *, int); extern int add_minbps_avp (struct buffer *buf, int speed); /* jz: needed for outgoing call */ extern int add_maxbps_avp (struct buffer *buf, int speed); /* jz: needed for outgoing call */ extern int add_number_avp (struct buffer *buf, char *no); /* jz: needed for outgoing call */ xl2tpd-1.3.16/avpsend.c000066400000000000000000000202261374460464600146430ustar00rootroot00000000000000/* * Layer Two Tunnelling Protocol Daemon * Copyright (C) 1998 Adtran, Inc. * Copyright (C) 2002 Jeff McAdams * * Mark Spencer * * This software is distributed under the terms * of the GPL, which you should have received * along with this source. * * Attribute Value Pair creating routines */ #include #include #include #include #include "l2tp.h" struct half_words { _u16 s0; _u16 s1; _u16 s2; _u16 s3; } __attribute__ ((packed)); void add_nonmandatory_header(struct buffer *buf, _u16 length, _u16 type) { struct avp_hdr *avp = (struct avp_hdr *) (buf->start + buf->len); avp->length = htons (length); avp->vendorid = htons (VENDOR_ID); avp->attr = htons (type); } void add_header(struct buffer *buf, _u16 length, _u16 type) { add_nonmandatory_header(buf, length|MBIT, type); } /* * These routines should add AVP's to a buffer * to be sent */ /* FIXME: If SANITY is on, we should check for buffer overruns */ int add_message_type_avp (struct buffer *buf, _u16 type) { struct half_words *ptr = (struct half_words *) (buf->start + buf->len + sizeof(struct avp_hdr)); add_header(buf, 0x8, 0); ptr->s0 = htons(type); buf->len += 0x8; return 0; } int add_protocol_avp (struct buffer *buf) { struct half_words *ptr = (struct half_words *) (buf->start + buf->len + sizeof(struct avp_hdr)); add_header(buf, 0x8, 0x2); /* Length and M bit */ ptr->s0 = htons (OUR_L2TP_VERSION); buf->len += 0x8; return 0; } int add_frame_caps_avp (struct buffer *buf, _u16 caps) { struct half_words *ptr = (struct half_words *) (buf->start + buf->len + sizeof(struct avp_hdr)); add_header(buf, 0xA, 0x3); ptr->s0 = 0; ptr->s1 = htons (caps); buf->len += 0xA; return 0; } int add_bearer_caps_avp (struct buffer *buf, _u16 caps) { struct half_words *ptr = (struct half_words *) (buf->start + buf->len + sizeof(struct avp_hdr)); add_header(buf, 0xA, 0x4); ptr->s0 = 0; ptr->s1 = htons (caps); buf->len += 0xA; return 0; } /* FIXME: I need to send tie breaker AVP's */ int add_firmware_avp (struct buffer *buf) { struct half_words *ptr = (struct half_words *) (buf->start + buf->len + sizeof(struct avp_hdr)); add_nonmandatory_header(buf, 0x8, 0x6); ptr->s0 = htons (FIRMWARE_REV); buf->len += 0x8; return 0; } int add_hostname_avp (struct buffer *buf, const char *hostname) { size_t namelen = strlen(hostname); if (namelen > MAXAVPSIZE - 6) { namelen = MAXAVPSIZE - 6; } add_header(buf, 0x6 + namelen, 0x7); strncpy ((char *) (buf->start + buf->len + sizeof(struct avp_hdr)), hostname, namelen); buf->len += 0x6 + namelen; return 0; } int add_vendor_avp (struct buffer *buf) { add_nonmandatory_header(buf, 0x6 + strlen (VENDOR_NAME), 0x8); strcpy ((char *) (buf->start + buf->len + sizeof(struct avp_hdr)), VENDOR_NAME); buf->len += 0x6 + strlen (VENDOR_NAME); return 0; } int add_tunnelid_avp (struct buffer *buf, _u16 tid) { struct half_words *ptr = (struct half_words *) (buf->start + buf->len + sizeof(struct avp_hdr)); add_header(buf, 0x8, 0x9); ptr->s0 = htons (tid); buf->len += 0x8; return 0; } int add_avp_rws (struct buffer *buf, _u16 rws) { struct half_words *ptr = (struct half_words *) (buf->start + buf->len + sizeof(struct avp_hdr)); add_header(buf, 0x8, 0xA); ptr->s0 = htons (rws); buf->len += 0x8; return 0; } int add_challenge_avp (struct buffer *buf, unsigned char *c, int len) { add_header(buf, (0x6 + len), 0xB); memcpy((char *) (buf->start + buf->len + sizeof(struct avp_hdr)), c, len); buf->len += 0x6 + len; return 0; } int add_chalresp_avp (struct buffer *buf, unsigned char *c, int len) { add_header(buf, (0x6 + len), 0xD); memcpy((char *) (buf->start + buf->len + sizeof(struct avp_hdr)), c, len); buf->len += 0x6 + len; return 0; } int add_randvect_avp (struct buffer *buf, unsigned char *c, int len) { add_header(buf, (0x6 + len), 0x24); memcpy((char *) (buf->start + buf->len + sizeof(struct avp_hdr)), c, len); buf->len += 0x6 + len; return 0; } int add_result_code_avp (struct buffer *buf, _u16 result, _u16 error, char *msg, int len) { struct half_words *ptr = (struct half_words *) (buf->start + buf->len + sizeof(struct avp_hdr)); add_header(buf, (0xA + len), 0x1); ptr->s0 = htons (result); ptr->s1 = htons (error); memcpy ((char *) &ptr->s2, msg, len); buf->len += 0xA + len; return 0; } #ifdef TEST_HIDDEN int add_callid_avp (struct buffer *buf, _u16 callid, struct tunnel *t) { #else int add_callid_avp (struct buffer *buf, _u16 callid) { #endif struct half_words *ptr = (struct half_words *) (buf->start + buf->len + sizeof(struct avp_hdr)); #ifdef TEST_HIDDEN if (t->hbit) raw++; #endif add_header(buf, 0x8, 0xE); ptr->s0 = htons (callid); buf->len += 0x8; #ifdef TEST_HIDDEN if (t->hbit) encrypt_avp (buf, 8, t); #endif return 0; } int add_serno_avp (struct buffer *buf, unsigned int serno) { struct half_words *ptr = (struct half_words *) (buf->start + buf->len + sizeof(struct avp_hdr)); add_header(buf, 0xA, 0xF); ptr->s0 = htons ((serno >> 16) & 0xFFFF); ptr->s1 = htons (serno & 0xFFFF); buf->len += 0xA; return 0; } int add_bearer_avp (struct buffer *buf, int bearer) { struct half_words *ptr = (struct half_words *) (buf->start + buf->len + sizeof(struct avp_hdr)); add_header(buf, 0xA, 0x12); ptr->s0 = htons ((bearer >> 16) & 0xFFFF); ptr->s1 = htons (bearer & 0xFFFF); buf->len += 0xA; return 0; } int add_frame_avp (struct buffer *buf, int frame) { struct half_words *ptr = (struct half_words *) (buf->start + buf->len + sizeof(struct avp_hdr)); add_header(buf, 0xA, 0x13); ptr->s0 = htons ((frame >> 16) & 0xFFFF); ptr->s1 = htons (frame & 0xFFFF); buf->len += 0xA; return 0; } int add_txspeed_avp (struct buffer *buf, int speed) { struct half_words *ptr = (struct half_words *) (buf->start + buf->len + sizeof(struct avp_hdr)); add_header(buf, 0xA, 0x18); ptr->s0 = htons ((speed >> 16) & 0xFFFF); ptr->s1 = htons (speed & 0xFFFF); buf->len += 0xA; return 0; } int add_rxspeed_avp (struct buffer *buf, int speed) { struct half_words *ptr = (struct half_words *) (buf->start + buf->len + sizeof(struct avp_hdr)); add_nonmandatory_header(buf, 0xA, 0x26); ptr->s0 = htons ((speed >> 16) & 0xFFFF); ptr->s1 = htons (speed & 0xFFFF); buf->len += 0xA; return 0; } int add_physchan_avp (struct buffer *buf, unsigned int physchan) { struct half_words *ptr = (struct half_words *) (buf->start + buf->len + sizeof(struct avp_hdr)); add_nonmandatory_header(buf, 0xA, 0x19); ptr->s0 = htons ((physchan >> 16) & 0xFFFF); ptr->s1 = htons (physchan & 0xFFFF); buf->len += 0xA; return 0; } int add_ppd_avp (struct buffer *buf, _u16 ppd) { struct half_words *ptr = (struct half_words *) (buf->start + buf->len + sizeof(struct avp_hdr)); add_header(buf, 0x8, 0x14); ptr->s0 = htons (ppd); buf->len += 0x8; return 0; } int add_seqreqd_avp (struct buffer *buf) { add_header(buf, 0x6, 0x27); buf->len += 0x6; return 0; } /* jz: options dor the outgoing call */ /* jz: Minimum BPS - 16 */ int add_minbps_avp (struct buffer *buf, int speed) { struct half_words *ptr = (struct half_words *) (buf->start + buf->len + sizeof(struct avp_hdr)); add_header(buf, 0xA, 0x10); ptr->s0 = htons ((speed >> 16) & 0xFFFF); ptr->s1 = htons (speed & 0xFFFF); buf->len += 0xA; return 0; } /* jz: Maximum BPS - 17 */ int add_maxbps_avp (struct buffer *buf, int speed) { struct half_words *ptr = (struct half_words *) (buf->start + buf->len + sizeof(struct avp_hdr)); add_header(buf, 0xA, 0x11); ptr->s0 = htons ((speed >> 16) & 0xFFFF); ptr->s1 = htons (speed & 0xFFFF); buf->len += 0xA; return 0; } /* jz: Dialed Number 21 */ int add_number_avp (struct buffer *buf, char *no) { add_header(buf, (0x6 + strlen (no)), 0x15); strncpy ((char *) (buf->start + buf->len + sizeof(struct avp_hdr)), no, strlen (no)); buf->len += 0x6 + strlen (no); return 0; } xl2tpd-1.3.16/call.c000066400000000000000000000452521374460464600141240ustar00rootroot00000000000000/* * Layer Two Tunnelling Protocol Daemon * Copyright (C) 1998 Adtran, Inc. * Copyright (C) 2002 Jeff McAdams * * Mark Spencer * * This software is distributed under the terms * of the GPL, which you should have received * along with this source. * * Handle a call as a separate thread */ #include #include #include #include #include #include #include #include #include #include #include #include #include "l2tp.h" #include "ipsecmast.h" struct buffer *new_payload (struct sockaddr_in peer) { struct buffer *tmp = new_buf (MAX_RECV_SIZE); if (!tmp) return NULL; tmp->peer = peer; tmp->start += sizeof (struct payload_hdr); tmp->len = 0; return tmp; } inline void recycle_payload (struct buffer *buf, struct sockaddr_in peer) { buf->start = buf->rstart + sizeof (struct payload_hdr); buf->len = 0; buf->peer = peer; } void add_payload_hdr (struct tunnel *t, struct call *c, struct buffer *buf) { struct payload_hdr *p; buf->start -= sizeof (struct payload_hdr); buf->len += sizeof (struct payload_hdr); /* Account for no offset */ buf->start += 2; buf->len -= 2; if (!c->fbit && !c->ourfbit) { /* Forget about Ns and Nr fields then */ buf->start += 4; buf->len -= 4; } if (!c->lbit) { /* Forget about specifying the length */ buf->start += 2; buf->len -= 2; } p = (struct payload_hdr *) buf->start; /* p->ver = htons(c->lbit | c->rbit | c->fbit | c->ourfbit | VER_L2TP); */ p->ver = htons (c->lbit | c->fbit | c->ourfbit | VER_L2TP); if (c->lbit) { p->length = htons ((_u16) buf->len); } else { p = (struct payload_hdr *) (((char *) p) - 2); } p->tid = htons (t->tid); p->cid = htons (c->cid); if (c->fbit || c->ourfbit) { p->Ns = htons (c->data_seq_num); p->Nr = htons (c->data_rec_seq_num); } c->data_seq_num++; /* c->rbit=0; */ } int read_packet (struct call *c) { struct buffer *buf = c->ppp_buf; unsigned char ch; unsigned char escape = 0; unsigned char *p; int res; int errors = 0; p = buf->start + buf->len; while (1) { if (c->rbuf_pos >= c->rbuf_max) { c->rbuf_max = read(c->fd, c->rbuf, sizeof (c->rbuf)); res = c->rbuf_max; c->rbuf_pos = 0; } else { res = 1; } ch = c->rbuf[c->rbuf_pos++]; /* if there was a short read, then see what is about */ if (res < 1) { if (res == 0) { /* * Hmm.. Nothing to read. It happens */ return 0; } else if ((errno == EIO) || (errno == EINTR) || (errno == EAGAIN)) { /* * Oops, we were interrupted! * Or, we ran out of data too soon * anyway, we discarded whatever it is we * have */ return 0; } errors++; l2tp_log (LOG_DEBUG, "%s: Error %d (%s)\n", __FUNCTION__, errno, strerror (errno)); if (errors > 10) { l2tp_log (LOG_DEBUG, "%s: Too many errors. Declaring call dead.\n", __FUNCTION__); c->rbuf_pos = 0; c->rbuf_max = 0; return -errno; } continue; } switch (ch) { case PPP_FLAG: if (escape) { l2tp_log (LOG_DEBUG, "%s: got an escaped PPP_FLAG\n", __FUNCTION__); c->rbuf_pos = 0; c->rbuf_max = 0; return -EINVAL; } if (buf->len >= 2) { /* must be the end, drop the FCS */ buf->len -= 2; } else if (buf->len == 1) { /* Do nothing, just return the single character*/ } else { /* if the buffer is empty, then we have the beginning * of a packet, not the end */ break; } /* return what we have now */ return buf->len; case PPP_ESCAPE: escape = PPP_TRANS; break; default: ch ^= escape; escape = 0; if (buf->len < buf->maxlen) { *p = ch; p++; buf->len++; break; } l2tp_log (LOG_WARNING, "%s: read overrun\n", __FUNCTION__); c->rbuf_pos = 0; c->rbuf_max = 0; return -EINVAL; } } /* I should never get here */ l2tp_log (LOG_WARNING, "%s: You should not see this message. If you do, please enter " "a bug report at http://lists.xelerance.com/mailman/listinfo/xl2tpd", __FUNCTION__); return -EINVAL; } void call_close (struct call *c) { struct buffer *buf; struct schedule_entry *se, *ose; struct call *tmp, *tmp2; if (!c || !c->container) { l2tp_log (LOG_DEBUG, "%s: called on null call or containerless call\n", __FUNCTION__); return; } if (c == c->container->self) { /* * We're actually closing the * entire tunnel */ /* First de-schedule any remaining packet transmissions for this tunnel. That means Hello's and any remaining packets scheduled for transmission. This is a very nasty little piece of code here. */ se = events; ose = NULL; while (se) { if ((((struct buffer *) se->data)->tunnel == c->container) || ((struct tunnel *) se->data == c->container)) { #ifdef DEBUG_CLOSE l2tp_log (LOG_DEBUG, "%s: Descheduling event\n", __FUNCTION__); #endif if (ose) { ose->next = se->next; if ((struct tunnel *) se->data != c->container) toss ((struct buffer *) (se->data)); free (se); se = ose->next; } else { events = se->next; if ((struct tunnel *) se->data != c->container) toss ((struct buffer *) (se->data)); free (se); se = events; } } else { ose = se; se = se->next; } } if (c->closing) { /* Really close this tunnel, as our StopCCN has been ACK'd */ #ifdef DEBUG_CLOSE l2tp_log (LOG_DEBUG, "%s: Actually closing tunnel %d\n", __FUNCTION__, c->container->ourtid); #endif destroy_tunnel (c->container); return; } /* * We need to close, but need to provide reliable delivery * of the final StopCCN. We record our state to know when * we have actually received an ACK on our StopCCN */ c->closeSs = c->container->control_seq_num; buf = new_outgoing (c->container); add_message_type_avp (buf, StopCCN); if (c->container->hbit) { mk_challenge (c->container->chal_them.vector, VECTOR_SIZE); add_randvect_avp (buf, c->container->chal_them.vector, VECTOR_SIZE); } add_tunnelid_avp (buf, c->container->ourtid); if (c->result < 0) c->result = RESULT_CLEAR; if (c->error < 0) c->error = 0; add_result_code_avp (buf, c->result, c->error, c->errormsg, strlen (c->errormsg)); add_control_hdr (c->container, c, buf); if (gconfig.packet_dump) do_packet_dump (buf); #ifdef DEBUG_CLOSE l2tp_log (LOG_DEBUG, "%s: enqueing close message for tunnel\n", __FUNCTION__); #endif control_xmit (buf); /* * We also need to stop all traffic on any calls contained * within us. */ tmp = c->container->call_head; while (tmp) { tmp2 = tmp->next; tmp->needclose = 0; tmp->closing = -1; call_close (tmp); tmp = tmp2; } l2tp_log (LOG_INFO, "Connection %d closed to %s, port %d (%s)\n", c->container->tid, IPADDY (c->container->peer.sin_addr), ntohs (c->container->peer.sin_port), c->errormsg); } else { /* * Just close a call */ if (c->zlb_xmit) deschedule (c->zlb_xmit); /* if (c->dethrottle) deschedule(c->dethrottle); */ if (c->closing) { #ifdef DEBUG_CLOSE l2tp_log (LOG_DEBUG, "%s: Actually closing call %d\n", __FUNCTION__, c->ourcid); #endif destroy_call (c); return; } c->closeSs = c->container->control_seq_num; buf = new_outgoing (c->container); add_message_type_avp (buf, CDN); if (c->container->hbit) { mk_challenge (c->container->chal_them.vector, VECTOR_SIZE); add_randvect_avp (buf, c->container->chal_them.vector, VECTOR_SIZE); } if (c->result < 0) c->result = RESULT_CLEAR; if (c->error < 0) c->error = 0; add_result_code_avp (buf, c->result, c->error, c->errormsg, strlen (c->errormsg)); #ifdef TEST_HIDDEN add_callid_avp (buf, c->ourcid, c->container); #else add_callid_avp (buf, c->ourcid); #endif add_control_hdr (c->container, c, buf); if (gconfig.packet_dump) do_packet_dump (buf); #ifdef DEBUG_CLOSE l2tp_log (LOG_DEBUG, "%s: enqueuing close message for call %d\n", __FUNCTION__, c->ourcid); #endif control_xmit (buf); l2tp_log (LOG_INFO, "%s: Call %d to %s disconnected\n", __FUNCTION__, c->ourcid, IPADDY (c->container->peer.sin_addr)); } /* * Note that we're in the process of closing now */ c->closing = -1; } void destroy_call (struct call *c) { /* * Here, we unconditionally destroy a call. */ struct call *p; struct timeval tv; pid_t pid; /* * Close the tty */ if (c->fd > 0) { close (c->fd); c->fd = -1; } /* if (c->dethrottle) deschedule(c->dethrottle); */ if (c->zlb_xmit) deschedule (c->zlb_xmit); toss(c->ppp_buf); #ifdef IP_ALLOCATION if (c->addr) unreserve_addr (c->addr); if (c->lns && c->lns->localrange) unreserve_addr (c->lns->localaddr); #endif /* * Kill off PPPD and wait for it to * return to us. This should only be called * in rare cases if PPPD hasn't already died * voluntarily */ pid = c->pppd; if (pid > 0) { /* Set c->pppd to zero to prevent recursion with child_handler */ c->pppd = 0; /* * There is a bug in some PPPD versions where sending a SIGTERM * does not actually seem to kill PPPD, and xl2tpd waits indefinately * using waitpid, not accepting any new connections either. Therefor * we now use some more force and send it a SIGKILL instead of SIGTERM. * One confirmed buggy version of pppd is ppp-2.4.2-6.4.RHEL4 * See http://bugs.xelerance.com/view.php?id=739 * * Sometimes pppd takes 7 sec to go down! We don't have that much time, * since all other calls are suspended while doing this. */ #ifdef TRUST_PPPD_TO_DIE #ifdef DEBUG_PPPD l2tp_log (LOG_DEBUG, "Terminating pppd: sending TERM signal to pid %d\n", pid); #endif kill (pid, SIGTERM); #else #ifdef DEBUG_PPPD l2tp_log (LOG_DEBUG, "Terminating pppd: sending KILL signal to pid %d\n", pid); #endif kill (pid, SIGKILL); #endif } if (c->container) { p = c->container->call_head; /* * Remove us from the call list, although * we might not actually be there */ if (p) { if (p == c) { c->container->call_head = c->next; c->container->count--; } else { while (p->next && (p->next != c)) p = p->next; if (p->next) { p->next = c->next; c->container->count--; } } } } if (c->lac) { c->lac->c = NULL; if (c->lac->redial && (c->lac->rtimeout > 0) && !c->lac->rsched && c->lac->active) { #ifdef DEBUG_MAGIC l2tp_log (LOG_DEBUG, "Will redial in %d seconds\n", c->lac->rtimeout); #endif tv.tv_sec = c->lac->rtimeout; tv.tv_usec = 0; c->lac->rsched = schedule (tv, magic_lac_dial, c->lac); } } if(c->oldptyconf) free(c->oldptyconf); free (c); } struct call *new_call (struct tunnel *parent) { unsigned char entropy_buf[2] = "\0"; struct call *tmp = calloc (1,sizeof (struct call)); if (!tmp) return NULL; tmp->tx_pkts = 0; tmp->rx_pkts = 0; tmp->tx_bytes = 0; tmp->rx_bytes = 0; tmp->zlb_xmit = NULL; /* tmp->throttle = 0; */ /* tmp->dethrottle=NULL; */ tmp->prx = 0; /* tmp->rbit = 0; */ tmp->msgtype = 0; /* tmp->timeout = 0; */ tmp->data_seq_num = 0; tmp->data_rec_seq_num = 0; tmp->pLr = -1; tmp->nego = 0; tmp->debug = 0; tmp->seq_reqd = 0; tmp->state = 0; /* Nothing so far */ if (parent->self) { #ifndef TESTING /* while(get_call(parent->ourtid, (tmp->ourcid = (rand() && 0xFFFF)),0,0)); */ /* FIXME: What about possibility of multiple random #'s??? */ /* tmp->ourcid = (rand () & 0xFFFF); */ get_entropy(entropy_buf, 2); { unsigned short *temp; temp = (unsigned short *)entropy_buf; tmp->ourcid = *temp & 0xFFFF; #ifdef DEBUG_ENTROPY l2tp_log(LOG_DEBUG, "ourcid = %u, entropy_buf = %hx\n", tmp->ourcid, *temp); #endif } #else tmp->ourcid = 0x6227; #endif } tmp->dialed[0] = 0; tmp->dialing[0] = 0; tmp->subaddy[0] = 0; tmp->physchan = -1; tmp->serno = 0; tmp->bearer = -1; tmp->cid = -1; tmp->qcid = -1; tmp->container = parent; /* tmp->rws = -1; */ tmp->fd = -1; tmp->rbuf_pos = 0; tmp->rbuf_max = 0; tmp->ppp_buf = new_payload (parent->peer); tmp->oldptyconf = malloc (sizeof (struct termios)); tmp->pnu = 0; tmp->cnu = 0; tmp->needclose = 0; tmp->closing = 0; tmp->die = 0; tmp->pppd = 0; tmp->error = -1; tmp->result = -1; tmp->errormsg[0] = 0; tmp->fbit = 0; tmp->cid = 0; tmp->lbit = 0; /* Inherit LAC and LNS from parent */ tmp->lns = parent->lns; tmp->lac = parent->lac; tmp->addr = 0; /* tmp->ourrws = DEFAULT_RWS_SIZE; */ /* if (tmp->ourrws >= 0) tmp->ourfbit = FBIT; else */ tmp->ourfbit = 0; /* initialize to 0 since we don't actually use this value at this point anywhere in the code (I don't think) We might just be able to remove it completely */ tmp->dial_no[0] = '\0'; /* jz: dialing number for outgoing call */ return tmp; } struct call *get_tunnel (int tunnel, unsigned int addr, int port) { UNUSED(addr); UNUSED(port); struct tunnel *st; if (tunnel) { st = tunnels.head; while (st) { if (st->ourtid == tunnel) { return st->self; } st = st->next; } } return NULL; } struct call *get_call (int tunnel, int call, struct in_addr addr, int port, IPsecSAref_t refme, IPsecSAref_t refhim) { /* * Figure out which call struct should handle this. * If we have tunnel and call ID's then they are unique. * Otherwise, if the tunnel is 0, look for an existing connection * or create a new tunnel. */ struct tunnel *st; struct call *sc; if (tunnel) { st = tunnels.head; while (st) { if (st->ourtid == tunnel && (gconfig.ipsecsaref==0 || (st->refhim == refhim || refhim==IPSEC_SAREF_NULL || st->refhim==IPSEC_SAREF_NULL))) { if (call) { sc = st->call_head; while (sc) { /* confirm that this is in fact a call with the right SA! */ if (sc->ourcid == call) return sc; sc = sc->next; } l2tp_log (LOG_DEBUG, "%s: can't find call %d in tunnel %d\n (ref=%d/%d)", __FUNCTION__, call, tunnel, refme, refhim); return NULL; } else { return st->self; } } st = st->next; } l2tp_log (LOG_INFO, "Can not find tunnel %u (refhim=%u)\n", tunnel, refhim); return NULL; } else { /* You can't specify a call number if you haven't specified a tunnel silly! */ if (call) { l2tp_log (LOG_WARNING, "%s: call ID specified, but no tunnel ID specified. tossing.\n", __FUNCTION__); return NULL; } /* * Well, nothing appropriate... Let's add a new tunnel, if * we are not at capacity. */ if (gconfig.debug_tunnel) { l2tp_log (LOG_DEBUG, "%s: allocating new tunnel for host %s, port %d.\n", __FUNCTION__, IPADDY (addr), ntohs (port)); } if (!(st = new_tunnel ())) { l2tp_log (LOG_WARNING, "%s: unable to allocate new tunnel for host %s, port %d.\n", __FUNCTION__, IPADDY (addr), ntohs (port)); return NULL; }; st->peer.sin_family = AF_INET; st->peer.sin_port = port; st->refme = refme; st->refhim = refhim; st->udp_fd = -1; st->pppox_fd = -1; bcopy (&addr, &st->peer.sin_addr, sizeof (addr)); st->next = tunnels.head; tunnels.head = st; tunnels.count++; return st->self; } } xl2tpd-1.3.16/call.h000066400000000000000000000116671374460464600141340ustar00rootroot00000000000000/* * Layer Two Tunnelling Protocol Daemon * Copyright (C) 1998 Adtran, Inc. * Copyright (C) 2002 Jeff McAdams * * Mark Spencer * * This software is distributed under the terms * of the GPL, which you should have received * along with this source. * * Handle a call as a separate thread (header file) */ #include #include "misc.h" #include "common.h" #include "ipsecmast.h" #define CALL_CACHE_SIZE 256 struct call { /* int rbit; Set the "R" bit on the next packet? */ int lbit; /* Should we send length field? */ /* int throttle; Throttle the connection? */ int seq_reqd; /* Sequencing required? */ int tx_pkts; /* Transmitted packets */ int rx_pkts; /* Received packets */ int tx_bytes; /* transmitted bytes */ int rx_bytes; /* received bytes */ struct schedule_entry *zlb_xmit; /* Scheduled ZLB transmission */ /* struct schedule_entry *dethrottle; */ /* Scheduled dethrottling (overrun) */ /* int timeout; Has our timeout expired? If so, we'll go ahead and transmit, full window or not, and set the R-bit on this packet. */ int prx; /* What was the last packet we sent as an Nr? Used to manage payload ZLB's */ int state; /* Current state */ int frame; /* Framing being used */ struct call *next; /* Next call, for linking */ int debug; int msgtype; /* What kind of message are we working with right now? */ int ourcid; /* Our call number */ int cid; /* Their call number */ int qcid; /* Quitting CID */ int bearer; /* Bearer type of call */ unsigned int serno; /* Call serial number */ unsigned int addr; /* Address reserved for this call */ int txspeed; /* Transmit speed */ int rxspeed; /* Receive speed */ int ppd; /* Packet processing delay (of peer) */ int physchan; /* Physical channel ID */ char dialed[MAXSTRLEN]; /* Number dialed for call */ char dialing[MAXSTRLEN]; /* Original caller ID */ char subaddy[MAXSTRLEN]; /* Sub address */ int needclose; /* Do we need to close this call? */ int closing; /* Are we actually in the process of closing? */ /* needclose closing state ========= ======= ===== 0 0 Running 1 0 Send Closing notice 1 1 Waiting for closing notice 0 1 Closing ZLB received, actulaly close */ struct tunnel *container; /* Tunnel we belong to */ int fd; /* File descriptor for pty */ unsigned char rbuf[MAX_RECV_SIZE]; /* pty read buffer */ int rbuf_pos; /* Read buffer position */ int rbuf_max; /* Read buffer data length */ struct buffer *ppp_buf; /* Packet readed from pty */ struct termios *oldptyconf; int die; int nego; /* Show negotiation? */ int pppd; /* PID of pppd */ int result; /* Result code */ int error; /* Error code */ int fbit; /* Use sequence numbers? */ int ourfbit; /* Do we want sequence numbers? */ /* int ourrws; Our RWS for the call */ int cnu; /* Do we need to send updated Ns, Nr values? */ int pnu; /* ditto for payload packet */ char errormsg[MAXSTRLEN]; /* Error message */ /* int rws; Receive window size, or -1 for none */ struct timeval lastsent; /* When did we last send something? */ _u16 data_seq_num; /* Sequence for next payload packet */ _u16 data_rec_seq_num; /* Sequence for next received payload packet */ _u16 closeSs; /* What number was in Ns when we started to close? */ int pLr; /* Last packet received by peer */ struct lns *lns; /* LNS that owns us */ struct lac *lac; /* LAC that owns us */ char dial_no[128]; /* jz: dialing number for outgoing call */ }; extern void push_handler (int); extern void toss (struct buffer *); extern struct call *get_call (int tunnel, int call, struct in_addr addr, int port, IPsecSAref_t refme, IPsecSAref_t refhim); extern struct call *get_tunnel (int, unsigned int, int); extern void destroy_call (struct call *); extern struct call *new_call (struct tunnel *); extern void set_error (struct call *, int, const char *, ...); void *call_thread_init (void *); void call_close (struct call *); xl2tpd-1.3.16/common.h000066400000000000000000000007021374460464600144750ustar00rootroot00000000000000/* * Layer 2 Tunnelling Protocol Daemon * Copyright (C) 2002 Jeff McAdams * * This software is distributed under the terms of the GPL, which you * should have receivede along with this source. * * Defines common to several different files */ #ifndef _COMMON_H_ typedef unsigned char _u8; typedef unsigned short _u16; typedef unsigned long long _u64; extern int rand_source; #ifndef LINUX # define SOL_IP 0 #endif #define _COMMON_H_ #endif xl2tpd-1.3.16/contrib/000077500000000000000000000000001374460464600144755ustar00rootroot00000000000000xl2tpd-1.3.16/contrib/pfc.1000066400000000000000000000042111374460464600153250ustar00rootroot00000000000000.\" Hey, EMACS: -*- nroff -*- .\" 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 PFC 1 "October 30, 2008" .\" 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 pfc \- active precompiled filters generator .SH SYNOPSIS .B pfc .RI >/etc/ppp/your.active.filter .SH DESCRIPTION This manual page documents briefly the .B pfc command. .PP .\" TeX users may be more comfortable with the \fB\fP and .\" \fI\fP escape sequences to invode bold face and italics, .\" respectively. \fBpfc\fP is the Precompiled Filter Compiler - a tool to generate "active precompiled filters". If your pppd supports this feature, you can use this utility to generate the filter files. The Active Filter allows a connect on demand pppd to determine what is 'interesting' traffic, and then initiate the PPP session. The tool allows you to create the filters, in libpcap format, for use by pppd. Common filters are used to ignore traffic (ie: ntp, various protocol keepalives, etc...) so PPP sessions are not initiated until 'real' traffic requires them. .PP Note that the generated compiled filter expression is specific to point-to-point links, and differs from the format generated by tcpdump -ddd. .PP (specify precompiled-active-filter=/etc/ppp/your.active.filter in the ppp options file) .SH EXAMPLE /usr/bin/pfc ntp and ldap > /etc/ppp/your.active.filter .SH SEE ALSO pfc is from the FLoppy Isdn 4 Linux project - see http://www.fli4l.de/en/home/news/ .SH AUTHOR This manual page was written by Roberto C. Sanchez , for the Debian project (but may be used by others). xl2tpd-1.3.16/contrib/pfc.README000066400000000000000000000006771374460464600161360ustar00rootroot00000000000000 Source: http://www.fli4l.de/en/home/news/ If pppd supports "active precompiled filters", you can use this utiliy to generate them. This is useful for preventing the pppd to bring an on-demand connection up by spurious traffic, such as ntp or routing protocol packets. usage: pfc > /etc/ppp/your.active.filter (specify precompiled-active-filter=/etc/ppp/your.active.filter in the ppp options file) example: ./pfc ntp and ldap xl2tpd-1.3.16/contrib/pfc.c000066400000000000000000000023461374460464600154160ustar00rootroot00000000000000/* * Taken from fli4l 3.0 * Make sure you compile it against the same libpcap version used in OpenWrt */ #include #include #include #include #ifdef LINUX # include # include # include #endif #if defined(FREEBSD) || defined(OPENBSD) || defined(NETBSD) || defined(SOLARIS) # include #endif #ifdef SOLARIS # define u_int32_t unsigned int #endif #include int main (int argc, char ** argv) { pcap_t *pc; /* Fake struct pcap so we can compile expr */ struct bpf_program filter; /* Filter program for link-active pkts */ u_int32_t netmask=0; int dflag = 3; if (argc == 4) { if (!strcmp (argv[1], "-d")) { dflag = atoi (argv[2]); argv += 2; argc -=2; } } if (argc != 2) { printf ("usage; %s [ -d ] expression\n", argv[0]); return 1; } pc = pcap_open_dead(DLT_PPP_PPPD, PPP_HDRLEN); if (pcap_compile(pc, &filter, argv[1], 1, netmask) == 0) { printf ("#\n# Expression: %s\n#\n", argv[1]); bpf_dump (&filter, dflag); return 0; } else { printf("error in active-filter expression: %s\n", pcap_geterr(pc)); } return 1; } xl2tpd-1.3.16/contrib/pppol2tp-2.6.23.README000066400000000000000000000002611374460464600176610ustar00rootroot00000000000000No patch is required for linux 2.6.23 and up. The kernel comes native support for kernel mode l2tp. You can verify this by looking for the file /usr/include/linux/if_pppol2tp.h xl2tpd-1.3.16/contrib/pppol2tp-linux-2.4.27.patch000066400000000000000000002562431374460464600211770ustar00rootroot00000000000000Index: linux-2.4.27-l2tp/Documentation/Configure.help =================================================================== --- linux-2.4.27-l2tp.orig/Documentation/Configure.help +++ linux-2.4.27-l2tp/Documentation/Configure.help @@ -9913,6 +9913,16 @@ CONFIG_PPPOE on cvs.samba.org. The required support will be present in the next ppp release (2.4.2). +PPP over L2TP +config PPPOL2TP + Support for PPP-over-L2TP socket family. L2TP is a protocol used by + ISPs and enterprises to tunnel PPP traffic over UDP tunnels. L2TP is + replacing PPTP for VPN uses. + + This kernel component handles only L2TP data packets: a userland + daemon handles L2TP control protocol (tunnel and session setup). One + such daemon is OpenL2TP (http://openl2tp.sourceforge.net/). + Wireless LAN (non-hamradio) CONFIG_NET_RADIO Support for wireless LANs and everything having to do with radio, Index: linux-2.4.27-l2tp/drivers/net/Config.in =================================================================== --- linux-2.4.27-l2tp.orig/drivers/net/Config.in +++ linux-2.4.27-l2tp/drivers/net/Config.in @@ -327,6 +327,7 @@ if [ ! "$CONFIG_PPP" = "n" ]; then dep_tristate ' PPP BSD-Compress compression' CONFIG_PPP_BSDCOMP $CONFIG_PPP if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then dep_tristate ' PPP over Ethernet (EXPERIMENTAL)' CONFIG_PPPOE $CONFIG_PPP + dep_tristate ' PPP over L2TP (EXPERIMENTAL)' CONFIG_PPPOL2TP $CONFIG_PPP $CONFIG_PPPOE fi if [ "$CONFIG_ATM" = "y" -o "$CONFIG_ATM" = "m" ]; then dep_tristate ' PPP over ATM (EXPERIMENTAL)' CONFIG_PPPOATM $CONFIG_PPP $CONFIG_ATM Index: linux-2.4.27-l2tp/drivers/net/Makefile =================================================================== --- linux-2.4.27-l2tp.orig/drivers/net/Makefile +++ linux-2.4.27-l2tp/drivers/net/Makefile @@ -162,6 +162,7 @@ obj-$(CONFIG_PPP_SYNC_TTY) += ppp_synctt obj-$(CONFIG_PPP_DEFLATE) += ppp_deflate.o obj-$(CONFIG_PPP_BSDCOMP) += bsd_comp.o obj-$(CONFIG_PPPOE) += pppox.o pppoe.o +obj-$(CONFIG_PPPOL2TP) += pppox.o pppol2tp.o obj-$(CONFIG_SLIP) += slip.o ifeq ($(CONFIG_SLIP_COMPRESSED),y) Index: linux-2.4.27-l2tp/drivers/net/pppol2tp.c =================================================================== --- /dev/null +++ linux-2.4.27-l2tp/drivers/net/pppol2tp.c @@ -0,0 +1,2588 @@ +/** -*- linux-c -*- *********************************************************** + * Linux PPP over L2TP (PPPoX/PPPoL2TP) Sockets + * + * PPPoX --- Generic PPP encapsulation socket family + * PPPoL2TP --- PPP over L2TP (RFC 2661) + * + * + * Version: 0.13.0 + * + * 251003 : Copied from pppoe.c version 0.6.9. + * + * Author: Martijn van Oosterhout + * Contributors: + * Michal Ostrowski + * Arnaldo Carvalho de Melo + * David S. Miller (davem@redhat.com) + * James Chapman (jchapman@katalix.com) + * + * License: + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + */ + +/* This driver handles only L2TP data frames; control frames are handled by a + * userspace application. + * + * To send data in an L2TP session, userspace opens a PPPoL2TP socket and + * attaches it to a bound UDP socket with local tunnel_id / session_id and + * peer tunnel_id / session_id set. Data can then be sent or received using + * regular socket sendmsg() / recvmsg() calls. Kernel parameters of the socket + * can be read or modified using ioctl() or [gs]etsockopt() calls. + * + * When a PPPoL2TP socket is connected with local and peer session_id values + * zero, the socket is treated as a special tunnel management socket. + * + * Here's example userspace code to create a socket for sending/receiving data + * over an L2TP session:- + * + * struct sockaddr_pppol2tp sax; + * int fd; + * int session_fd; + * + * fd = socket(AF_PPPOX, SOCK_DGRAM, PX_PROTO_OL2TP); + * + * sax.sa_family = AF_PPPOX; + * sax.sa_protocol = PX_PROTO_OL2TP; + * sax.pppol2tp.fd = tunnel_fd; // bound UDP socket + * sax.pppol2tp.pid = 0; // current pid owns UDP socket + * sax.pppol2tp.addr.sin_addr.s_addr = addr->sin_addr.s_addr; + * sax.pppol2tp.addr.sin_port = addr->sin_port; + * sax.pppol2tp.addr.sin_family = AF_INET; + * sax.pppol2tp.s_tunnel = tunnel_id; + * sax.pppol2tp.s_session = session_id; + * sax.pppol2tp.d_tunnel = peer_tunnel_id; + * sax.pppol2tp.d_session = peer_session_id; + * + * session_fd = connect(fd, (struct sockaddr *)&sax, sizeof(sax)); + * + */ + +#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 +#include + +#define PPPOL2TP_DRV_VERSION "V0.13" + +/* Developer debug code. */ +#if 0 +#define DEBUG /* Define to compile in very verbose developer + * debug */ +#define DEBUG_MOD_USE_COUNT /* Define to debug module use count bugs */ +#endif + +/* Useful to debug module use_count problems */ +#ifdef DEBUG_MOD_USE_COUNT +#undef MOD_INC_USE_COUNT +#undef MOD_DEC_USE_COUNT +static int mod_use_count = 0; +#define MOD_INC_USE_COUNT do { \ + mod_use_count++; \ + printk(KERN_DEBUG "%s: INC_USE_COUNT, now %d\n", __FUNCTION__, mod_use_count); \ +} while (0) +#define MOD_DEC_USE_COUNT do { \ + mod_use_count--; \ + printk(KERN_DEBUG "%s: DEC_USE_COUNT, now %d\n", __FUNCTION__, mod_use_count); \ +} while (0) +#endif /* DEBUG_MOD_USE_COUNT */ + +/* Timeouts are specified in milliseconds to/from userspace */ +#define JIFFIES_TO_MS(t) ((t) * 1000 / HZ) +#define MS_TO_JIFFIES(j) ((j * HZ) / 1000) + +/* L2TP header constants */ +#define L2TP_HDRFLAG_T 0x8000 +#define L2TP_HDRFLAG_L 0x4000 +#define L2TP_HDRFLAG_S 0x0800 +#define L2TP_HDRFLAG_O 0x0200 +#define L2TP_HDRFLAG_P 0x0100 + +#define L2TP_HDR_VER_MASK 0x000F +#define L2TP_HDR_VER 0x0002 + +/* Space for UDP, L2TP and PPP headers */ +#define PPPOL2TP_HEADER_OVERHEAD 40 + +/* Just some random numbers */ +#define L2TP_TUNNEL_MAGIC 0x42114DDA +#define L2TP_SESSION_MAGIC 0x0C04EB7D + +#define PPPOL2TP_HASH_BITS 4 +#define PPPOL2TP_HASH_SIZE (1 << PPPOL2TP_HASH_BITS) + +/* Default trace flags */ +#ifdef DEBUG +#define PPPOL2TP_DEFAULT_DEBUG_FLAGS -1 +#else +#define PPPOL2TP_DEFAULT_DEBUG_FLAGS 0 +#endif + +/* For kernel compatability. This might not work for early 2.4 kernels */ +#ifndef dst_pmtu +#define dst_pmtu(dst) dst->pmtu +#endif + +/* Debug kernel message control. + * Verbose debug messages (L2TP_MSG_DEBUG flag) are optionally compiled in. + */ +#ifdef DEBUG +#define DPRINTK(_mask, _fmt, args...) \ + do { \ + if ((_mask) & PPPOL2TP_MSG_DEBUG) \ + printk(KERN_DEBUG "PPPOL2TP %s: " _fmt, \ + __FUNCTION__, ##args); \ + } while(0) +#else +#define DPRINTK(_mask, _fmt, args...) do { } while(0) +#endif /* DEBUG */ + +#define PRINTK(_mask, _type, _lvl, _fmt, args...) \ + do { \ + if ((_mask) & (_type)) \ + printk(_lvl "PPPOL2TP: " _fmt, ##args); \ + } while(0) + +/* Extra driver debug. Should only be enabled by developers working on + * this driver. + */ +#ifdef DEBUG +#define ENTER_FUNCTION printk(KERN_DEBUG "PPPOL2TP: --> %s\n", __FUNCTION__) +#define EXIT_FUNCTION printk(KERN_DEBUG "PPPOL2TP: <-- %s\n", __FUNCTION__) +#else +#define ENTER_FUNCTION do { } while(0) +#define EXIT_FUNCTION do { } while(0) +#endif + +#define container_of(ptr, type, member) ({ \ + const typeof( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)( (char *)__mptr - offsetof(type,member) );}) + +struct pppol2tp_tunnel; + +/* Describes a session. It is the user_data field in the PPPoL2TP + * socket. Contains information to determine incoming packets and transmit + * outgoing ones. + */ +struct pppol2tp_session +{ + int magic; /* should be + * L2TP_SESSION_MAGIC */ + int owner; /* pid that opened the socket */ + + struct sock *sock; /* Pointer to the session + * PPPoX socket */ + struct sock *tunnel_sock; /* Pointer to the tunnel UDP + * socket */ + + struct pppol2tp_addr tunnel_addr; /* Description of tunnel */ + + struct pppol2tp_tunnel *tunnel; /* back pointer to tunnel + * context */ + + char name[20]; /* "sess xxxxx/yyyyy", where + * x=tunnel_id, y=session_id */ + int mtu; + int mru; + int flags; /* accessed by PPPIOCGFLAGS. + * Unused. */ + int recv_seq:1; /* expect receive packets with + * sequence numbers? */ + int send_seq:1; /* send packets with sequence + * numbers? */ + int lns_mode:1; /* behave as LNS? LAC enables + * sequence numbers under + * control of LNS. */ + int debug; /* bitmask of debug message + * categories */ + int reorder_timeout; /* configured reorder timeout + * (in jiffies) */ + u16 nr; /* session NR state (receive) */ + u16 ns; /* session NR state (send) */ + struct sk_buff_head reorder_q; /* receive reorder queue */ + struct pppol2tp_ioc_stats stats; + struct hlist_node hlist; /* Hash list node */ +}; + +/* The user_data field of the tunnel's UDP socket. It contains info to track + * all the associated sessions so incoming packets can be sorted out + */ +struct pppol2tp_tunnel +{ + int magic; /* Should be L2TP_TUNNEL_MAGIC */ + + struct proto *old_proto; /* original proto */ + struct proto l2tp_proto; /* L2TP proto */ + rwlock_t hlist_lock; /* protect session_hlist */ + struct hlist_head session_hlist[PPPOL2TP_HASH_SIZE]; + /* hashed list of sessions, + * hashed by id */ + int debug; /* bitmask of debug message + * categories */ + char name[12]; /* "tunl xxxxx" */ + struct pppol2tp_ioc_stats stats; + + void (*old_data_ready)(struct sock *, int); + void (*old_sk_destruct)(struct sock *); + + struct sock *sock; /* Parent socket */ + struct list_head list; /* Keep a list of all open + * prepared sockets */ + + atomic_t session_count; +}; + +/* Private data stored for received packets in the skb. + */ +struct pppol2tp_skb_cb { + u16 ns; + u16 nr; + int has_seq; + int length; + unsigned long expires; +}; + +#define PPPOL2TP_SKB_CB(skb) ((struct pppol2tp_skb_cb *) &skb->cb[sizeof(struct inet_skb_parm)]) + +/* Number of bytes to build transmit L2TP headers. + * Unfortunately the size is different depending on whether sequence numbers + * are enabled. + */ +#define PPPOL2TP_L2TP_HDR_SIZE_SEQ 10 +#define PPPOL2TP_L2TP_HDR_SIZE_NOSEQ 6 + + +static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb); + +static struct ppp_channel_ops pppol2tp_chan_ops = { pppol2tp_xmit , NULL }; +static struct proto_ops pppol2tp_ops; +static LIST_HEAD(pppol2tp_tunnel_list); + +/* Macros to derive session/tunnel context pointers from a socket. */ +#define SOCK_2_SESSION(sock, session, err, errval, label, quiet) \ + session = (struct pppol2tp_session *)((sock)->user_data); \ + if (!session || session->magic != L2TP_SESSION_MAGIC) { \ + if (!quiet) \ + printk(KERN_ERR "%s: %s:%d: BAD SESSION MAGIC " \ + "(" #sock "=%p) session=%p magic=%x\n", \ + __FUNCTION__, __FILE__, __LINE__, sock, \ + session, session ? session->magic : 0); \ + err = errval; \ + goto label; \ + } + +#define SOCK_2_TUNNEL(sock, tunnel, err, errval, label, quiet) \ + tunnel = (struct pppol2tp_tunnel *)((sock)->user_data); \ + if (!tunnel || tunnel->magic != L2TP_TUNNEL_MAGIC) { \ + if (!quiet) \ + printk(KERN_ERR "%s: %s:%d: BAD TUNNEL MAGIC " \ + "(" #sock "=%p) tunnel=%p magic=%x\n", \ + __FUNCTION__, __FILE__, __LINE__, sock, \ + tunnel, tunnel ? tunnel->magic : 0); \ + err = errval; \ + goto label; \ + } + +/* Session hash list. + * The session_id SHOULD be random according to RFC2661, but several + * L2TP implementations (Cisco and Microsoft) use incrementing + * session_ids. So we do a real hash on the session_id, rather than a + * simple bitmask. + */ +static inline struct hlist_head * +pppol2tp_session_id_hash(struct pppol2tp_tunnel *tunnel, u16 session_id) +{ + unsigned long hash_val = (unsigned long) session_id; + return &tunnel->session_hlist[hash_long(hash_val, PPPOL2TP_HASH_BITS)]; +} + +/* Lookup a session by id + */ +static struct pppol2tp_session * +pppol2tp_session_find(struct pppol2tp_tunnel *tunnel, u16 session_id) +{ + struct hlist_head *session_list = + pppol2tp_session_id_hash(tunnel, session_id); + struct hlist_node *tmp; + struct hlist_node *walk; + struct pppol2tp_session *session; + + hlist_for_each_safe(walk, tmp, session_list) { + session = hlist_entry(walk, struct pppol2tp_session, hlist); + if (session->tunnel_addr.s_session == session_id) { + return session; + } + } + + return NULL; +} + +/* Copied from socket.c + */ +static __inline__ void sockfd_put(struct socket *sock) +{ + fput(sock->file); +} + +/***************************************************************************** + * Receive data handling + *****************************************************************************/ + +/* Queue a skb in order. If the skb has no sequence number, queue it + * at the tail. + */ +static void pppol2tp_recv_queue_skb(struct pppol2tp_session *session, struct sk_buff *skb) +{ + struct sk_buff *next; + struct sk_buff *prev; + u16 ns = PPPOL2TP_SKB_CB(skb)->ns; + + ENTER_FUNCTION; + + spin_lock(&session->reorder_q.lock); + + prev = (struct sk_buff *) &session->reorder_q; + next = prev->next; + while (next != prev) { + if (PPPOL2TP_SKB_CB(next)->ns > ns) { + __skb_insert(skb, next->prev, next, next->list); + PRINTK(session->debug, PPPOL2TP_MSG_SEQ, KERN_DEBUG, + "%s: pkt %hu, inserted before %hu, reorder_q len=%d\n", + session->name, ns, PPPOL2TP_SKB_CB(next)->ns, + skb_queue_len(&session->reorder_q)); + session->stats.rx_oos_packets++; + goto out; + } + next = next->next; + } + + __skb_queue_tail(&session->reorder_q, skb); + +out: + spin_unlock(&session->reorder_q.lock); + EXIT_FUNCTION; +} + +/* Dequeue a single skb, passing it either to ppp or to userspace. + */ +static void pppol2tp_recv_dequeue_skb(struct pppol2tp_session *session, struct sk_buff *skb) +{ + struct pppol2tp_tunnel *tunnel = session->tunnel; + int length = PPPOL2TP_SKB_CB(skb)->length; + struct sock *session_sock = NULL; + + ENTER_FUNCTION; + + /* We're about to requeue the skb, so unlink it and return resources + * to its current owner (a socket receive buffer). Also release the + * dst to force a route lookup on the inner IP packet since skb->dst + * currently points to the dst of the UDP tunnel. + */ + skb_unlink(skb); + skb_orphan(skb); + dst_release(skb->dst); + skb->dst = NULL; + +#ifdef CONFIG_NETFILTER + /* We need to forget conntrack info as we reuse the same skb. */ + nf_conntrack_put(skb->nfct); + skb->nfct = NULL; +#ifdef CONFIG_NETFILTER_DEBUG + skb->nf_debug = 0; +#endif +#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) + skb->nf_bridge = NULL; +#endif +#endif /* CONFIG_NETFILTER */ + + tunnel->stats.rx_packets++; + tunnel->stats.rx_bytes += length; + session->stats.rx_packets++; + session->stats.rx_bytes += length; + + if (PPPOL2TP_SKB_CB(skb)->has_seq) { + /* Bump our Nr */ + session->nr++; + PRINTK(session->debug, PPPOL2TP_MSG_SEQ, KERN_DEBUG, + "%s: updated nr to %hu\n", session->name, session->nr); + } + + /* If the socket is bound, send it in to PPP's input queue. Otherwise + * queue it on the session socket. + */ + session_sock = session->sock; + if (session_sock->state & PPPOX_BOUND) { + PRINTK(session->debug, PPPOL2TP_MSG_DATA, KERN_DEBUG, + "%s: recv %d byte data frame, passing to ppp\n", + session->name, length); + ppp_input(&session_sock->protinfo.pppox->chan, skb); + } else { + PRINTK(session->debug, PPPOL2TP_MSG_DATA, KERN_INFO, + "%s: socket not bound\n", session->name); + /* Not bound. Queue it now */ + if (sock_queue_rcv_skb(session_sock, skb) < 0) { + session->stats.rx_errors++; + kfree_skb(skb); + if (!session_sock->dead) + session_sock->data_ready(session_sock, 0); + } + } + + DPRINTK(session->debug, "calling sock_put; refcnt=%d\n", + session->sock->refcnt.counter); + sock_put(session->sock); + EXIT_FUNCTION; +} + +/* Dequeue skbs from the session's reorder_q, subject to packet order. + * Skbs that have been in the queue for too long are simply discarded. + */ +static void pppol2tp_recv_dequeue(struct pppol2tp_session *session) +{ + struct sk_buff *next; + struct sk_buff *prev; + + ENTER_FUNCTION; + + prev = (struct sk_buff *) &session->reorder_q; + spin_lock(&session->reorder_q.lock); + next = prev->next; + + /* If the pkt at the head of the queue has the nr that we + * expect to send up next, dequeue it and any other + * in-sequence packets behind it. + */ + while (next != prev) { + struct sk_buff *skb = next; + next = next->next; + spin_unlock(&session->reorder_q.lock); + + if (time_after(jiffies, PPPOL2TP_SKB_CB(skb)->expires)) { + session->stats.rx_seq_discards++; + session->stats.rx_errors++; + PRINTK(session->debug, PPPOL2TP_MSG_SEQ, KERN_DEBUG, + "%s: oos pkt %hu len %d discarded (too old), waiting for %hu, reorder_q_len=%d\n", + session->name, PPPOL2TP_SKB_CB(skb)->ns, + PPPOL2TP_SKB_CB(skb)->length, session->nr, + skb_queue_len(&session->reorder_q)); + skb_unlink(skb); + kfree_skb(skb); + goto again; + } + + if (PPPOL2TP_SKB_CB(skb)->has_seq) { + if (PPPOL2TP_SKB_CB(skb)->ns != session->nr) { + PRINTK(session->debug, PPPOL2TP_MSG_SEQ, KERN_DEBUG, + "%s: holding oos pkt %hu len %d, waiting for %hu, reorder_q_len=%d\n", + session->name, PPPOL2TP_SKB_CB(skb)->ns, + PPPOL2TP_SKB_CB(skb)->length, session->nr, + skb_queue_len(&session->reorder_q)); + goto out; + } + } + pppol2tp_recv_dequeue_skb(session, skb); +again: + spin_lock(&session->reorder_q.lock); + } + + spin_unlock(&session->reorder_q.lock); +out: + EXIT_FUNCTION; +} + +/* Internal receive frame. Do the real work of receiving an L2TP data frame + * here. + * Returns 0 if the packet was a data packet and was successfully passed on. + * Returns 1 if the packet was not a good data packet and could not be + * forwarded. All such packets are passed up to userspace to deal with. + */ +static int pppol2tp_recv_core(struct sock *sock, struct sk_buff *skb) +{ + struct pppol2tp_session *session = NULL; + int error = 0; + struct pppol2tp_tunnel *tunnel; + unsigned char *ptr; + u16 hdrflags; + u16 tunnel_id, session_id; + int length; + + ENTER_FUNCTION; + + SOCK_2_TUNNEL(sock, tunnel, error, 1, end, 0); + + /* Short packet? */ + if (skb->len < sizeof(struct udphdr)) { + PRINTK(tunnel->debug, PPPOL2TP_MSG_DATA, KERN_INFO, + "%s: recv short packet (len=%d)\n", tunnel->name, skb->len); + goto end; + } + + /* Point to L2TP header */ + ptr = skb->data + sizeof(struct udphdr); + + /* Get L2TP header flags */ + hdrflags = ntohs(*(u16*)ptr); + + /* Trace packet contents, if enabled */ + if (tunnel->debug & PPPOL2TP_MSG_DATA) { + printk(KERN_DEBUG "%s: recv: ", tunnel->name); + + for (length = 0; length < 16; length++) + printk(" %02X", ptr[length]); + printk("\n"); + } + + /* Get length of L2TP packet */ + length = ntohs(skb->h.uh->len) - sizeof(struct udphdr); + + /* Too short? */ + if (length < 12) { + PRINTK(tunnel->debug, PPPOL2TP_MSG_DATA, KERN_INFO, + "%s: recv short L2TP packet (len=%d)\n", tunnel->name, length); + goto end; + } + + /* If type is control packet, it is handled by userspace. */ + if (hdrflags & L2TP_HDRFLAG_T) { + PRINTK(tunnel->debug, PPPOL2TP_MSG_DATA, KERN_DEBUG, + "%s: recv control packet, len=%d\n", tunnel->name, length); + goto end; + } + + /* Skip flags */ + ptr += 2; + + /* If length is present, skip it */ + if (hdrflags & L2TP_HDRFLAG_L) + ptr += 2; + + /* Extract tunnel and session ID */ + tunnel_id = ntohs(*(u16 *) ptr); + ptr += 2; + session_id = ntohs(*(u16 *) ptr); + ptr += 2; + + /* Find the session context */ + session = pppol2tp_session_find(tunnel, session_id); + if (!session) { + /* Not found? Pass to userspace to deal with */ + PRINTK(tunnel->debug, PPPOL2TP_MSG_DATA, KERN_INFO, + "%s: no socket found (%hu/%hu). Passing up.\n", + tunnel->name, tunnel_id, session_id); + goto end; + } + sock_hold(session->sock); + + DPRINTK(session->debug, "%s: socket rcvbuf alloc=%d\n", + session->name, atomic_read(&sock->rmem_alloc)); + + /* The ref count on the socket was increased by the above call since + * we now hold a pointer to the session. Take care to do sock_put() + * when exiting this function from now on... + */ + + /* Handle the optional sequence numbers. If we are the LAC, + * enable/disable sequence numbers under the control of the LNS. If + * no sequence numbers present but we were expecting them, discard + * frame. + */ + if (hdrflags & L2TP_HDRFLAG_S) { + u16 ns, nr; + ns = ntohs(*(u16 *) ptr); + ptr += 2; + nr = ntohs(*(u16 *) ptr); + ptr += 2; + + /* Received a packet with sequence numbers. If we're the LNS, + * check if we sre sending sequence numbers and if not, + * configure it so. + */ + if ((!session->lns_mode) && (!session->send_seq)) { + PRINTK(session->debug, PPPOL2TP_MSG_SEQ, KERN_INFO, + "%s: requested to enable seq numbers by LNS\n", + session->name); + session->send_seq = -1; + } + + /* Store L2TP info in the skb */ + PPPOL2TP_SKB_CB(skb)->ns = ns; + PPPOL2TP_SKB_CB(skb)->nr = nr; + PPPOL2TP_SKB_CB(skb)->has_seq = 1; + + PRINTK(session->debug, PPPOL2TP_MSG_SEQ, KERN_DEBUG, + "%s: recv data ns=%hu, nr=%hu, session nr=%hu\n", + session->name, ns, nr, session->nr); + } else { + /* No sequence numbers. + * If user has configured mandatory sequence numbers, discard. + */ + if (session->recv_seq) { + PRINTK(session->debug, PPPOL2TP_MSG_SEQ, KERN_WARNING, + "%s: recv data has no seq numbers when required. " + "Discarding\n", session->name); + session->stats.rx_seq_discards++; + session->stats.rx_errors++; + goto discard; + } + + /* If we're the LAC and we're sending sequence numbers, the + * LNS has requested that we no longer send sequence numbers. + * If we're the LNS and we're sending sequence numbers, the + * LAC is broken. Discard the frame. + */ + if ((!session->lns_mode) && (session->send_seq)) { + PRINTK(session->debug, PPPOL2TP_MSG_SEQ, KERN_INFO, + "%s: requested to disable seq numbers by LNS\n", + session->name); + session->send_seq = 0; + } else if (session->send_seq) { + PRINTK(session->debug, PPPOL2TP_MSG_SEQ, KERN_WARNING, + "%s: recv data has no seq numbers when required. " + "Discarding\n", session->name); + session->stats.rx_seq_discards++; + session->stats.rx_errors++; + goto discard; + } + + /* Store L2TP info in the skb */ + PPPOL2TP_SKB_CB(skb)->has_seq = 0; + } + + /* If offset bit set, skip it. */ + if (hdrflags & L2TP_HDRFLAG_O) + ptr += 2 + ntohs(*(u16 *) ptr); + + skb_pull(skb, ptr - skb->data); + + /* Skip PPP header, if present. In testing, Microsoft L2TP clients + * don't send the PPP header (PPP header compression enabled), but + * other clients can include the header. So we cope with both cases + * here. The PPP header is always FF03 when using L2TP. + * + * Note that skb->data[] isn't dereferenced from a u16 ptr here since + * the field may be unaligned. + */ + if ((skb->data[0] == 0xff) && (skb->data[1] == 0x03)) + skb_pull(skb, 2); + + /* Prepare skb for adding to the session's reorder_q. Hold + * packets for max reorder_timeout or 1 second if not + * reordering. + */ + PPPOL2TP_SKB_CB(skb)->length = length; + PPPOL2TP_SKB_CB(skb)->expires = jiffies + + (session->reorder_timeout ? session->reorder_timeout : HZ); + + /* Add packet to the session's receive queue. Reordering is done here, if + * enabled. Saved L2TP protocol info is stored in skb->sb[]. + */ + if (PPPOL2TP_SKB_CB(skb)->has_seq) { + if (session->reorder_timeout != 0) { + /* Packet reordering enabled. Add skb to session's + * reorder queue, in order of ns. + */ + pppol2tp_recv_queue_skb(session, skb); + } else { + /* Packet reordering disabled. Discard out-of-sequence + * packets + */ + if (PPPOL2TP_SKB_CB(skb)->ns != session->nr) { + session->stats.rx_seq_discards++; + session->stats.rx_errors++; + PRINTK(session->debug, PPPOL2TP_MSG_SEQ, KERN_DEBUG, + "%s: oos pkt %hu len %d discarded, waiting for %hu, reorder_q_len=%d\n", + session->name, PPPOL2TP_SKB_CB(skb)->ns, + PPPOL2TP_SKB_CB(skb)->length, session->nr, + skb_queue_len(&session->reorder_q)); + goto discard; + } + skb_queue_tail(&session->reorder_q, skb); + } + } else { + /* No sequence numbers. Add the skb to the tail of the + * reorder queue. This ensures that it will be + * delivered after all previous sequenced skbs. + */ + skb_queue_tail(&session->reorder_q, skb); + } + + /* Try to dequeue as many skbs from reorder_q as we can. */ + pppol2tp_recv_dequeue(session); + + EXIT_FUNCTION; + return 0; + +discard: + DPRINTK(session->debug, "discarding skb, len=%d\n", skb->len); + skb_unlink(skb); + kfree_skb(skb); + DPRINTK(session->debug, "calling sock_put; refcnt=%d\n", + session->sock->refcnt.counter); + sock_put(session->sock); + EXIT_FUNCTION; + return 0; + +end: + EXIT_FUNCTION; + return 1; +} + +/* The data_ready hook on the UDP socket. Scan the incoming packet list for + * packets to process. Only control or bad data packets are delivered to + * userspace. + */ +static void pppol2tp_data_ready(struct sock *sk, int len) +{ + int err; + struct pppol2tp_tunnel *tunnel; + struct sk_buff *skb; + + ENTER_FUNCTION; + SOCK_2_TUNNEL(sk, tunnel, err, -EBADF, end, 0); + + PRINTK(tunnel->debug, PPPOL2TP_MSG_DATA, KERN_DEBUG, + "%s: received %d bytes\n", tunnel->name, len); + + skb = skb_dequeue(&sk->receive_queue); + if (pppol2tp_recv_core(sk, skb)) { + DPRINTK(tunnel->debug, "%s: packet passing to userspace\n", + tunnel->name); + skb_queue_head(&sk->receive_queue, skb); + tunnel->old_data_ready(sk, len); + } else { + DPRINTK(tunnel->debug, "%s: data packet received\n", + tunnel->name); + } +end: + EXIT_FUNCTION; + return; +} + +/* Receive message. This is the recvmsg for the PPPoL2TP socket. + */ +static int pppol2tp_recvmsg(struct socket *sock, struct msghdr *msg, int len, + int flags, struct scm_cookie *scm) +{ + int err = 0; + struct sk_buff *skb = NULL; + struct sock *sk = sock->sk; + + ENTER_FUNCTION; + + err = -EIO; + if (sock->state & PPPOX_BOUND) + goto error; + + msg->msg_namelen = 0; + + skb=skb_recv_datagram(sk, flags & ~MSG_DONTWAIT, + flags & MSG_DONTWAIT, &err); + if (skb) { + err = memcpy_toiovec(msg->msg_iov, (unsigned char *) skb->data, + skb->len); + if (err < 0) + goto do_skb_free; + err = skb->len; + } +do_skb_free: + if (skb) + kfree_skb(skb); +error: + EXIT_FUNCTION; + return err; +} + +/************************************************************************ + * Transmit handling + ***********************************************************************/ + +/* Internal UDP socket transmission + */ +static int pppol2tp_udp_sock_send(struct pppol2tp_session *session, + struct pppol2tp_tunnel *tunnel, + struct msghdr *msg, int total_len) +{ + mm_segment_t fs; + int error; + + ENTER_FUNCTION; + + DPRINTK(session->debug, "%s: udp_sendmsg call...\n", session->name); +#ifdef DEBUG + /* Catch bad socket parameter errors */ + if (msg->msg_name) { + struct sockaddr_in * usin = (struct sockaddr_in*)msg->msg_name; + if (msg->msg_namelen < sizeof(*usin)) { + printk(KERN_ERR "msg->msg_namelen wrong, %d\n", msg->msg_namelen); + return -EINVAL; + } + if (usin->sin_family != AF_INET) { + if (usin->sin_family != AF_UNSPEC) { + printk(KERN_ERR "addr family wrong: %d\n", usin->sin_family); + return -EINVAL; + } + } + if ((usin->sin_addr.s_addr == 0) || (usin->sin_port == 0)) { + printk(KERN_ERR "udp addr=%x/%hu\n", usin->sin_addr.s_addr, usin->sin_port); + return -EINVAL; + } + } +#endif /* DEBUG */ + + /* Set to userspace data segment while we do a sendmsg() call. We're + * actually calling a userspace API from the kernel here... + */ + fs = get_fs(); + set_fs(get_ds()); + + /* The actual sendmsg() call... */ + error = tunnel->old_proto->sendmsg(session->tunnel_sock, msg, total_len); + if (error >= 0) { + tunnel->stats.tx_packets++; + tunnel->stats.tx_bytes += error; + session->stats.tx_packets++; + session->stats.tx_bytes += error; + } else { + tunnel->stats.tx_errors++; + session->stats.tx_errors++; + } + + /* Back to kernel space */ + set_fs(fs); + + DPRINTK(session->debug, "%s: %s: returning result %d\n", __FUNCTION__, + session->name, error); + kfree(msg->msg_iov); + kfree(msg); + + EXIT_FUNCTION; + return error; +} + +/* Build an L2TP header for the session into the buffer provided. + */ +static int pppol2tp_build_l2tp_header(struct pppol2tp_session *session, + void *buf) +{ + u16 *bufp = buf; + u16 flags = L2TP_HDR_VER; + + if (session->send_seq) { + flags |= L2TP_HDRFLAG_S; + } + + /* Setup L2TP header. + * FIXME: Can this ever be unaligned? Is direct dereferencing of + * 16-bit header fields safe here for all architectures? + */ + *bufp++ = htons(flags); + *bufp++ = htons(session->tunnel_addr.d_tunnel); + *bufp++ = htons(session->tunnel_addr.d_session); + if (session->send_seq) { + *bufp++ = htons(session->ns); + *bufp++ = 0; + session->ns++; + PRINTK(session->debug, PPPOL2TP_MSG_SEQ, KERN_DEBUG, + "%s: updated ns to %hu\n", session->name, session->ns); + } + /* This is the PPP header really */ + *bufp = htons(0xff03); + + return ((void *) bufp) - buf; +} + +/* This is the sendmsg for the PPPoL2TP pppol2tp_session socket. We come here + * when a user application does a sendmsg() on the session socket. L2TP and + * PPP headers must be inserted into the user's data. + */ +static int pppol2tp_sendmsg(struct socket *sock, struct msghdr *m, + int total_len, struct scm_cookie *scm) +{ + static unsigned char ppph[2] = { 0xff, 0x03 }; + struct sock *sk = sock->sk; + int error = 0; + u8 hdr[PPPOL2TP_L2TP_HDR_SIZE_SEQ]; + int hdr_len; + struct msghdr *msg; + struct pppol2tp_session *session; + struct pppol2tp_tunnel *tunnel; + + ENTER_FUNCTION; + + if (sk->dead || !(sk->state & PPPOX_CONNECTED)) { + error = -ENOTCONN; + goto end; + } + + /* Get session and tunnel contexts */ + SOCK_2_SESSION(sk, session, error, -EBADF, end, 0); + SOCK_2_TUNNEL(session->tunnel_sock, tunnel, error, -EBADF, end, 0); + + /* Setup L2TP header */ + hdr_len = pppol2tp_build_l2tp_header(session, &hdr); + + if (session->send_seq) + PRINTK(session->debug, PPPOL2TP_MSG_DATA, KERN_DEBUG, + "%s: send %d bytes, ns=%hu\n", session->name, + total_len, session->ns - 1); + else + PRINTK(session->debug, PPPOL2TP_MSG_DATA, KERN_DEBUG, + "%s: send %d bytes\n", session->name, total_len); + + if (session->debug & PPPOL2TP_MSG_DATA) { + int i, j, count; + + printk(KERN_DEBUG "%s: xmit:", session->name); + count = 0; + for (i = 0; i < m->msg_iovlen; i++) { + for (j = 0; j < m->msg_iov[i].iov_len; j++) { + printk(" %02X", ((unsigned char *) m->msg_iov[i].iov_base)[j]); + count++; + if (count == 15) { + printk(" ..."); + break; + } + } + } + printk("\n"); + } + + /* Unfortunately, there is no direct way for us to pass an skb to the + * UDP layer, we have to pretend to be sending ordinary data and use + * sendmsg. + * + * We add the L2TP and PPP headers here. To do so, we create a new + * struct msghdr and insert the headers as the first iovecs. + */ + msg = kmalloc(sizeof(struct msghdr), GFP_ATOMIC); + if (msg == NULL) { + error = -ENOBUFS; + tunnel->stats.tx_errors++; + session->stats.tx_errors++; + goto end; + } + + msg->msg_iov = kmalloc((m->msg_iovlen + 2) * sizeof(struct iovec), + GFP_ATOMIC); + if (msg->msg_iov == NULL) { + error = -ENOBUFS; + tunnel->stats.tx_errors++; + session->stats.tx_errors++; + kfree(msg); + goto end; + } + + msg->msg_iov[0].iov_base = &hdr; + msg->msg_iov[0].iov_len = hdr_len; + msg->msg_iov[1].iov_base = &ppph; + msg->msg_iov[1].iov_len = sizeof(ppph); + memcpy(&msg->msg_iov[2], &m->msg_iov[0], + m->msg_iovlen * sizeof(struct iovec)); + msg->msg_iovlen = m->msg_iovlen + 2; + + /* If the user calls sendto() that's just too bad */ + msg->msg_name = &session->tunnel_addr.addr; + msg->msg_namelen = sizeof(session->tunnel_addr.addr); + + msg->msg_control = m->msg_control; + msg->msg_controllen = m->msg_controllen; + msg->msg_flags = m->msg_flags; + + /* Do the real work. This always frees msg, regardless of whether + * there was an error + */ + error = pppol2tp_udp_sock_send(session, tunnel, msg, + total_len + hdr_len + sizeof(ppph)); + +end: + EXIT_FUNCTION; + return error; +} + + +/* Transmit function called by generic PPP driver. Sends PPP frame over + * PPPoL2TP socket. + * + * This is almost the same as pppol2tp_sendmsg(), but rather than being called + * with a msghdr from userspace, it is called with a skb from the kernel. + */ +static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb) +{ + static unsigned char ppph[2] = { 0xff, 0x03 }; + struct sock *sk = (struct sock *) chan->private; + int error = 0; + u8 hdr[PPPOL2TP_L2TP_HDR_SIZE_SEQ]; + int hdr_len; + struct msghdr *msg; + struct pppol2tp_session *session; + struct pppol2tp_tunnel *tunnel; + + ENTER_FUNCTION; + + if (sk->dead || !(sk->state & PPPOX_CONNECTED)) { + DPRINTK(-1, "dead=%d state=%x\n", sk->dead, sk->state); + error = -ENOTCONN; + goto end; + } + + /* Get session and tunnel contexts from the socket */ + SOCK_2_SESSION(sk, session, error, -EBADF, end, 0); + SOCK_2_TUNNEL(session->tunnel_sock, tunnel, error, -EBADF, end, 0); + + /* Setup L2TP header */ + hdr_len = pppol2tp_build_l2tp_header(session, &hdr); + + if (session->send_seq) + PRINTK(session->debug, PPPOL2TP_MSG_DATA, KERN_DEBUG, + "%s: send %d bytes, ns=%hu\n", + session->name, skb->len, session->ns - 1); + else + PRINTK(session->debug, PPPOL2TP_MSG_DATA, KERN_DEBUG, + "%s: send %d bytes\n", session->name, skb->len); + + if (session->debug & PPPOL2TP_MSG_DATA) { + int i; + + printk(KERN_DEBUG "%s: xmit:", session->name); + for (i = 0; i < skb->len; i++) { + printk(" %02X", skb->data[i]); + if (i == 15) { + printk(" ..."); + break; + } + } + printk("\n"); + } + + /* Unfortunatly there doesn't appear to be a way for us to pass an skb + * to the UDP layer, we have to pretend to be sending ordinary data + * and use sendmsg + */ + msg = kmalloc(sizeof(struct msghdr), GFP_ATOMIC); + if (msg == NULL) { + error = -ENOBUFS; + tunnel->stats.tx_errors++; + session->stats.tx_errors++; + goto end; + } + + msg->msg_iov = kmalloc(2 * sizeof(struct iovec), GFP_ATOMIC); + if (msg->msg_iov == NULL) { + error = -ENOBUFS; + tunnel->stats.tx_errors++; + session->stats.tx_errors++; + kfree(msg); + goto end; + } + msg->msg_iov[0].iov_base = &hdr; + msg->msg_iov[0].iov_len = hdr_len; + /* FIXME: do we need to handle skb fragments here? */ + msg->msg_iov[1].iov_base = &ppph; + msg->msg_iov[1].iov_len = sizeof(ppph); + msg->msg_iov[2].iov_base = skb->data; + msg->msg_iov[2].iov_len = skb->len; + msg->msg_iovlen = 3; + + /* If the user calls sendto() that's just too bad */ + msg->msg_name = &session->tunnel_addr.addr; + msg->msg_namelen = sizeof(session->tunnel_addr.addr); + + msg->msg_control = NULL; + msg->msg_controllen = 0; + msg->msg_flags = MSG_DONTWAIT; /* Need this to prevent blocking */ + + /* Do the real work. This always frees msg, regardless of whether + * there was an error + */ + error = pppol2tp_udp_sock_send(session, tunnel, msg, + skb->len + hdr_len + sizeof(ppph)); + + kfree_skb(skb); + +end: + EXIT_FUNCTION; + return error; +} + +/***************************************************************************** + * Session (and tunnel control) socket create/destroy. + *****************************************************************************/ + +/* When the tunnel UDP socket is closed, all the attached sockets need to go + * too. This handles that. + */ +static void pppol2tp_tunnel_closeall(struct pppol2tp_tunnel *tunnel) +{ + int hash; + struct hlist_node *walk; + struct hlist_node *tmp; + struct pppol2tp_session *session; + struct sock *sk; + + ENTER_FUNCTION; + + if (tunnel == NULL) + BUG(); + + PRINTK(tunnel->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO, + "%s: closing all sessions...\n", tunnel->name); + + for (hash = 0; hash < PPPOL2TP_HASH_SIZE; hash++) { + hlist_for_each_safe(walk, tmp, &tunnel->session_hlist[hash]) { + session = hlist_entry(walk, struct pppol2tp_session, hlist); + + sk = session->sock; + + PRINTK(session->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO, + "%s: closing session\n", session->name); + + write_lock_bh(&tunnel->hlist_lock); + hlist_del_init(&session->hlist); + write_unlock_bh(&tunnel->hlist_lock); + + sock_hold(sk); + + lock_sock(sk); + + if (sk->state & (PPPOX_CONNECTED | PPPOX_BOUND)) { + pppox_unbind_sock(sk); + sk->state = PPPOX_DEAD; + sk->state_change(sk); + } + + /* Purge any queued data */ + skb_queue_purge(&sk->receive_queue); + skb_queue_purge(&sk->write_queue); + + release_sock(sk); + + DPRINTK(session->debug, "calling sock_put; refcnt=%d\n", + sk->refcnt.counter); + sock_put(sk); + } + } + + EXIT_FUNCTION; +} + +/* Really kill the tunnel. + * Come here only when all sessions have been cleared from the tunnel. + */ +static void pppol2tp_tunnel_free(struct pppol2tp_tunnel *tunnel) +{ + struct sock *sk = tunnel->sock; + + ENTER_FUNCTION; + + /* Remove from socket list */ + list_del_init(&tunnel->list); + + sk->prot = tunnel->old_proto; + sk->data_ready = tunnel->old_data_ready; + sk->destruct = tunnel->old_sk_destruct; + sk->user_data = NULL; + + DPRINTK(tunnel->debug, "%s: MOD_DEC_USE_COUNT\n", tunnel->name); + kfree(tunnel); + MOD_DEC_USE_COUNT; + + EXIT_FUNCTION; +} + +/* Tunnel UDP socket destruct hook. + * The tunnel context is deleted only when all session sockets have been + * closed. + */ +static void pppol2tp_tunnel_destruct(struct sock *sk) +{ + struct pppol2tp_tunnel *tunnel; + int error = 0; + ENTER_FUNCTION; + + SOCK_2_TUNNEL(sk, tunnel, error, -EBADF, end, 0); + + PRINTK(tunnel->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO, + "%s: closing...\n", tunnel->name); + + pppol2tp_tunnel_closeall(tunnel); + +end: + EXIT_FUNCTION; + return; +} + +/* Really kill the socket. (Called from sock_put if refcnt == 0.) + */ +static void pppol2tp_session_destruct(struct sock *sk) +{ + struct pppol2tp_session *session = NULL; + int error = 0; + + ENTER_FUNCTION; + + if (sk->user_data != NULL) { + struct pppol2tp_tunnel *tunnel; + + SOCK_2_SESSION(sk, session, error, -EBADF, out, 0); + skb_queue_purge(&session->reorder_q); + + /* Don't use SOCK_2_TUNNEL() here to get the tunnel context + * because the tunnel socket might have already been closed + * (its sk->user_data will be NULL) so use the session's + * private tunnel ptr instead. + */ + tunnel = session->tunnel; + if (tunnel != NULL) { + if (tunnel->magic != L2TP_TUNNEL_MAGIC) { + printk(KERN_ERR "%s: %s:%d: BAD TUNNEL MAGIC " + "( tunnel=%p magic=%x )\n", + __FUNCTION__, __FILE__, __LINE__, + tunnel, tunnel->magic); + goto out; + } + } + + /* Delete tunnel context if this was the last session on the + * tunnel. This was allocated when the first session was + * created on the tunnel. See + * pppol2tp_prepare_tunnel_socket(). + */ + DPRINTK(tunnel->debug, "%s: session_count=%d\n", + tunnel->name, atomic_read(&tunnel->session_count)); + if (atomic_dec_and_test(&tunnel->session_count)) { + pppol2tp_tunnel_free(tunnel); + } + } + + if (session != NULL) + DPRINTK(session->debug, "%s: MOD_DEC_USE_COUNT\n", session->name); + + if (sk->protinfo.pppox) + kfree(sk->protinfo.pppox); + + if (session != NULL) + kfree(session); + MOD_DEC_USE_COUNT; + +out: + EXIT_FUNCTION; +} + +/* Called when the PPPoX socket (session) is closed. + */ +static int pppol2tp_release(struct socket *sock) +{ + struct sock *sk = sock->sk; + struct pppol2tp_session *session = NULL; + struct pppol2tp_tunnel *tunnel; + int error = 0; + ENTER_FUNCTION; + + if (!sk) + return 0; + + if (sk->dead != 0) + return -EBADF; + + if (sk->user_data) { /* Was this socket actually connected? */ + SOCK_2_SESSION(sk, session, error, -EBADF, end, 0); + + /* Don't use SOCK_2_TUNNEL() here to get the tunnel context + * because the tunnel socket might have already been closed + * (its sk->user_data will be NULL) so use the session's + * private tunnel ptr instead. + */ + tunnel = session->tunnel; + if (tunnel != NULL) { + if (tunnel->magic == L2TP_TUNNEL_MAGIC) { + /* Delete the session socket from the hash */ + write_lock_bh(&tunnel->hlist_lock); + hlist_del_init(&session->hlist); + write_unlock_bh(&tunnel->hlist_lock); + } else { + printk(KERN_ERR "%s: %s:%d: BAD TUNNEL MAGIC " + "( tunnel=%p magic=%x )\n", + __FUNCTION__, __FILE__, __LINE__, + tunnel, tunnel->magic); + goto end; + } + } + } + + lock_sock(sk); + + if (sk->state & (PPPOX_CONNECTED | PPPOX_BOUND)) + pppox_unbind_sock(sk); + + /* Signal the death of the socket. */ + sk->state = PPPOX_DEAD; + sock_orphan(sk); + sock->sk = NULL; + + /* Purge any queued data */ + skb_queue_purge(&sk->receive_queue); + skb_queue_purge(&sk->write_queue); + + release_sock(sk); + + if (session != NULL) + DPRINTK(session->debug, "calling sock_put; refcnt=%d\n", + session->sock->refcnt.counter); + sock_put(sk); + +end: + EXIT_FUNCTION; + return error; +} + +/* Copied from fget() in fs/file_table.c. + * Allows caller to specify the pid that owns the fd. + */ +static struct file *pppol2tp_fget(pid_t pid, unsigned int fd) +{ + struct file *file; + struct files_struct *files = current->files; + + if (pid != 0) { + struct task_struct *tsk = find_task_by_pid(pid); + if (tsk == NULL) + return NULL; + files = tsk->files; + } + + spin_lock(&files->file_lock); + file = fcheck_files(files, fd); + if (file) + get_file(file); + spin_unlock(&files->file_lock); + return file; +} + +/* Copied from net/socket.c */ +extern __inline__ struct socket *socki_lookup(struct inode *inode) +{ + return &inode->u.socket_i; +} + +/* Copied from sockfd_lookup() in net/socket.c. + * Allows caller to specify the pid that owns the fd. + */ +static struct socket *pppol2tp_sockfd_lookup(pid_t pid, int fd, int *err) +{ + struct file *file; + struct inode *inode; + struct socket *sock; + + if (!(file = pppol2tp_fget(pid, fd))) { + *err = -EBADF; + return NULL; + } + + inode = file->f_dentry->d_inode; + if (!inode->i_sock || !(sock = socki_lookup(inode))) { + *err = -ENOTSOCK; + fput(file); + return NULL; + } + + if (sock->file != file) { + printk(KERN_ERR "socki_lookup: socket file changed!\n"); + sock->file = file; + } + return sock; +} + +/* Internal function to prepare a tunnel (UDP) socket to have PPPoX sockets + * attached to it + */ +static struct sock *pppol2tp_prepare_tunnel_socket(pid_t pid, int fd, + u16 tunnel_id, int *error) +{ + int err; + struct socket *sock = NULL; + struct sock *sk; + struct pppol2tp_tunnel *tunnel; + struct sock *ret = NULL; + + ENTER_FUNCTION; + + /* Get the socket from the fd */ + err = -EBADF; + sock = pppol2tp_sockfd_lookup(pid, fd, &err); + if (!sock) { + PRINTK(-1, PPPOL2TP_MSG_CONTROL, KERN_ERR, + "tunl %hu: sockfd_lookup(fd=%d) returned %d\n", + tunnel_id, fd, err); + goto err; + } + + /* Quick sanity checks */ + err = -ESOCKTNOSUPPORT; + if (sock->type != SOCK_DGRAM) { + PRINTK(-1, PPPOL2TP_MSG_CONTROL, KERN_ERR, + "tunl %hu: fd %d wrong type, got %d, expected %d\n", + tunnel_id, fd, sock->type, SOCK_DGRAM); + goto err; + } + err = -EAFNOSUPPORT; + if (sock->ops->family!=AF_INET) { + PRINTK(-1, PPPOL2TP_MSG_CONTROL, KERN_ERR, + "tunl %hu: fd %d wrong family, got %d, expected %d\n", + tunnel_id, fd, sock->ops->family, AF_INET); + goto err; + } + + err = -ENOTCONN; + sk = sock->sk; + + /* Check if this socket has already been prepped */ + tunnel = (struct pppol2tp_tunnel *)sk->user_data; + if (tunnel != NULL) { + /* User-data field already set */ + err = -EBUSY; + if (tunnel->magic != L2TP_TUNNEL_MAGIC) { + printk(KERN_ERR "%s: %s:%d: BAD TUNNEL MAGIC " + "( tunnel=%p magic=%x )\n", + __FUNCTION__, __FILE__, __LINE__, + tunnel, tunnel->magic); + goto err; + } + + /* This socket has already been prepped */ + ret = tunnel->sock; + goto out; + } + + /* This socket is available and needs prepping. Create a new tunnel + * context and init it. + */ + sk->user_data = tunnel = kmalloc(sizeof(struct pppol2tp_tunnel), GFP_KERNEL); + if (sk->user_data == NULL) { + err = -ENOMEM; + goto err; + } + + memset(tunnel, 0, sizeof(struct pppol2tp_tunnel)); + + tunnel->magic = L2TP_TUNNEL_MAGIC; + sprintf(&tunnel->name[0], "tunl %hu", tunnel_id); + + tunnel->stats.tunnel_id = tunnel_id; + + tunnel->debug = PPPOL2TP_DEFAULT_DEBUG_FLAGS; + + DPRINTK(tunnel->debug, "tunl %hu: allocated tunnel=%p, sk=%p, sock=%p\n", + tunnel_id, tunnel, sk, sock); + + /* Setup the new protocol stuff */ + tunnel->old_proto = sk->prot; + tunnel->l2tp_proto = *sk->prot; + + sk->prot = &tunnel->l2tp_proto; + + tunnel->old_data_ready = sk->data_ready; + sk->data_ready = &pppol2tp_data_ready; + + tunnel->old_sk_destruct = sk->destruct; + sk->destruct = &pppol2tp_tunnel_destruct; + + tunnel->sock = sk; + sk->allocation = GFP_ATOMIC; + + rwlock_init(&tunnel->hlist_lock); + + /* Add tunnel to our list */ + INIT_LIST_HEAD(&tunnel->list); + list_add(&tunnel->list, &pppol2tp_tunnel_list); + + ret = tunnel->sock; + + MOD_INC_USE_COUNT; + DPRINTK(-1, "tunl %hu: MOD_INC_USE_COUNT\n", tunnel_id); + + *error = 0; +out: + if (sock) + sockfd_put(sock); + EXIT_FUNCTION; + + return ret; + +err: + *error = err; + goto out; +} + +/* socket() handler. Initialize a new struct sock. + */ +static int pppol2tp_create(struct socket *sock) +{ + int error = 0; + struct sock *sk; + + ENTER_FUNCTION; + DPRINTK(-1, "sock=%p\n", sock); + + sk = sk_alloc(PF_PPPOX, GFP_KERNEL, 1); + if (!sk) + return -ENOMEM; + + MOD_INC_USE_COUNT; + DPRINTK(-1, "MOD_INC_USE_COUNT\n"); + + sock_init_data(sock, sk); + + sock->state = SS_UNCONNECTED; + sock->ops = &pppol2tp_ops; + + sk->protocol = PX_PROTO_OL2TP; + sk->family = PF_PPPOX; + + sk->next = NULL; + sk->pprev = NULL; + sk->state = PPPOX_NONE; + sk->type = SOCK_STREAM; + sk->destruct = pppol2tp_session_destruct; + sk->backlog_rcv = pppol2tp_recv_core; + + sk->protinfo.pppox = kmalloc(sizeof(struct pppox_opt), GFP_KERNEL); + if (!sk->protinfo.pppox) { + error = -ENOMEM; + goto free_sk; + } + + memset((void *) sk->protinfo.pppox, 0, sizeof(struct pppox_opt)); + sk->protinfo.pppox->sk = sk; + + sock->sk = sk; + + EXIT_FUNCTION; + return 0; + +free_sk: + sk_free(sk); + EXIT_FUNCTION; + return error; +} + +/* connect() handler.. Attach a PPPoX socket to a tunnel UDP socket + */ +int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr, + int sockaddr_len, int flags) +{ + struct sock *sk = sock->sk; + struct sockaddr_pppol2tp *sp = (struct sockaddr_pppol2tp *) uservaddr; + struct pppox_opt *po = sk->protinfo.pppox; + struct sock *tunnel_sock = NULL; + struct pppol2tp_session *session = NULL; + struct pppol2tp_tunnel *tunnel; + struct dst_entry *dst; + int error = 0; + + ENTER_FUNCTION; + + DPRINTK(-1, "sock=%p, uservaddr=%p, sockaddr_len=%d, flags=%d, addr=%x/%hu\n", + sock, uservaddr, sockaddr_len, flags, + ntohl(sp->pppol2tp.addr.sin_addr.s_addr), ntohs(sp->pppol2tp.addr.sin_port)); + lock_sock(sk); + + error = -EINVAL; + if (sp->sa_protocol != PX_PROTO_OL2TP) + goto end; + + /* Check for already bound sockets */ + error = -EBUSY; + if (sk->state & PPPOX_CONNECTED) + goto end; + + /* We don't supporting rebinding anyway */ + if (sk->user_data) + goto end; /* socket is already attached */ + + /* Don't bind if s_tunnel is 0 */ + error = -EINVAL; + if (sp->pppol2tp.s_tunnel == 0) + goto end; + + /* Look up the tunnel socket and configure it if necessary */ + tunnel_sock = pppol2tp_prepare_tunnel_socket(sp->pppol2tp.pid, + sp->pppol2tp.fd, + sp->pppol2tp.s_tunnel, + &error); + if (tunnel_sock == NULL) + goto end; + tunnel = tunnel_sock->user_data; + + /* Allocate and initialize a new session context. + */ + session = kmalloc(sizeof(struct pppol2tp_session), GFP_KERNEL); + if (session == NULL) { + error = -ENOMEM; + goto end; + } + + memset(session, 0, sizeof(struct pppol2tp_session)); + + skb_queue_head_init(&session->reorder_q); + + session->magic = L2TP_SESSION_MAGIC; + session->owner = current->pid; + session->sock = sk; + session->tunnel = tunnel; + session->tunnel_sock = tunnel_sock; + session->tunnel_addr = sp->pppol2tp; + sprintf(&session->name[0], "sess %hu/%hu", + session->tunnel_addr.s_tunnel, + session->tunnel_addr.s_session); + + session->stats.tunnel_id = session->tunnel_addr.s_tunnel; + session->stats.session_id = session->tunnel_addr.s_session; + + INIT_HLIST_NODE(&session->hlist); + + session->debug = PPPOL2TP_DEFAULT_DEBUG_FLAGS; + + /* Default MTU must allow space for UDP/L2TP/PPP + * headers. Leave some slack. + */ + session->mtu = session->mru = 1500 - PPPOL2TP_HEADER_OVERHEAD; + + /* If PMTU discovery was enabled, use the MTU that was discovered */ + dst = sk_dst_get(sk); + if (dst != NULL) { + u32 pmtu = dst_pmtu(dst); + if (pmtu != 0) { + session->mtu = session->mru = pmtu - + PPPOL2TP_HEADER_OVERHEAD; + DPRINTK(session->debug, + "%s: MTU set by Path MTU discovery: mtu=%d\n", + session->name, session->mtu); + } + dst_release(dst); + } + + /* Special case: if source & dest session_id == 0x0000, this socket is + * being created to manage the tunnel. Don't add the session to the + * session hash list, just set up the internal context for use by + * ioctl() and sockopt() handlers. + */ + if ((session->tunnel_addr.s_session == 0) && + (session->tunnel_addr.d_session == 0)) { + error = 0; + DPRINTK(session->debug, + "tunl %hu: socket created for tunnel mgmt ops\n", + session->tunnel_addr.s_tunnel); + sk->user_data = session; + goto out_no_ppp; + } + + DPRINTK(session->debug, "%s: allocated session=%p, sock=%p, owner=%d\n", + session->name, session, sk, session->owner); + + /* Add session to the tunnel's hash list */ + SOCK_2_TUNNEL(tunnel_sock, tunnel, error, -EBADF, end, 0); + write_lock_bh(&tunnel->hlist_lock); + hlist_add_head(&session->hlist, + pppol2tp_session_id_hash(tunnel, + session->tunnel_addr.s_session)); + write_unlock_bh(&tunnel->hlist_lock); + + /* This is how we get the session context from the socket. */ + sk->user_data = session; + + /* We don't store any more options in the pppox_opt, everything is in + * user_data (struct pppol2tp_session) + */ + po->sk = sk; + + /* Right now, because we don't have a way to push the incoming skb's + * straight through the UDP layer, the only header we need to worry + * about is the L2TP header. This size is different depending on + * whether sequence numbers are enabled for the data channel. + */ + po->chan.hdrlen = PPPOL2TP_L2TP_HDR_SIZE_NOSEQ; + + po->chan.private = sk; + po->chan.ops = &pppol2tp_chan_ops; + po->chan.mtu = session->mtu; + + error = ppp_register_channel(&po->chan); + if (error) + goto end; + +out_no_ppp: + atomic_inc(&tunnel->session_count); + sk->state = PPPOX_CONNECTED; + PRINTK(session->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO, + "%s: created\n", session->name); + +end: + release_sock(sk); + + if (error != 0) + PRINTK(session ? session->debug : -1, PPPOL2TP_MSG_CONTROL, + KERN_WARNING, "%s: connect failed: %d\n", session->name, + error); + + EXIT_FUNCTION; + + return error; +} + +/* getname() support. + */ +static int pppol2tp_getname(struct socket *sock, struct sockaddr *uaddr, + int *usockaddr_len, int peer) +{ + int len = sizeof(struct sockaddr_pppol2tp); + struct sockaddr_pppol2tp sp; + int error = 0; + struct pppol2tp_session *session; + + ENTER_FUNCTION; + + error = -ENOTCONN; + if (sock->sk->state != PPPOX_CONNECTED) + goto end; + + SOCK_2_SESSION(sock->sk, session, error, -EBADF, end, 0); + + sp.sa_family = AF_PPPOX; + sp.sa_protocol = PX_PROTO_OL2TP; + memcpy(&sp.pppol2tp, &session->tunnel_addr, + sizeof(struct pppol2tp_addr)); + + memcpy(uaddr, &sp, len); + + *usockaddr_len = len; + + error = 0; +end: + EXIT_FUNCTION; + return error; +} + +/**************************************************************************** + * ioctl() handlers. + * + * The PPPoX socket is created for L2TP sessions: tunnels have their own UDP + * sockets. However, in order to control kernel tunnel features, we allow + * userspace to create a special "tunnel" PPPoX socket which is used for + * control only. Tunnel PPPoX sockets have session_id == 0 and simply allow + * the user application to issue L2TP setsockopt(), getsockopt() and ioctl() + * calls. + ****************************************************************************/ + +/* Session ioctl helper. + */ +static int pppol2tp_session_ioctl(struct pppol2tp_session *session, + unsigned int cmd, unsigned long arg) +{ + struct ifreq ifr; + int err = 0; + struct sock *sk = session->sock; + int val = (int) arg; + + sock_hold(sk); + + PRINTK(session->debug, PPPOL2TP_MSG_CONTROL, KERN_DEBUG, + "%s: pppol2tp_session_ioctl(cmd=%#x, arg=%#lx)\n", + session->name, cmd, arg); + + switch (cmd) { + case SIOCGIFMTU: + err = -ENXIO; + if (!(sk->state & PPPOX_CONNECTED)) + break; + + err = -EFAULT; + if (copy_from_user(&ifr, (void *) arg, sizeof(struct ifreq))) + break; + ifr.ifr_mtu = session->mtu; + if (copy_to_user((void *) arg, &ifr, sizeof(struct ifreq))) + break; + + PRINTK(session->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO, + "%s: get mtu=%d\n", session->name, session->mtu); + err = 0; + break; + + case SIOCSIFMTU: + err = -ENXIO; + if (!(sk->state & PPPOX_CONNECTED)) + break; + + err = -EFAULT; + if (copy_from_user(&ifr, (void *) arg, sizeof(struct ifreq))) + break; + + session->mtu = ifr.ifr_mtu; +; + PRINTK(session->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO, + "%s: set mtu=%d\n", session->name, session->mtu); + err = 0; + break; + + case PPPIOCGMRU: + err = -ENXIO; + if (!(sk->state & PPPOX_CONNECTED)) + break; + + err = -EFAULT; + if (put_user(session->mru, (int *) arg)) + break; + + PRINTK(session->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO, + "%s: get mru=%d\n", session->name, session->mru); + err = 0; + break; + + case PPPIOCSMRU: + err = -ENXIO; + if (!(sk->state & PPPOX_CONNECTED)) + break; + + err = -EFAULT; + if (get_user(val,(int *) arg)) + break; + + session->mru = val; + PRINTK(session->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO, + "%s: set mru=%d\n", session->name, session->mru); + err = 0; + break; + + case PPPIOCGFLAGS: + err = -EFAULT; + if (put_user(session->flags, (int *) arg)) + break; + + PRINTK(session->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO, + "%s: get flags=%d\n", session->name, session->flags); + err = 0; + break; + + case PPPIOCSFLAGS: + err = -EFAULT; + if (get_user(val, (int *) arg)) + break; + session->flags = val; + PRINTK(session->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO, + "%s: set flags=%d\n", session->name, session->flags); + err = 0; + break; + + case PPPIOCGL2TPSTATS: + err = -ENXIO; + + if (!(sk->state & PPPOX_CONNECTED)) + break; + + if (copy_to_user((void *) arg, &session->stats, + sizeof(session->stats))) + break; + PRINTK(session->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO, + "%s: get L2TP stats\n", session->name); + err = 0; + break; + + default: + err = -ENOSYS; + break; + } + + sock_put(sk); + + return err; +} + +/* Tunnel ioctl helper. + * + * Note the special handling for PPPIOCGL2TPSTATS below. If the ioctl data + * specifies a session_id, the session ioctl handler is called. This allows an + * application to retrieve session stats via a tunnel socket. + */ +static int pppol2tp_tunnel_ioctl(struct pppol2tp_tunnel *tunnel, + unsigned int cmd, unsigned long arg) +{ + int err = 0; + struct sock *sk = tunnel->sock; + struct pppol2tp_ioc_stats stats_req; + + sock_hold(sk); + + PRINTK(tunnel->debug, PPPOL2TP_MSG_CONTROL, KERN_DEBUG, + "%s: pppol2tp_tunnel_ioctl(cmd=%#x, arg=%#lx)\n", tunnel->name, + cmd, arg); + + switch (cmd) { + case PPPIOCGL2TPSTATS: + err = -ENXIO; + + if (!(sk->state & PPPOX_CONNECTED)) + break; + + if (copy_from_user(&stats_req, (void *) arg, + sizeof(stats_req))) { + err = -EFAULT; + break; + } + if (stats_req.session_id != 0) { + /* resend to session ioctl handler */ + struct pppol2tp_session *session = + pppol2tp_session_find(tunnel, stats_req.session_id); + if (session != NULL) + err = pppol2tp_session_ioctl(session, cmd, arg); + else + err = -EBADR; + break; + } + if (copy_to_user((void *) arg, &tunnel->stats, + sizeof(tunnel->stats))) { + err = -EFAULT; + break; + } + PRINTK(tunnel->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO, + "%s: get L2TP stats\n", tunnel->name); + err = 0; + break; + + default: + err = -ENOSYS; + break; + } + + sock_put(sk); + + return err; +} + +/* Main ioctl() handler. + * Dispatch to tunnel or session helpers depending on the socket. + */ +static int pppol2tp_ioctl(struct socket *sock, unsigned int cmd, + unsigned long arg) +{ + struct sock *sk = sock->sk; + struct pppol2tp_session *session; + struct pppol2tp_tunnel *tunnel; + int err = 0; + + ENTER_FUNCTION; + + if (!sk) + return 0; + + if (sk->dead != 0) + return -EBADF; + + if ((sk->user_data == NULL) || + (!(sk->state & (PPPOX_CONNECTED | PPPOX_BOUND)))) { + err = -ENOTCONN; + DPRINTK(-1, "ioctl: socket %p not connected.\n", sk); + goto end; + } + + SOCK_2_SESSION(sk, session, err, -EBADF, end, 0); + SOCK_2_TUNNEL(session->tunnel_sock, tunnel, err, -EBADF, end, 1); + + /* Special case: if session's session_id is zero, treat ioctl as a + * tunnel ioctl + */ + if ((session->tunnel_addr.s_session == 0) && + (session->tunnel_addr.d_session == 0)) { + err = pppol2tp_tunnel_ioctl(tunnel, cmd, arg); + goto end; + } + + err = pppol2tp_session_ioctl(session, cmd, arg); + +end: + EXIT_FUNCTION; + return err; +} + +/***************************************************************************** + * setsockopt() / getsockopt() support. + * + * The PPPoX socket is created for L2TP sessions: tunnels have their own UDP + * sockets. In order to control kernel tunnel features, we allow userspace to + * create a special "tunnel" PPPoX socket which is used for control only. + * Tunnel PPPoX sockets have session_id == 0 and simply allow the user + * application to issue L2TP setsockopt(), getsockopt() and ioctl() calls. + *****************************************************************************/ + +/* Tunnel setsockopt() helper. + */ +static int pppol2tp_tunnel_setsockopt(struct sock *sk, + struct pppol2tp_tunnel *tunnel, + int optname, int val) +{ + int err = 0; + + switch (optname) { + case PPPOL2TP_SO_DEBUG: + tunnel->debug = val; + PRINTK(tunnel->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO, + "%s: set debug=%x\n", tunnel->name, tunnel->debug); + break; + + default: + err = -ENOPROTOOPT; + break; + } + + return err; +} + +/* Session setsockopt helper. + */ +static int pppol2tp_session_setsockopt(struct sock *sk, + struct pppol2tp_session *session, + int optname, int val) +{ + int err = 0; + + switch (optname) { + case PPPOL2TP_SO_RECVSEQ: + if ((val != 0) && (val != 1)) { + err = -EINVAL; + break; + } + session->recv_seq = val ? -1 : 0; + PRINTK(session->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO, + "%s: set recv_seq=%d\n", session->name, + session->recv_seq); + break; + + case PPPOL2TP_SO_SENDSEQ: + if ((val != 0) && (val != 1)) { + err = -EINVAL; + break; + } + session->send_seq = val ? -1 : 0; + { + /* FIXME: is it safe to change the ppp channel's + * hdrlen on the fly? + */ + struct sock *sk = session->sock; + struct pppox_opt *po = sk->protinfo.pppox; + po->chan.hdrlen = val ? PPPOL2TP_L2TP_HDR_SIZE_SEQ : + PPPOL2TP_L2TP_HDR_SIZE_NOSEQ; + } + PRINTK(session->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO, + "%s: set send_seq=%d\n", session->name, session->send_seq); + break; + + case PPPOL2TP_SO_LNSMODE: + if ((val != 0) && (val != 1)) { + err = -EINVAL; + break; + } + session->lns_mode = val ? -1 : 0; + PRINTK(session->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO, + "%s: set lns_mode=%d\n", session->name, + session->lns_mode); + break; + + case PPPOL2TP_SO_DEBUG: + session->debug = val; + PRINTK(session->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO, + "%s: set debug=%x\n", session->name, session->debug); + break; + + case PPPOL2TP_SO_REORDERTO: + session->reorder_timeout = MS_TO_JIFFIES(val); + PRINTK(session->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO, + "%s: set reorder_timeout=%d\n", session->name, + session->reorder_timeout); + break; + + default: + err = -ENOPROTOOPT; + break; + } + + return err; +} + +/* Main setsockopt() entry point. + * Does API checks, then calls either the tunnel or session setsockopt + * handler, according to whether the PPPoL2TP socket is a for a regular + * session or the special tunnel type. + */ +static int pppol2tp_setsockopt(struct socket *sock, int level, int optname, + char *optval, int optlen) +{ + struct sock *sk = sock->sk; + struct pppol2tp_session *session = sk->user_data; + struct pppol2tp_tunnel *tunnel; + int val; + int err = 0; + + if (level != SOL_PPPOL2TP) + return udp_prot.setsockopt(sk, level, optname, optval, optlen); + + if (optlenuser_data == NULL) { + err = -ENOTCONN; + DPRINTK(-1, "setsockopt: socket %p not connected.\n", sk); + goto end; + } + + SOCK_2_SESSION(sk, session, err, -EBADF, end, 0); + SOCK_2_TUNNEL(session->tunnel_sock, tunnel, err, -EBADF, end, 1); + + lock_sock(sk); + + /* Special case: if session_id == 0x0000, treat as operation on tunnel + */ + if ((session->tunnel_addr.s_session == 0) && + (session->tunnel_addr.d_session == 0)) + err = pppol2tp_tunnel_setsockopt(sk, tunnel, optname, val); + else + err = pppol2tp_session_setsockopt(sk, session, optname, val); + + release_sock(sk); +end: + return err; +} + +/* Tunnel getsockopt helper. + */ +static int pppol2tp_tunnel_getsockopt(struct sock *sk, + struct pppol2tp_tunnel *tunnel, + int optname, int *val) +{ + int err = 0; + + switch (optname) { + case PPPOL2TP_SO_DEBUG: + *val = tunnel->debug; + PRINTK(tunnel->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO, + "%s: get debug=%x\n", tunnel->name, tunnel->debug); + break; + + default: + err = -ENOPROTOOPT; + break; + } + + return err; +} + +/* Session getsockopt helper. + */ +static int pppol2tp_session_getsockopt(struct sock *sk, + struct pppol2tp_session *session, + int optname, int *val) +{ + int err = 0; + + switch (optname) { + case PPPOL2TP_SO_RECVSEQ: + *val = session->recv_seq; + PRINTK(session->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO, + "%s: get recv_seq=%d\n", session->name, *val); + break; + + case PPPOL2TP_SO_SENDSEQ: + *val = session->send_seq; + PRINTK(session->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO, + "%s: get send_seq=%d\n", session->name, *val); + break; + + case PPPOL2TP_SO_LNSMODE: + *val = session->lns_mode; + PRINTK(session->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO, + "%s: get lns_mode=%d\n", session->name, *val); + break; + + case PPPOL2TP_SO_DEBUG: + *val = session->debug; + PRINTK(session->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO, + "%s: get debug=%d\n", session->name, *val); + break; + + case PPPOL2TP_SO_REORDERTO: + *val = JIFFIES_TO_MS(session->reorder_timeout); + PRINTK(session->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO, + "%s: get reorder_timeout=%d\n", session->name, *val); + break; + + default: + err = -ENOPROTOOPT; + } + + return err; +} + +/* Main getsockopt() entry point. + * Does API checks, then calls either the tunnel or session getsockopt + * handler, according to whether the PPPoX socket is a for a regular session + * or the special tunnel type. + */ +static int pppol2tp_getsockopt(struct socket *sock, int level, + int optname, char *optval, int *optlen) +{ + struct sock *sk = sock->sk; + struct pppol2tp_session *session = sk->user_data; + struct pppol2tp_tunnel *tunnel; + int val, len; + int err = 0; + + if (level != SOL_PPPOL2TP) + return udp_prot.getsockopt(sk, level, optname, optval, optlen); + + if (get_user(len,optlen)) + return -EFAULT; + + len = min_t(unsigned int, len, sizeof(int)); + + if (len < 0) + return -EINVAL; + + if (sk->user_data == NULL) { + err = -ENOTCONN; + DPRINTK(-1, "getsockopt: socket %p not connected.\n", sk); + goto end; + } + + /* Get the session and tunnel contexts */ + SOCK_2_SESSION(sk, session, err, -EBADF, end, 0); + SOCK_2_TUNNEL(session->tunnel_sock, tunnel, err, -EBADF, end, 1); + + /* Special case: if session_id == 0x0000, treat as operation on tunnel */ + if ((session->tunnel_addr.s_session == 0) && + (session->tunnel_addr.d_session == 0)) + err = pppol2tp_tunnel_getsockopt(sk,tunnel, optname, &val); + else + err = pppol2tp_session_getsockopt(sk,session, optname, &val); + + if (put_user(len, optlen)) + return -EFAULT; + + if (copy_to_user(optval, &val, len)) + return -EFAULT; + +end: + return err; +} + +/***************************************************************************** + * /proc filesystem for debug + *****************************************************************************/ + +#ifdef CONFIG_PROC_FS + +#include + +static int pppol2tp_proc_open(struct inode *inode, struct file *file); +static void *pppol2tp_proc_start(struct seq_file *m, loff_t *_pos); +static void *pppol2tp_proc_next(struct seq_file *p, void *v, loff_t *pos); +static void pppol2tp_proc_stop(struct seq_file *p, void *v); +static int pppol2tp_proc_show(struct seq_file *m, void *v); + +static struct proc_dir_entry *pppol2tp_proc; + +static struct seq_operations pppol2tp_proc_ops = { + .start = pppol2tp_proc_start, + .next = pppol2tp_proc_next, + .stop = pppol2tp_proc_stop, + .show = pppol2tp_proc_show, +}; + +static struct file_operations pppol2tp_proc_fops = { + .open = pppol2tp_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,26)) +static inline struct proc_dir_entry *PDE(const struct inode *inode) +{ + return (struct proc_dir_entry *)inode->u.generic_ip; +} +#endif + +static int pppol2tp_proc_open(struct inode *inode, struct file *file) +{ + struct seq_file *m; + int ret = 0; + + ENTER_FUNCTION; + ret = seq_open(file, &pppol2tp_proc_ops); + if (ret < 0) + goto out; + + m = file->private_data; + m->private = PDE(inode)->data; + +out: + EXIT_FUNCTION; + return ret; +} + +static void *pppol2tp_proc_start(struct seq_file *m, loff_t *_pos) +{ + struct pppol2tp_tunnel *tunnel = NULL; + loff_t pos = *_pos; + struct list_head *walk; + struct list_head *tmp; + + ENTER_FUNCTION; + + /* allow for the header line */ + if (!pos) { + tunnel = (void *)1; + goto out; + } + pos--; + + /* find the n'th element in the list */ + list_for_each_safe(walk, tmp, &pppol2tp_tunnel_list) { + tunnel = list_entry(walk, struct pppol2tp_tunnel, list); + if (!pos--) { + sock_hold(tunnel->sock); + goto out; + } + } + tunnel = NULL; + +out: + EXIT_FUNCTION; + + return tunnel; +} + +static void *pppol2tp_proc_next(struct seq_file *p, void *v, loff_t *pos) +{ + struct pppol2tp_tunnel *tunnel = v; + struct list_head *tmp; + struct list_head *list; + + ENTER_FUNCTION; + + (*pos)++; + + if (v == (void *)1) + list = &pppol2tp_tunnel_list; + else + list = &tunnel->list; + + tmp = list->next; + if (tmp == &pppol2tp_tunnel_list) + tunnel = NULL; + else + tunnel = list_entry(tmp, struct pppol2tp_tunnel, list); + + EXIT_FUNCTION; + + return tunnel; +} + +static void pppol2tp_proc_stop(struct seq_file *p, void *v) +{ + struct pppol2tp_tunnel *tunnel = v; + + ENTER_FUNCTION; + + if (tunnel != NULL) + sock_put(tunnel->sock); + + EXIT_FUNCTION; +} + +static int pppol2tp_proc_show(struct seq_file *m, void *v) +{ + struct pppol2tp_tunnel *tunnel = v; + struct pppol2tp_session *session; + struct hlist_node *walk; + struct hlist_node *tmp; + int i; + + ENTER_FUNCTION; + + /* display header on line 1 */ + if (v == (void *)1) { + seq_puts(m, "PPPoL2TP driver info, " PPPOL2TP_DRV_VERSION "\n"); + seq_puts(m, "TUNNEL name, user-data-ok " + "session-count magic-ok\n"); + seq_puts(m, " debug tx-pkts/bytes/errs rx-pkts/bytes/errs\n"); + seq_puts(m, " SESSION name, addr/port src-tid/sid " + "dest-tid/sid state user-data-ok magic-ok\n"); + seq_puts(m, " mtu/mru/rcvseq/sendseq/lns debug reorderto\n"); + seq_puts(m, " nr/ns tx-pkts/bytes/errs rx-pkts/bytes/errs\n"); + goto out; + } + + seq_printf(m, "TUNNEL '%s', %c %d MAGIC %s\n", + tunnel->name, + (tunnel == tunnel->sock->user_data) ? 'Y':'N', + atomic_read(&tunnel->session_count), + (tunnel->magic == L2TP_TUNNEL_MAGIC) ? "OK" : "BAD"); + seq_printf(m, " %08x %llu/%llu/%llu %llu/%llu/%llu\n", + tunnel->debug, + tunnel->stats.tx_packets, tunnel->stats.tx_bytes, + tunnel->stats.tx_errors, + tunnel->stats.rx_packets, tunnel->stats.rx_bytes, + tunnel->stats.rx_errors); + + if (tunnel->magic != L2TP_TUNNEL_MAGIC) { + seq_puts(m, "*** Aborting ***\n"); + goto out; + } + + for (i = 0; i < PPPOL2TP_HASH_SIZE; i++) { + hlist_for_each_safe(walk, tmp, &tunnel->session_hlist[i]) { + session = hlist_entry(walk, struct pppol2tp_session, hlist); + seq_printf(m, " SESSION '%s' %08X/%d %04X/%04X -> " + "%04X/%04X %d %c MAGIC %s\n", + session->name, + htonl(session->tunnel_addr.addr.sin_addr.s_addr), + htons(session->tunnel_addr.addr.sin_port), + session->tunnel_addr.s_tunnel, + session->tunnel_addr.s_session, + session->tunnel_addr.d_tunnel, + session->tunnel_addr.d_session, + session->sock->state, + (session == session->sock->user_data) ? + 'Y' : 'N', + (session->magic == L2TP_SESSION_MAGIC) ? + "OK" : "BAD"); + + seq_printf(m, " %d/%d/%c/%c/%s %08x %d\n", + session->mtu, session->mru, + session->recv_seq ? 'R' : '-', + session->send_seq ? 'S' : '-', + session->lns_mode ? "LNS" : "LAC", + session->debug, + JIFFIES_TO_MS(session->reorder_timeout)); + seq_printf(m, " %hu/%hu %llu/%llu/%llu %llu/%llu/%llu\n", + session->nr, session->ns, + session->stats.tx_packets, + session->stats.tx_bytes, + session->stats.tx_errors, + session->stats.rx_packets, + session->stats.rx_bytes, + session->stats.rx_errors); + + if (session->magic != L2TP_SESSION_MAGIC) { + seq_puts(m, "*** Aborting ***\n"); + goto out; + } + } + } +out: + seq_puts(m, "\n"); + + EXIT_FUNCTION; + + return 0; +} + +#endif /* CONFIG_PROC_FS */ + +/***************************************************************************** + * Init and cleanup + *****************************************************************************/ + +static struct proto_ops pppol2tp_ops = { + .family = AF_PPPOX, + .release = pppol2tp_release, + .bind = sock_no_bind, + .connect = pppol2tp_connect, + .socketpair = sock_no_socketpair, + .accept = sock_no_accept, + .getname = pppol2tp_getname, + .poll = datagram_poll, + .listen = sock_no_listen, + .shutdown = sock_no_shutdown, + .setsockopt = pppol2tp_setsockopt, + .getsockopt = pppol2tp_getsockopt, + .sendmsg = pppol2tp_sendmsg, + .recvmsg = pppol2tp_recvmsg, + .mmap = sock_no_mmap +}; + +struct pppox_proto pppol2tp_proto = { + .create = pppol2tp_create, + .ioctl = pppol2tp_ioctl +}; + +int __init pppol2tp_init(void) +{ + int err = register_pppox_proto(PX_PROTO_OL2TP, &pppol2tp_proto); + + if (err == 0) { +#ifdef CONFIG_PROC_FS + pppol2tp_proc = create_proc_entry("pppol2tp", 0, proc_net); + if (!pppol2tp_proc) { + return -ENOMEM; + } + pppol2tp_proc->owner = THIS_MODULE; + pppol2tp_proc->proc_fops = &pppol2tp_proc_fops; +#endif /* CONFIG_PROC_FS */ + printk(KERN_INFO "PPPoL2TP kernel driver, %s\n", + PPPOL2TP_DRV_VERSION); + } + + return err; +} + +void __exit pppol2tp_exit(void) +{ + unregister_pppox_proto(PX_PROTO_OL2TP); +#ifdef CONFIG_PROC_FS + remove_proc_entry("pppol2tp", proc_net); +#endif +#ifdef DEBUG_MOD_USE_COUNT + printk(KERN_DEBUG "%s: module use_count is %d\n", __FUNCTION__, mod_use_count); +#endif +} + +module_init(pppol2tp_init); +module_exit(pppol2tp_exit); + +MODULE_AUTHOR("Martijn van Oosterhout "); +MODULE_DESCRIPTION("PPP over L2TP over UDP, " PPPOL2TP_DRV_VERSION); +MODULE_LICENSE("GPL"); Index: linux-2.4.27-l2tp/drivers/net/pppox.c =================================================================== --- linux-2.4.27-l2tp.orig/drivers/net/pppox.c +++ linux-2.4.27-l2tp/drivers/net/pppox.c @@ -121,10 +121,17 @@ static int pppox_create(struct socket *s int err = 0; if (protocol < 0 || protocol > PX_MAX_PROTO) - return -EPROTOTYPE; + return -EPROTOTYPE; +#ifdef CONFIG_KMOD + if (proto[protocol] == NULL) { + char buffer[32]; + sprintf(buffer, "pppox-proto-%d", protocol); + request_module(buffer); + } +#endif if (proto[protocol] == NULL) - return -EPROTONOSUPPORT; + return -EPROTONOSUPPORT; err = (*proto[protocol]->create)(sock); Index: linux-2.4.27-l2tp/include/linux/hash.h =================================================================== --- /dev/null +++ linux-2.4.27-l2tp/include/linux/hash.h @@ -0,0 +1,58 @@ +#ifndef _LINUX_HASH_H +#define _LINUX_HASH_H +/* Fast hashing routine for a long. + (C) 2002 William Lee Irwin III, IBM */ + +/* + * Knuth recommends primes in approximately golden ratio to the maximum + * integer representable by a machine word for multiplicative hashing. + * Chuck Lever verified the effectiveness of this technique: + * http://www.citi.umich.edu/techreports/reports/citi-tr-00-1.pdf + * + * These primes are chosen to be bit-sparse, that is operations on + * them can use shifts and additions instead of multiplications for + * machines where multiplications are slow. + */ +#if BITS_PER_LONG == 32 +/* 2^31 + 2^29 - 2^25 + 2^22 - 2^19 - 2^16 + 1 */ +#define GOLDEN_RATIO_PRIME 0x9e370001UL +#elif BITS_PER_LONG == 64 +/* 2^63 + 2^61 - 2^57 + 2^54 - 2^51 - 2^18 + 1 */ +#define GOLDEN_RATIO_PRIME 0x9e37fffffffc0001UL +#else +#error Define GOLDEN_RATIO_PRIME for your wordsize. +#endif + +static inline unsigned long hash_long(unsigned long val, unsigned int bits) +{ + unsigned long hash = val; + +#if BITS_PER_LONG == 64 + /* Sigh, gcc can't optimise this alone like it does for 32 bits. */ + unsigned long n = hash; + n <<= 18; + hash -= n; + n <<= 33; + hash -= n; + n <<= 3; + hash += n; + n <<= 3; + hash -= n; + n <<= 4; + hash += n; + n <<= 2; + hash += n; +#else + /* On some cpus multiply is faster, on others gcc will do shifts */ + hash *= GOLDEN_RATIO_PRIME; +#endif + + /* High bits are more random, so use them. */ + return hash >> (BITS_PER_LONG - bits); +} + +static inline unsigned long hash_ptr(void *ptr, unsigned int bits) +{ + return hash_long((unsigned long)ptr, bits); +} +#endif /* _LINUX_HASH_H */ Index: linux-2.4.27-l2tp/include/linux/if_ppp.h =================================================================== --- linux-2.4.27-l2tp.orig/include/linux/if_ppp.h +++ linux-2.4.27-l2tp/include/linux/if_ppp.h @@ -107,6 +107,21 @@ struct ifpppcstatsreq { struct ppp_comp_stats stats; }; +/* For PPPIOCGL2TPSTATS */ +struct pppol2tp_ioc_stats { + __u16 tunnel_id; /* redundant */ + __u16 session_id; /* if zero, get tunnel stats */ + __u64 tx_packets; + __u64 tx_bytes; + __u64 tx_errors; + __u64 rx_packets; + __u64 rx_bytes; + __u64 rx_seq_discards; + __u64 rx_oos_packets; + __u64 rx_errors; + int using_ipsec; /* valid only for session_id == 0 */ +}; + #define ifr__name b.ifr_ifrn.ifrn_name #define stats_ptr b.ifr_ifru.ifru_data @@ -143,6 +158,7 @@ struct ifpppcstatsreq { #define PPPIOCDISCONN _IO('t', 57) /* disconnect channel */ #define PPPIOCATTCHAN _IOW('t', 56, int) /* attach to ppp channel */ #define PPPIOCGCHAN _IOR('t', 55, int) /* get ppp channel number */ +#define PPPIOCGL2TPSTATS _IOR('t', 54, struct pppol2tp_ioc_stats) #define SIOCGPPPSTATS (SIOCDEVPRIVATE + 0) #define SIOCGPPPVER (SIOCDEVPRIVATE + 1) /* NEVER change this!! */ Index: linux-2.4.27-l2tp/include/linux/if_pppol2tp.h =================================================================== --- /dev/null +++ linux-2.4.27-l2tp/include/linux/if_pppol2tp.h @@ -0,0 +1,67 @@ +/*************************************************************************** + * Linux PPP over L2TP (PPPoL2TP) Socket Implementation (RFC 2661) + * + * This file supplies definitions required by the PPP over L2TP driver + * (pppol2tp.c). All version information wrt this file is located in pppol2tp.c + * + * License: + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + */ + +#ifndef __LINUX_IF_PPPOL2TP_H +#define __LINUX_IF_PPPOL2TP_H + +#include + +#ifdef __KERNEL__ +#include +#endif + +/* Structure used to bind() the socket to a particular socket & tunnel */ +struct pppol2tp_addr +{ + pid_t pid; /* pid that owns the fd. + * 0 => current */ + int fd; /* FD of UDP socket to use */ + + struct sockaddr_in addr; /* IP address and port to send to */ + + __u16 s_tunnel, s_session; /* For matching incoming packets */ + __u16 d_tunnel, d_session; /* For sending outgoing packets */ +}; + +/* Socket options: + * DEBUG - bitmask of debug message categories + * SENDSEQ - 0 => don't send packets with sequence numbers + * 1 => send packets with sequence numbers + * RECVSEQ - 0 => receive packet sequence numbers are optional + * 1 => drop receive packets without sequence numbers + * LNSMODE - 0 => act as LAC. + * 1 => act as LNS. + * REORDERTO - reorder timeout (in millisecs). If 0, don't try to reorder. + */ +enum { + PPPOL2TP_SO_DEBUG = 1, + PPPOL2TP_SO_RECVSEQ = 2, + PPPOL2TP_SO_SENDSEQ = 3, + PPPOL2TP_SO_LNSMODE = 4, + PPPOL2TP_SO_REORDERTO = 5, +}; + +/* Debug message categories for the DEBUG socket option */ +enum { + PPPOL2TP_MSG_DEBUG = (1 << 0), /* verbose debug (if + * compiled in) */ + PPPOL2TP_MSG_CONTROL = (1 << 1), /* userspace - kernel + * interface */ + PPPOL2TP_MSG_SEQ = (1 << 2), /* sequence numbers */ + PPPOL2TP_MSG_DATA = (1 << 3), /* data packets */ +}; + + + +#endif Index: linux-2.4.27-l2tp/include/linux/if_pppox.h =================================================================== --- linux-2.4.27-l2tp.orig/include/linux/if_pppox.h +++ linux-2.4.27-l2tp/include/linux/if_pppox.h @@ -1,6 +1,6 @@ /*************************************************************************** * Linux PPP over X - Generic PPP transport layer sockets - * Linux PPP over Ethernet (PPPoE) Socket Implementation (RFC 2516) + * Linux PPP over Ethernet (PPPoE) Socket Implementation (RFC 2516) * * This file supplies definitions required by the PPP over Ethernet driver * (pppox.c). All version information wrt this file is located in pppox.c @@ -28,6 +28,7 @@ #include #include #endif /* __KERNEL__ */ +#include /* For user-space programs to pick up these definitions * which they wouldn't get otherwise without defining __KERNEL__ @@ -37,30 +38,48 @@ #define PF_PPPOX AF_PPPOX #endif /* !(AF_PPPOX) */ -/************************************************************************ - * PPPoE addressing definition - */ -typedef __u16 sid_t; -struct pppoe_addr{ - sid_t sid; /* Session identifier */ - unsigned char remote[ETH_ALEN]; /* Remote address */ - char dev[IFNAMSIZ]; /* Local device to use */ -}; - -/************************************************************************ - * Protocols supported by AF_PPPOX - */ +/************************************************************************ + * PPPoE addressing definition + */ +typedef __u16 sid_t; +struct pppoe_addr{ + sid_t sid; /* Session identifier */ + unsigned char remote[ETH_ALEN]; /* Remote address */ + char dev[IFNAMSIZ]; /* Local device to use */ +}; + +/************************************************************************ + * Protocols supported by AF_PPPOX + */ #define PX_PROTO_OE 0 /* Currently just PPPoE */ -#define PX_MAX_PROTO 1 - -struct sockaddr_pppox { - sa_family_t sa_family; /* address family, AF_PPPOX */ - unsigned int sa_protocol; /* protocol identifier */ - union{ - struct pppoe_addr pppoe; - }sa_addr; -}__attribute__ ((packed)); +#define PX_PROTO_OL2TP 1 /* Now L2TP also */ +#define PX_MAX_PROTO 2 +/* The use of a union isn't viable because the size of this struct + * must stay fixed over time -- applications use sizeof(struct + * sockaddr_pppox) to fill it. Use protocol specific sockaddr types + * instead. + */ +struct sockaddr_pppox { + sa_family_t sa_family; /* address family, AF_PPPOX */ + unsigned int sa_protocol; /* protocol identifier */ + union{ + struct pppoe_addr pppoe; + }sa_addr; +}__attribute__ ((packed)); /* deprecated */ + +/* Must be binary-compatible with sockaddr_pppox for backwards compatabilty */ +struct sockaddr_pppoe { + sa_family_t sa_family; /* address family, AF_PPPOX */ + unsigned int sa_protocol; /* protocol identifier */ + struct pppoe_addr pppoe; +}__attribute__ ((packed)); + +struct sockaddr_pppol2tp { + sa_family_t sa_family; /* address family, AF_PPPOX */ + unsigned int sa_protocol; /* protocol identifier */ + struct pppol2tp_addr pppol2tp; +}__attribute__ ((packed)); /********************************************************************* * Index: linux-2.4.27-l2tp/include/linux/list.h =================================================================== --- linux-2.4.27-l2tp.orig/include/linux/list.h +++ linux-2.4.27-l2tp/include/linux/list.h @@ -3,7 +3,9 @@ #if defined(__KERNEL__) || defined(_LVM_H_INCLUDE) +#include #include +#include /* * Simple doubly linked list implementation. @@ -254,6 +256,159 @@ static inline void list_splice_init(stru pos = list_entry(pos->member.next, typeof(*pos), member), \ prefetch(pos->member.next)) +/* + * These are non-NULL pointers that will result in page faults + * under normal circumstances, used to verify that nobody uses + * non-initialized list entries. + */ +#define LIST_POISON1 ((void *) 0x00100100) +#define LIST_POISON2 ((void *) 0x00200200) + +/* + * Double linked lists with a single pointer list head. + * Mostly useful for hash tables where the two pointer list head is + * too wasteful. + * You lose the ability to access the tail in O(1). + */ + +struct hlist_head { + struct hlist_node *first; +}; + +struct hlist_node { + struct hlist_node *next, **pprev; +}; + +#define HLIST_HEAD_INIT { .first = NULL } +#define HLIST_HEAD(name) struct hlist_head name = { .first = NULL } +#define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL) +#define INIT_HLIST_NODE(ptr) ((ptr)->next = NULL, (ptr)->pprev = NULL) + +static inline int hlist_unhashed(const struct hlist_node *h) +{ + return !h->pprev; +} + +static inline int hlist_empty(const struct hlist_head *h) +{ + return !h->first; +} + +static inline void __hlist_del(struct hlist_node *n) +{ + struct hlist_node *next = n->next; + struct hlist_node **pprev = n->pprev; + *pprev = next; + if (next) + next->pprev = pprev; +} + +static inline void hlist_del(struct hlist_node *n) +{ + __hlist_del(n); + n->next = LIST_POISON1; + n->pprev = LIST_POISON2; +} + +static inline void hlist_del_init(struct hlist_node *n) +{ + if (n->pprev) { + __hlist_del(n); + INIT_HLIST_NODE(n); + } +} + +static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h) +{ + struct hlist_node *first = h->first; + n->next = first; + if (first) + first->pprev = &n->next; + h->first = n; + n->pprev = &h->first; +} + +/* next must be != NULL */ +static inline void hlist_add_before(struct hlist_node *n, + struct hlist_node *next) +{ + n->pprev = next->pprev; + n->next = next; + next->pprev = &n->next; + *(n->pprev) = n; +} + +static inline void hlist_add_after(struct hlist_node *n, + struct hlist_node *next) +{ + next->next = n->next; + n->next = next; + next->pprev = &n->next; + + if(next->next) + next->next->pprev = &next->next; +} + +#define hlist_entry(ptr, type, member) container_of(ptr,type,member) + +#define hlist_for_each(pos, head) \ + for (pos = (head)->first; pos && ({ prefetch(pos->next); 1; }); \ + pos = pos->next) + +#define hlist_for_each_safe(pos, n, head) \ + for (pos = (head)->first; pos && ({ n = pos->next; 1; }); \ + pos = n) + +/** + * hlist_for_each_entry - iterate over list of given type + * @tpos: the type * to use as a loop counter. + * @pos: the &struct hlist_node to use as a loop counter. + * @head: the head for your list. + * @member: the name of the hlist_node within the struct. + */ +#define hlist_for_each_entry(tpos, pos, head, member) \ + for (pos = (head)->first; \ + pos && ({ prefetch(pos->next); 1;}) && \ + ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ + pos = pos->next) + +/** + * hlist_for_each_entry_continue - iterate over a hlist continuing after existing point + * @tpos: the type * to use as a loop counter. + * @pos: the &struct hlist_node to use as a loop counter. + * @member: the name of the hlist_node within the struct. + */ +#define hlist_for_each_entry_continue(tpos, pos, member) \ + for (pos = (pos)->next; \ + pos && ({ prefetch(pos->next); 1;}) && \ + ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ + pos = pos->next) + +/** + * hlist_for_each_entry_from - iterate over a hlist continuing from existing point + * @tpos: the type * to use as a loop counter. + * @pos: the &struct hlist_node to use as a loop counter. + * @member: the name of the hlist_node within the struct. + */ +#define hlist_for_each_entry_from(tpos, pos, member) \ + for (; pos && ({ prefetch(pos->next); 1;}) && \ + ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ + pos = pos->next) + +/** + * hlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry + * @tpos: the type * to use as a loop counter. + * @pos: the &struct hlist_node to use as a loop counter. + * @n: another &struct hlist_node to use as temporary storage + * @head: the head for your list. + * @member: the name of the hlist_node within the struct. + */ +#define hlist_for_each_entry_safe(tpos, pos, n, head, member) \ + for (pos = (head)->first; \ + pos && ({ n = pos->next; 1; }) && \ + ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ + pos = n) + #endif /* __KERNEL__ || _LVM_H_INCLUDE */ #endif Index: linux-2.4.27-l2tp/include/linux/socket.h =================================================================== --- linux-2.4.27-l2tp.orig/include/linux/socket.h +++ linux-2.4.27-l2tp/include/linux/socket.h @@ -259,6 +259,7 @@ struct ucred { #define SOL_IRDA 266 #define SOL_NETBEUI 267 #define SOL_LLC 268 +#define SOL_PPPOL2TP 269 /* IPX options */ #define IPX_TYPE 1 xl2tpd-1.3.16/contrib/pppol2tp-linux-2.4.27.patch.README000066400000000000000000000001271374460464600221170ustar00rootroot00000000000000NOTE: This patch currently does not work together with xl2tpd's "ipsec saref" option. xl2tpd-1.3.16/contrib/system_tray/000077500000000000000000000000001374460464600170605ustar00rootroot00000000000000xl2tpd-1.3.16/contrib/system_tray/REAME.txt000066400000000000000000000020341374460464600204510ustar00rootroot00000000000000This program read xl2tpd log file and show status icon in system tray. To compile it name file main.cpp and execute command in terminal. g++ `pkg-config --cflags --libs gtk+-2.0` main.cpp -o xl2tpd-tray-icon then copy xl2tpd-tray-icon to directory /usr/bin then copy 4 image files (connect.png, disconnect.png, online.png, offline.png) to directory /usr/share/xl2tpd-tray-icon then make file /etc/xdg/autostart/xl2tpd-tray-icon.desktop with content [Desktop Entry] Name=xl2tpd-tray-icon Exec=xl2tpd-tray-icon Terminal=false Type=Application X-GNOME-Autostart-enabled=true after reboot program will start automatically. ----- Images are from Openclipart (Creative Commons Zero 1.0 Public Domain License) and Pixabay (Free for commerical use. No attribution required) https://openclipart.org/detail/198745/mono-tool-offline-mode-off https://openclipart.org/detail/198746/mono-tool-offline-mode-on https://pixabay.com/en/connection-broken-network-98523/ https://pixabay.com/en/network-computer-workstations-lan-98522/ xl2tpd-1.3.16/contrib/system_tray/connect.png000066400000000000000000000047321374460464600212250ustar00rootroot00000000000000PNG  IHDR szzgAMA a cHRMz&u0`:pQ<bKGDtIME  AoIDATXÍW[lsz}_v/(A@QHm%T6O7D UmShZ!ZPUBjA<qkNM8"/z94pg5sf6gA^?=B 0Nsr\xO/`f!J{0~2܊ jM }ypGوWV=11b{mR* tp5< wVWqlct{ϟjRPH ad`tӴ(Ek=@gnnv q;BH)rR h$H(J{vO8vc$c&+nZPշrBHh$!IЕnED~~")۝s=q}ᜇ5xOa-$RDPڸ X,"ffR W!Z֐@`g!Go1Shf- 0ԻI}E7= ٳyRKN_[367cߛF5 @P kȂluve`A.u+19" PJ"4m QdS"+ 2pXZZh6Qoz(u4 R@k usiw\2BLW/t&# jXlmP.oшEc8!%Ak t R[D hiTykqlan{lo7f33HBk8pց@d* $Ck }j-8Ibww*k*j`fhHf-#1:/awf%B ; T_B$ [[541 gD 0Ij(r]B6,!ScWWa`:qĻ=MMM Gp`^`G驗6IT*( 2T*1IW7\8:;U.GoA!v+8EtFbqG4j.=䓿j4׈Ȩfp᧗/_V666FHCCCG@JΪ['bVsZihP-`ph}Es!@6A 3,ff&ܷ-B= po?R*zzل֦5AyrrҖJl6Zh4ι5LVDkW1[YYI}<zyiil}ccѨ^zGK196>\. Z4+++~ ,/.:::z}zz:>t萘_Be{8wo-@.&#”{1Xky`=+G1w0R.,;S@D ̌Qk]q_VgZp[~p4y! *@IZݔ @La B."jF`fݷ7} @`l|N)p"j0=%$q }ξ~v'য়~P,Oy"D7}Uܞ^5ƈ8N&KãbyyKaȚ* %tEXtdate:create2019-02-13T14:18:55-05:00zxBw%tEXtdate:modify2015-11-25T17:11:13-05:00IENDB`xl2tpd-1.3.16/contrib/system_tray/disconnect.png000066400000000000000000000046121374460464600217220ustar00rootroot00000000000000PNG  IHDR szzgAMA a cHRMz&u0`:pQ<bKGDtIME  2Z]IDATXÍI\WsWSwnmLAQ" $YdM$Y%RBJaXa  c7mwkxXt>wo'|SO6_}տݾmV "G 7F#VwZy~aG1ں{}1^Ilrx/V arQβvho6x)mT*j5NB7FeXJ}P@)֪2~Ni9̍F;̓e<dp%:>C""EQ)RZ9yp1"zvvX[ess EQHD.bH[ڸ7;;A'8 ܹ6V" >D(%{`zzI93+"tvTM}CpqDJQc4"Rݼ8fIeb[^SZ!3p Z Ⱦs|l,3+ 9J"C//7\vKաOI> "(e ʲm[iQ\$ 8t\f0Ȉ1"֐<IRZ)U :bPJBY*)(% y|2pjnw1bmDs.T!wnkch$HSV]PMF)UsO{ y.~1(RPeQJ=z !FKNs~՘ljU"Ζ:FsDv G!w߽(2xFax<"|s׈y>v|G>3p&Vb@)53\-EA V16Q ]BOs1 H>gGIX}y{qkkk/\ *^Onk,|gr{cOǞ}=''lw-^q+\]񉭴I W,_^w#ceqMlbEĉ+ eZ6gM:Z$I%N<o-Vl4ӟ~cGɖ=ٲRȃ>s;w-Z8N{"iF!sx(ZW;|rB\_><@ 3okRݳs`zʽ_k7p˥;WQn޴֨qݣpzyNU*t=$ٱc|!$ݾ}F[4O1aY/>,j!ĉeޫB(N#R400 }(-$A#,Ib !D@Rtl*0J&͎ڽ_+&x7lx(V2/ph\w])UODڽ^9sZm]ګz^GM"IfWz߰v~G1*t^~ig&eH|/E1^%tEXtdate:create2019-02-13T14:18:29-05:00!%tEXtdate:modify2015-11-25T17:10:50-05:00IENDB`xl2tpd-1.3.16/contrib/system_tray/main.cpp000066400000000000000000000106301374460464600205100ustar00rootroot00000000000000// reading file #include #include // trimming string #include #include #include #include // regex #include // gtk #include static std::string logfilepath = ""; // trim from start (in place) static inline void ltrim(std::string &s) { s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](int ch) { return !std::isspace(ch); })); } // trim from end (in place) static inline void rtrim(std::string &s) { s.erase(std::find_if(s.rbegin(), s.rend(), [](int ch) { return !std::isspace(ch); }).base(), s.end()); } // trim from both ends (in place) static inline void trim(std::string &s) { ltrim(s); rtrim(s); } // с++ read file to string std::string readfile(std::string filepath) { std::fstream f(filepath, std::fstream::in ); std::string s; getline( f, s, '\0'); f.close(); return s; } // c++ regex example std::string whereIsLogFile() { std::string xl2tpd=readfile("/etc/xl2tpd/xl2tpd.conf"); if (xl2tpd!="") { xl2tpd = std::regex_replace (xl2tpd, std::regex("(^|\n);[^\n]*(?=\n|$)"), ""); std::string options = ""; std::smatch match; if (std::regex_search(xl2tpd, match, std::regex("(^|\n)pppoptfile\\s*=\\s*([^\n]+)(\n|$)")) && match.size() > 1) { options=readfile(match.str(2)); if (options!="") { options = std::regex_replace (options, std::regex("(^|\n)#[^\n]*(?=\n|$)"), ""); if (std::regex_search(options, match, std::regex("(^|\n)logfile\\s*([^\n]+)(\n|$)")) && match.size() > 1) { return match.str(2); } } } } return "/home/user/beeline.xl2tpd.log"; } // c++ search string in file int get_status_from_file() { std::string s = readfile(logfilepath); // split file by string std::string delimiter = "Modem hangup"; // select last element of array size_t pos = 0; std::string token; while ((pos = s.find(delimiter)) != std::string::npos) { token = s.substr(0, pos); s.erase(0, pos + delimiter.length()); } trim(s); if (s=="") { return 0; } else { delimiter = "status = 0x0"; token = "1"; while ((pos = s.find(delimiter)) != std::string::npos) { token = "3"; s.erase(0, pos + delimiter.length()); } trim(s); if (s=="") { return 2; } if (token == "1") { return 1; } else { return 3; } } } // c++ convert gchar std::string const gchar* convertstring2gchar(std::string s) { const gchar* x; const char* cv = s.c_str(); x = (const gchar*) cv; return x; } // с++ system tray icon static gboolean updateIcon(gpointer data) { GtkStatusIcon *icon = (GtkStatusIcon*)data; int m = get_status_from_file(); std::string icon_name; std::string icontext; std::string icons_path = "/usr/share/xl2tpd-tray-icon/"; std::string ext = ".png"; switch (m) { case 0: icon_name="offline"; icontext = "Internet offline"; break; case 1: icon_name="connect"; icontext = "Trying to connect to internet"; break; case 2: icon_name="online"; icontext = "Internet works"; break; case 3: icon_name="disconnect"; icontext = "Disconnecting internet"; break; } gtk_status_icon_set_from_file (icon, convertstring2gchar(icons_path+icon_name + ext)); gtk_status_icon_set_tooltip (icon, convertstring2gchar(icontext)); return true; } static void trayIconPopup(GtkStatusIcon *status_icon, guint button, guint32 activate_time, gpointer popUpMenu) { gtk_menu_popup(GTK_MENU(popUpMenu), NULL, NULL, gtk_status_icon_position_menu, status_icon, button, activate_time); } static void trayExit(GtkMenuItem *item, gpointer user_data) { exit(0); } int main(int argc, char **argv) { gtk_init(&argc,&argv); GtkStatusIcon *icon = gtk_status_icon_new_from_file ("connect.png"); gtk_status_icon_set_visible(icon, 1); gtk_status_icon_set_tooltip(icon, "Icon"); GtkWidget *menu, *menuItemView, *menuItemExit; menu = gtk_menu_new(); menuItemExit = gtk_menu_item_new_with_label ("Exit"); gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuItemExit); gtk_widget_show_all (menu); g_signal_connect(GTK_STATUS_ICON (icon), "popup-menu", GTK_SIGNAL_FUNC (trayIconPopup), menu); g_signal_connect (G_OBJECT (menuItemExit), "activate", G_CALLBACK (trayExit), NULL); logfilepath = whereIsLogFile(); // redraw status icon every 2 seconds g_timeout_add_seconds(2, updateIcon, icon); gtk_main(); return 0; } xl2tpd-1.3.16/contrib/system_tray/offline.png000066400000000000000000000020271374460464600212110ustar00rootroot00000000000000PNG  IHDR sgAMA abKGD̿ pHYsE5E5|WtIME )[GIDATHǥYHTa89ZF$R QJ Y"T&E EUPa]1F %EvS&APEYHLѦV8Y9:ڜ)39Nw-' S$"a@F+]5E7tJ0qD:WnQOaفwlI ݲd)C z&hV(KuCə@yFp\'C gYK<03Xs1&҈bG8@ 65bn$<[wvv/TijqR ʵVc8!Ga 㱳LhzzH2Ky2G*UGaPyIHd@4RI ?&lnz+.XdS1`$G.Iı2~ܸwsՓH믤o_HJXlK[XUl*$2[9ĭ XtEXtCopyrightCC0 Public Domain Dedication http://creativecommons.org/publicdomain/zero/1.0/%tEXtdate:create2019-02-13T14:17:45-05:00Gd%tEXtdate:modify2019-02-13T14:17:41-05:00˅tEXtSoftwarewww.inkscape.org<IENDB`xl2tpd-1.3.16/contrib/system_tray/online.png000066400000000000000000000015311374460464600210520ustar00rootroot00000000000000PNG  IHDR sgAMA abKGD̿ pHYsE5E5|WtIME }IDATHMHqǿZEˍ(K "i#xC/PA]PA$P$(sYd,t0"~=u{y~{YB f2YӒ@7b0=#XF]Dx>H-G(B;T8X£a0D6Q2d@5\چJb9Ie|LM{xXh!%aaC8}4C5i!W<R^`-ռtq!A9u$a<',u,1![`?\>ʧuSZE4c*K齓Ʈ`{ش2& ~Ӂ|.ІdľB+`?^v.qy #include #include #include #include #include #include #include "l2tp.h" _u16 ppp_crc16_table[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 }; int global_serno = 1; struct buffer *new_outgoing (struct tunnel *t) { /* * Make a new outgoing control packet */ struct buffer *tmp = new_buf (MAX_RECV_SIZE); if (!tmp) return NULL; tmp->peer = t->peer; tmp->start += sizeof (struct control_hdr); tmp->len = 0; tmp->retries = 0; tmp->tunnel = t; return tmp; } inline void recycle_outgoing (struct buffer *buf, struct sockaddr_in peer) { /* * This should only be used for ZLB's! */ buf->start = buf->rstart + sizeof (struct control_hdr); buf->peer = peer; buf->len = 0; buf->retries = -1; buf->tunnel = NULL; } void add_fcs (struct buffer *buf) { _u16 fcs = PPP_INITFCS; unsigned char *c = buf->start; size_t x; for (x = 0; x < buf->len; x++) { fcs = PPP_FCS (fcs, *c); c++; } fcs = fcs ^ 0xFFFF; *c = fcs & 0xFF; c++; *c = (fcs >> 8) & 0xFF; buf->len += 2; } void add_control_hdr (struct tunnel *t, struct call *c, struct buffer *buf) { struct control_hdr *h; buf->start -= sizeof (struct control_hdr); buf->len += sizeof (struct control_hdr); h = (struct control_hdr *) buf->start; h->ver = htons (TBIT | LBIT | FBIT | VER_L2TP); h->length = htons ((_u16) buf->len); h->tid = htons (t->tid); h->cid = htons (c->cid); h->Ns = htons (t->control_seq_num); h->Nr = htons (t->control_rec_seq_num); t->control_seq_num++; } void hello (void *tun) { struct buffer *buf; struct tunnel *t; struct timeval tv; tv.tv_sec = HELLO_DELAY; tv.tv_usec = 0; t = (struct tunnel *) tun; buf = new_outgoing (t); add_message_type_avp (buf, Hello); add_control_hdr (t, t->self, buf); if (gconfig.packet_dump) do_packet_dump (buf); #ifdef DEBUG_HELLO l2tp_log (LOG_DEBUG, "%s: sending Hello on %d\n", __FUNCTION__, t->ourtid); #endif control_xmit (buf); /* * Schedule another Hello in a little bit. */ #ifdef DEBUG_HELLO l2tp_log (LOG_DEBUG, "%s: scheduling another Hello on %d\n", __FUNCTION__, t->ourtid); #endif t->hello = schedule (tv, hello, (void *) t); } void control_zlb (struct buffer *buf, struct tunnel *t, struct call *c) { recycle_outgoing (buf, t->peer); add_control_hdr (t, c, buf); t->control_seq_num--; #ifdef DEBUG_ZLB l2tp_log (LOG_DEBUG, "%s: sending control ZLB on tunnel %d\n", __FUNCTION__, t->tid); #endif udp_xmit (buf, t); } /* * Get a local address from the local range, if configured. */ static int get_local_addr(struct tunnel *t, struct call *c) { #ifdef IP_ALLOCATION if (t->lns->localrange) { c->lns->localaddr = get_addr (t->lns->localrange); if (!c->lns->localaddr) { set_error (c, ERROR_NORES, "No available local IP addresses"); call_close (c); l2tp_log (LOG_DEBUG, "%s: Out of local IP addresses on tunnel %d!\n", __FUNCTION__, t->tid); return -EINVAL; } reserve_addr (c->lns->localaddr); } #endif return 0; } int control_finish (struct tunnel *t, struct call *c) { /* * After all AVP's have been handled, do anything else * which needs to be done, like prepare response * packets to go back. This is essentially the * implementation of the state machine of section 7.2.1 * * If we set c->needclose, the call (or tunnel) will * be closed upon return. */ struct buffer *buf; struct call *p, *z; struct tunnel *y; struct timeval tv; struct ppp_opts *po; char ip1[STRLEN]; char ip2[STRLEN]; char dummy_buf[128] = "/var/l2tp/"; /* jz: needed to read /etc/ppp/var.options - just kick it if you don't like */ char passwdfd_buf[32] = ""; /* buffer for the fd, not the password */ int i; int pppd_passwdfd[2]; int tmptid,tmpcid; if (c->msgtype < 0) { l2tp_log (LOG_DEBUG, "%s: Whoa... non-ZLB with no message type!\n", __FUNCTION__); return -EINVAL; } if (gconfig.debug_state) l2tp_log (LOG_DEBUG, "%s: message type is %s(%d). Tunnel is %d, call is %d.\n", __FUNCTION__, msgtypes[c->msgtype], c->msgtype, t->tid, c->cid); switch (c->msgtype) { case 0: /* * We need to initiate a connection. */ if (t->self == c) { if (t->lns) { t->ourrws = t->lns->tun_rws; t->hbit = t->lns->hbit; t->rxspeed = t->lns->rxspeed; t->txspeed = t->lns->txspeed; } else if (t->lac) { t->ourrws = t->lac->tun_rws; t->hbit = t->lac->hbit; t->rxspeed = t->lac->rxspeed; t->txspeed = t->lac->txspeed; } /* This is an attempt to bring up the tunnel */ t->state = SCCRQ; buf = new_outgoing (t); add_message_type_avp (buf, SCCRQ); if (t->hbit) { mk_challenge (t->chal_them.vector, VECTOR_SIZE); add_randvect_avp (buf, t->chal_them.vector, VECTOR_SIZE); } add_protocol_avp (buf); add_frame_caps_avp (buf, t->ourfc); add_bearer_caps_avp (buf, t->ourbc); /* FIXME: Tie breaker */ add_firmware_avp (buf); if (t->lac && t->lac->hostname && t->lac->hostname[0]) add_hostname_avp (buf, t->lac->hostname); else if (t->lns && t->lns->hostname && t->lns->hostname[0]) add_hostname_avp (buf, t->lns->hostname); else add_hostname_avp (buf, hostname); add_vendor_avp (buf); add_tunnelid_avp (buf, t->ourtid); if (t->ourrws >= 0) add_avp_rws (buf, t->ourrws); if ((t->lac && t->lac->challenge) || (t->lns && t->lns->challenge)) { if (t->chal_them.challenge) free(t->chal_them.challenge); t->chal_them.challenge = malloc(MD_SIG_SIZE); if (!(t->chal_them.challenge)) { l2tp_log (LOG_WARNING, "%s: malloc failed for challenge\n", __FUNCTION__); toss (buf); return -EINVAL; } mk_challenge (t->chal_them.challenge, MD_SIG_SIZE); t->chal_them.chal_len = MD_SIG_SIZE; add_challenge_avp (buf, t->chal_them.challenge, t->chal_them.chal_len); t->chal_them.state = STATE_CHALLENGED; /* We generate the challenge and make a note that we plan to challenge the peer, but we can't predict the response yet because we don't know their hostname AVP */ } add_control_hdr (t, c, buf); c->cnu = 0; if (gconfig.packet_dump) do_packet_dump (buf); if (gconfig.debug_state) l2tp_log (LOG_DEBUG, "%s: sending SCCRQ\n", __FUNCTION__); control_xmit (buf); } else { if (switch_io) { c->state = ICRQ; if (c->lns) { c->lbit = c->lns->lbit ? LBIT : 0; /* c->ourrws = c->lns->call_rws; if (c->ourrws > -1) c->ourfbit = FBIT; else c->ourfbit = 0; */ } else if (c->lac) { c->lbit = c->lac->lbit ? LBIT : 0; /* c->ourrws = c->lac->call_rws; if (c->ourrws > -1) c->ourfbit = FBIT; else c->ourfbit = 0; */ } buf = new_outgoing (t); add_message_type_avp (buf, ICRQ); if (t->hbit) { mk_challenge (t->chal_them.vector, VECTOR_SIZE); add_randvect_avp (buf, t->chal_them.vector, VECTOR_SIZE); } #ifdef TEST_HIDDEN add_callid_avp (buf, c->ourcid, t); #else add_callid_avp (buf, c->ourcid); #endif add_serno_avp (buf, global_serno); c->serno = global_serno; global_serno++; add_bearer_avp (buf, 0); add_control_hdr (t, c, buf); c->cnu = 0; if (gconfig.packet_dump) do_packet_dump (buf); if (gconfig.debug_state) l2tp_log (LOG_DEBUG, "%s: sending ICRQ\n", __FUNCTION__); control_xmit (buf); } else { /* jz: sending a OCRQ */ c->state = OCRQ; if (c->lns) { c->lbit = c->lns->lbit ? LBIT : 0; /* c->ourrws = c->lns->call_rws; if (c->ourrws > -1) c->ourfbit = FBIT; else c->ourfbit = 0; */ } else if (c->lac) { /* c->ourrws = c->lac->call_rws; if (c->ourrws > -1) c->ourfbit = FBIT; else c->ourfbit = 0; */ } if (t->fc & SYNC_FRAMING) c->frame = SYNC_FRAMING; else c->frame = ASYNC_FRAMING; buf = new_outgoing (t); add_message_type_avp (buf, OCRQ); #ifdef TEST_HIDDEN add_callid_avp (buf, c->ourcid, t); #else add_callid_avp (buf, c->ourcid); #endif add_serno_avp (buf, global_serno); c->serno = global_serno; global_serno++; add_minbps_avp (buf, DEFAULT_MIN_BPS); add_maxbps_avp (buf, DEFAULT_MAX_BPS); add_bearer_avp (buf, 0); add_frame_avp (buf, c->frame); add_number_avp (buf, c->dial_no); add_control_hdr (t, c, buf); c->cnu = 0; if (gconfig.packet_dump) do_packet_dump (buf); control_xmit (buf); } } break; case SCCRQ: /* * We've received a request, now let's * formulate a response. */ if (t->tid <= 0) { if (DEBUG) l2tp_log (LOG_DEBUG, "%s: Peer did not specify assigned tunnel ID. Closing.\n", __FUNCTION__); set_error (c, VENDOR_ERROR, "Specify your assigned tunnel ID"); c->needclose = -1; return -EINVAL; } if (!(t->lns = get_lns (t))) { if (DEBUG) l2tp_log (LOG_DEBUG, "%s: Denied connection to unauthorized peer %s\n", __FUNCTION__, IPADDY (t->peer.sin_addr)); set_error (c, VENDOR_ERROR, "No Authorization"); c->needclose = -1; return -EINVAL; } t->ourrws = t->lns->tun_rws; t->hbit = t->lns->hbit; if (t->fc < 0) { if (DEBUG) l2tp_log (LOG_DEBUG, "%s: Peer did not specify framing capability. Closing.\n", __FUNCTION__); set_error (c, VENDOR_ERROR, "Specify framing capability"); c->needclose = -1; return -EINVAL; } /* FIXME: Do we need to be sure they specified a version number? * Theoretically, yes, but we don't have anything in the code * to actually *do* anything with it, so...why check at this point? * We shouldn't be requiring a bearer capabilities AVP to be present in * SCCRQ and SCCRP as they aren't required if (t->bc < 0 ) { if (DEBUG) l2tp_log(LOG_DEBUG, "%s: Peer did not specify bearer capability. Closing.\n",__FUNCTION__); set_error(c, VENDOR_ERROR, "Specify bearer capability"); c->needclose = -1; return -EINVAL; } */ if ((!strlen (t->hostname)) && ((t->chal_us.state) || ((t->lns->challenge)))) { if (DEBUG) l2tp_log (LOG_DEBUG, "%s: Peer did not specify hostname. Closing.\n", __FUNCTION__); set_error (c, VENDOR_ERROR, "Specify your hostname"); c->needclose = -1; return -EINVAL; } y = tunnels.head; while (y) { if ((y->tid == t->tid) && (y->peer.sin_addr.s_addr == t->peer.sin_addr.s_addr) && (!gconfig.ipsecsaref || y->refhim == t->refhim) && (y != t)) { /* This can happen if we get a duplicate StartCCN or if they don't get our ACK packet */ /* * But it is legitimate for two different remote systems * to use the same tid */ l2tp_log (LOG_DEBUG, "%s: Peer requested tunnel %d twice, ignoring second one.\n", __FUNCTION__, t->tid); c->needclose = 0; c->closing = -1; return 0; } y = y->next; } t->state = SCCRP; buf = new_outgoing (t); add_message_type_avp (buf, SCCRP); if (t->hbit) { mk_challenge (t->chal_them.vector, VECTOR_SIZE); add_randvect_avp (buf, t->chal_them.vector, VECTOR_SIZE); } add_protocol_avp (buf); add_frame_caps_avp (buf, t->ourfc); add_bearer_caps_avp (buf, t->ourbc); add_firmware_avp (buf); if (t->lac && t->lac->hostname && t->lac->hostname[0]) add_hostname_avp (buf, t->lac->hostname); else if (t->lns && t->lns->hostname && t->lns->hostname[0]) add_hostname_avp (buf, t->lns->hostname); else add_hostname_avp (buf, hostname); add_vendor_avp (buf); add_tunnelid_avp (buf, t->ourtid); if (t->ourrws >= 0) add_avp_rws (buf, t->ourrws); if (t->chal_us.state) { t->chal_us.ss = SCCRP; handle_challenge (t, &t->chal_us); add_chalresp_avp (buf, t->chal_us.response, MD_SIG_SIZE); } if (t->lns->challenge) { if (t->chal_them.challenge) free(t->chal_them.challenge); t->chal_them.challenge = malloc(MD_SIG_SIZE); if (!(t->chal_them.challenge)) { l2tp_log (LOG_WARNING, "%s: malloc failed\n", __FUNCTION__); set_error (c, VENDOR_ERROR, "malloc failed"); toss (buf); return -EINVAL; } mk_challenge (t->chal_them.challenge, MD_SIG_SIZE); t->chal_them.chal_len = MD_SIG_SIZE; t->chal_them.ss = SCCCN; if (handle_challenge (t, &t->chal_them)) { /* We already know what to expect back */ l2tp_log (LOG_WARNING, "%s: No secret for '%s'\n", __FUNCTION__, t->hostname); set_error (c, VENDOR_ERROR, "No secret on our side"); toss (buf); return -EINVAL; }; add_challenge_avp (buf, t->chal_them.challenge, t->chal_them.chal_len); } add_control_hdr (t, c, buf); if (gconfig.packet_dump) do_packet_dump (buf); c->cnu = 0; if (gconfig.debug_state) l2tp_log (LOG_DEBUG, "%s: sending SCCRP\n", __FUNCTION__); control_xmit (buf); break; case SCCRP: /* * We have a reply. If everything is okay, send * a connected message */ if (t->fc < 0) { if (DEBUG) l2tp_log (LOG_DEBUG, "%s: Peer did not specify framing capability. Closing.\n", __FUNCTION__); set_error (c, VENDOR_ERROR, "Specify framing capability"); c->needclose = -1; return -EINVAL; } /* FIXME: Do we need to be sure they specified a version number? * Theoretically, yes, but we don't have anything in the code * to actually *do* anything with it, so...why check at this point? * We shouldn't be requiring a bearer capabilities AVP to be present in * SCCRQ and SCCRP as they aren't required if (t->bc < 0 ) { if (DEBUG) log(LOG_DEBUG, "%s: Peer did not specify bearer capability. Closing.\n",__FUNCTION__); set_error(c, VENDOR_ERROR, "Specify bearer capability"); c->needclose = -1; return -EINVAL; } */ if ((!strlen (t->hostname)) && ((t->chal_them.state) || ((t->chal_us.state)))) { if (DEBUG) l2tp_log (LOG_DEBUG, "%s: Peer did not specify hostname. Closing.\n", __FUNCTION__); set_error (c, VENDOR_ERROR, "Specify your hostname"); c->needclose = -1; return -EINVAL; } if (t->tid <= 0) { if (DEBUG) l2tp_log (LOG_DEBUG, "%s: Peer did not specify assigned tunnel ID. Closing.\n", __FUNCTION__); set_error (c, VENDOR_ERROR, "Specify your assigned tunnel ID"); c->needclose = -1; return -EINVAL; } if (t->chal_them.state) { t->chal_them.ss = SCCRP; if (handle_challenge (t, &t->chal_them)) { set_error (c, VENDOR_ERROR, "No secret key on our side"); l2tp_log (LOG_WARNING, "%s: No secret key for authenticating '%s'\n", __FUNCTION__, t->hostname); c->needclose = -1; return -EINVAL; } if (memcmp (t->chal_them.reply, t->chal_them.response, MD_SIG_SIZE)) { set_error (c, VENDOR_ERROR, "Invalid challenge authentication"); l2tp_log (LOG_DEBUG, "%s: Invalid authentication for host '%s'\n", __FUNCTION__, t->hostname); c->needclose = -1; return -EINVAL; } } if (t->chal_us.state) { t->chal_us.ss = SCCCN; if (handle_challenge (t, &t->chal_us)) { l2tp_log (LOG_WARNING, "%s: No secret for authenticating to '%s'\n", __FUNCTION__, t->hostname); set_error (c, VENDOR_ERROR, "No secret key on our end"); c->needclose = -1; return -EINVAL; }; } t->state = SCCCN; buf = new_outgoing (t); add_message_type_avp (buf, SCCCN); if (t->hbit) { mk_challenge (t->chal_them.vector, VECTOR_SIZE); add_randvect_avp (buf, t->chal_them.vector, VECTOR_SIZE); } if (t->chal_us.state) add_chalresp_avp (buf, t->chal_us.response, MD_SIG_SIZE); add_control_hdr (t, c, buf); if (gconfig.packet_dump) do_packet_dump (buf); c->cnu = 0; if (gconfig.debug_state) l2tp_log (LOG_DEBUG, "%s: sending SCCCN\n", __FUNCTION__); control_xmit (buf); #ifdef USE_KERNEL connect_pppol2tp(t); #endif /* Schedule a HELLO */ tv.tv_sec = HELLO_DELAY; tv.tv_usec = 0; #ifdef DEBUG_HELLO l2tp_log (LOG_DEBUG, "%s: scheduling initial HELLO on %d\n", __FUNCTION__, t->ourtid); #endif t->hello = schedule (tv, hello, (void *) t); l2tp_log (LOG_NOTICE, "Connection established to %s, %d. Local: %d, Remote: %d (ref=%u/%u).\n", IPADDY (t->peer.sin_addr), ntohs (t->peer.sin_port), t->ourtid, t->tid, t->refme, t->refhim); if (t->lac) { /* This is part of a LAC, so we want to go ahead and start an ICRQ now */ magic_lac_dial (t->lac); } break; case SCCCN: if (t->chal_them.state) { if (memcmp (t->chal_them.reply, t->chal_them.response, MD_SIG_SIZE)) { set_error (c, VENDOR_ERROR, "Invalid challenge authentication"); l2tp_log (LOG_DEBUG, "%s: Invalid authentication for host '%s'\n", __FUNCTION__, t->hostname); c->needclose = -1; return -EINVAL; } } t->state = SCCCN; l2tp_log (LOG_NOTICE, "Connection established to %s, %d. Local: %d, Remote: %d (ref=%u/%u). LNS session is '%s'\n", IPADDY (t->peer.sin_addr), ntohs (t->peer.sin_port), t->ourtid, t->tid, t->refme, t->refhim, t->lns->entname); #ifdef USE_KERNEL connect_pppol2tp(t); #endif /* Schedule a HELLO */ tv.tv_sec = HELLO_DELAY; tv.tv_usec = 0; #ifdef DEBUG_HELLO l2tp_log (LOG_DEBUG, "%s: scheduling initial HELLO on %d\n", __FUNCTION__, t->ourtid); #endif t->hello = schedule (tv, hello, (void *) t); break; case StopCCN: if (t->qtid < 0) { if (DEBUG) l2tp_log (LOG_DEBUG, "%s: Peer tried to disconnect without specifying tunnel ID\n", __FUNCTION__); return -EINVAL; } /* Work around bug in MSL2TP client */ if ((t->firmware == 0xff00) && (!(strncmp(t->vendor, "Deterministic Networks Inc.", 27)))) tmptid = t->ourtid; else tmptid = t->tid; if ((t->qtid != tmptid) && (tmptid > 0)) { if (DEBUG) l2tp_log (LOG_DEBUG, "%s: Peer [Vendor:%s] [Firmware:%d (0x%.4x)] tried to disconnect with invalid TID (%d != %d)\n", __FUNCTION__, t->vendor, t->firmware, t->firmware, t->qtid, tmptid); return -EINVAL; } /* In case they're disconnecting immediately after SCCN */ if (!t->tid) t->tid = t->qtid; if (t->self->result < 0) { if (DEBUG) l2tp_log (LOG_DEBUG, "%s: Peer tried to disconnect without specifying result code.\n", __FUNCTION__); return -EINVAL; } l2tp_log (LOG_INFO, "%s: Connection closed to %s, port %d (%s), Local: %d, Remote: %d\n", __FUNCTION__, IPADDY (t->peer.sin_addr), ntohs (t->peer.sin_port), t->self->errormsg, t->ourtid, t->tid); c->needclose = 0; c->closing = -1; break; case ICRQ: p = t->call_head; if (!p->lns) { set_error (p, ERROR_INVALID, "This tunnel cannot accept calls\n"); call_close (p); return -EINVAL; } p->lbit = p->lns->lbit ? LBIT : 0; /* p->ourrws = p->lns->call_rws; if (p->ourrws > -1) p->ourfbit = FBIT; else p->ourfbit = 0; */ if (p->cid < 0) { if (DEBUG) l2tp_log (LOG_DEBUG, "%s: Peer tried to initiate call without call ID\n", __FUNCTION__); /* Here it doesn't make sense to use the needclose flag because the call p did not receive any packets */ call_close (p); return -EINVAL; } z = p->next; while (z) { if (z->cid == p->cid) { /* This can happen if we get a duplicate ICRQ or if they don't get our ACK packet */ l2tp_log (LOG_DEBUG, "%s: Peer requested call %d twice, ignoring second one.\n", __FUNCTION__, p->cid); p->needclose = 0; p->closing = -1; return 0; } z = z->next; } p = t->call_head; /* FIXME: by commenting this out, we're not checking whether the serial * number avp is included in the ICRQ at all which its required to be. * Since the serial number is only used for human debugging aid, this * isn't a big deal, but it would be nice to have *some* sort of check * for it and perhaps just log it and go on. */ /* JLM if (p->serno<1) { if (DEBUG) log(LOG_DEBUG, "%s: Peer did not specify serial number when initiating call\n", __FUNCTION__); call_close(p); return -EINVAL; } */ #ifdef IP_ALLOCATION if (t->lns->assign_ip) { p->addr = get_addr (t->lns->range); if (!p->addr) { set_error (p, ERROR_NORES, "No available IP address"); call_close (p); l2tp_log (LOG_DEBUG, "%s: Out of IP addresses on tunnel %d!\n", __FUNCTION__, t->tid); return -EINVAL; } reserve_addr (p->addr); } else p->addr = 0; #endif p->state = ICRP; buf = new_outgoing (t); add_message_type_avp (buf, ICRP); if (t->hbit) { mk_challenge (t->chal_them.vector, VECTOR_SIZE); add_randvect_avp (buf, t->chal_them.vector, VECTOR_SIZE); } #ifdef TEST_HIDDEN add_callid_avp (buf, p->ourcid, t); #else add_callid_avp (buf, p->ourcid); #endif /* if (p->ourrws >=0) add_avp_rws(buf, p->ourrws); */ /* * FIXME: I should really calculate * Packet Processing Delay */ /* add_ppd_avp(buf,ppd); */ add_control_hdr (t, p, buf); if (gconfig.packet_dump) do_packet_dump (buf); p->cnu = 0; if (gconfig.debug_state) l2tp_log (LOG_DEBUG, "%s: Sending ICRP\n", __FUNCTION__); control_xmit (buf); break; case ICRP: if (c->cid < 0) { if (DEBUG) l2tp_log (LOG_DEBUG, "%s: Peer tried to negotiate ICRP without specifying call ID\n", __FUNCTION__); c->needclose = -1; return -EINVAL; } c->state = ICCN; if (t->fc & SYNC_FRAMING) c->frame = SYNC_FRAMING; else c->frame = ASYNC_FRAMING; buf = new_outgoing (t); add_message_type_avp (buf, ICCN); if (t->hbit) { mk_challenge (t->chal_them.vector, VECTOR_SIZE); add_randvect_avp (buf, t->chal_them.vector, VECTOR_SIZE); } add_txspeed_avp (buf, t->txspeed); add_frame_avp (buf, c->frame); /* if (c->ourrws >= 0) add_avp_rws(buf, c->ourrws); */ #ifndef CONFIG_WATCHDOG_FIREWALL /* FIXME: Packet Processing Delay */ /* We don't need any kind of proxy PPP stuff */ /* Can we proxy authenticate ourselves??? */ add_rxspeed_avp (buf, t->rxspeed); #endif /* add_seqreqd_avp (buf); *//* We don't have sequencing code, so * don't ask for sequencing */ add_control_hdr (t, c, buf); if (gconfig.packet_dump) do_packet_dump (buf); c->cnu = 0; if (gconfig.debug_state) l2tp_log (LOG_DEBUG, "%s: Sending ICCN\n", __FUNCTION__); l2tp_log (LOG_NOTICE, "Call established with %s, Local: %d, Remote: %d, Serial: %d (ref=%u/%u)\n", IPADDY (t->peer.sin_addr), c->ourcid, c->cid, c->serno, t->refme, t->refhim); control_xmit (buf); po = NULL; po = add_opt (po, "passive"); po = add_opt (po, "nodetach"); if (c->lac) { if (c->lac->defaultroute) po = add_opt (po, "defaultroute"); strncpy (ip1, IPADDY (c->lac->localaddr), sizeof (ip1)); strncpy (ip2, IPADDY (c->lac->remoteaddr), sizeof (ip2)); #ifdef IP_ALLOCATION po = add_opt (po, "%s:%s", c->lac->localaddr ? ip1 : "", c->lac->remoteaddr ? ip2 : ""); #endif if (c->lac->authself) { if (c->lac->pap_refuse) po = add_opt (po, "refuse-pap"); if (c->lac->chap_refuse) po = add_opt (po, "refuse-chap"); } else { po = add_opt (po, "refuse-pap"); po = add_opt (po, "refuse-chap"); } if (c->lac->authpeer) { po = add_opt (po, "auth"); if (c->lac->pap_require) po = add_opt (po, "require-pap"); if (c->lac->chap_require) po = add_opt (po, "require-chap"); } if (c->lac->authname[0]) { po = add_opt (po, "name"); po = add_opt (po, c->lac->authname); } if (c->lac->debug) po = add_opt (po, "debug"); if (c->lac->password[0]) { if (pipe (pppd_passwdfd) == -1) { l2tp_log (LOG_DEBUG, "%s: Unable to create password pipe for pppd\n", __FUNCTION__); return -EINVAL; } if (-1 == write (pppd_passwdfd[1], c->lac->password, strlen (c->lac->password))) { l2tp_log (LOG_DEBUG, "%s: Unable to write password to pipe for pppd\n", __FUNCTION__); close (pppd_passwdfd[1]); return -EINVAL; } close (pppd_passwdfd[1]); /* clear password if not redialing: paranoid? */ if (!c->lac->redial) for (i = 0; i < STRLEN; i++) c->lac->password[i] = '\0'; po = add_opt (po, "plugin"); po = add_opt (po, "passwordfd.so"); po = add_opt (po, "passwordfd"); snprintf (passwdfd_buf, 32, "%d", pppd_passwdfd[0]); po = add_opt (po, passwdfd_buf); } if (c->lac->pppoptfile[0]) { po = add_opt (po, "file"); po = add_opt (po, c->lac->pppoptfile); } }; if (c->lac->pass_peer) { po = add_opt (po, "ipparam"); po = add_opt (po, IPADDY (t->peer.sin_addr)); } start_pppd (c, po); opt_destroy (po); if (c->lac) c->lac->rtries = 0; if (c->lac->password[0]) close(pppd_passwdfd[0]); break; case ICCN: if (c == t->self) { l2tp_log (LOG_DEBUG, "%s: Peer attempted ICCN on the actual tunnel, not the call", __FUNCTION__); return -EINVAL; } if (c->txspeed < 1) { l2tp_log (LOG_DEBUG, "%s: Warning: Peer did not specify transmit speed\n", __FUNCTION__); /* don't refuse the connection over this c->needclose = -1; return -EINVAL; */ }; if (c->frame < 1) { l2tp_log (LOG_DEBUG, "%s: Warning: Peer did not specify framing type\n", __FUNCTION__); /* don't refuse the connection over this c->needclose = -1; return -EINVAL; */ } c->state = ICCN; if (get_local_addr(t, c)) return -EINVAL; strncpy (ip1, IPADDY (c->lns->localaddr), sizeof (ip1)); strncpy (ip2, IPADDY (c->addr), sizeof (ip2)); po = NULL; po = add_opt (po, "passive"); po = add_opt (po, "nodetach"); po = add_opt (po, "%s:%s", c->lns->localaddr ? ip1 : "", ip2); if (c->lns->authself) { if (c->lns->pap_refuse) po = add_opt (po, "refuse-pap"); if (c->lns->chap_refuse) po = add_opt (po, "refuse-chap"); } else { po = add_opt (po, "refuse-pap"); po = add_opt (po, "refuse-chap"); } if (c->lns->authpeer) { po = add_opt (po, "auth"); if (c->lns->pap_require) po = add_opt (po, "require-pap"); if (c->lns->chap_require) po = add_opt (po, "require-chap"); if (c->lns->passwdauth) po = add_opt (po, "login"); } if (c->lns->authname[0]) { po = add_opt (po, "name"); po = add_opt (po, c->lns->authname); } if (c->lns->debug) po = add_opt (po, "debug"); if (c->lns->pppoptfile[0]) { po = add_opt (po, "file"); po = add_opt (po, c->lns->pppoptfile); } if (c->lns->pass_peer) { po = add_opt (po, "ipparam"); po = add_opt (po, IPADDY (t->peer.sin_addr)); } start_pppd (c, po); opt_destroy (po); l2tp_log (LOG_NOTICE, "Call established with %s, PID: %d, Local: %d, Remote: %d, Serial: %d\n", IPADDY (t->peer.sin_addr), c->pppd, c->ourcid, c->cid, c->serno); break; case OCRP: /* jz: nothing to do for OCRP, waiting for OCCN */ break; case OCCN: /* jz: get OCCN, so the only thing we must do is to start the pppd */ po = NULL; po = add_opt (po, "passive"); po = add_opt (po, "nodetach"); po = add_opt (po, "file"); strcat (dummy_buf, c->dial_no); /* jz: use /etc/ppp/dialnumber.options for pppd - kick it if you don't like */ strcat (dummy_buf, ".options"); po = add_opt (po, dummy_buf); if (c->lac) { if (c->lac->defaultroute) po = add_opt (po, "defaultroute"); strncpy (ip1, IPADDY (c->lac->localaddr), sizeof (ip1)); strncpy (ip2, IPADDY (c->lac->remoteaddr), sizeof (ip2)); po = add_opt (po, "%s:%s", c->lac->localaddr ? ip1 : "", c->lac->remoteaddr ? ip2 : ""); if (c->lac->authself) { if (c->lac->pap_refuse) po = add_opt (po, "refuse-pap"); if (c->lac->chap_refuse) po = add_opt (po, "refuse-chap"); } else { po = add_opt (po, "refuse-pap"); po = add_opt (po, "refuse-chap"); } if (c->lac->authpeer) { po = add_opt (po, "auth"); if (c->lac->pap_require) po = add_opt (po, "require-pap"); if (c->lac->chap_require) po = add_opt (po, "require-chap"); } if (c->lac->authname[0]) { po = add_opt (po, "name"); po = add_opt (po, c->lac->authname); } if (c->lac->debug) po = add_opt (po, "debug"); if (c->lac->pppoptfile[0]) { po = add_opt (po, "file"); po = add_opt (po, c->lac->pppoptfile); } }; if (c->lac->pass_peer) { po = add_opt (po, "ipparam"); po = add_opt (po, IPADDY (t->peer.sin_addr)); } start_pppd (c, po); /* jz: just show some information */ l2tp_log (LOG_INFO, "parameters: Local: %d , Remote: %d , Serial: %d , Pid: %d , Tunnelid: %d , Phoneid: %s\n", c->ourcid, c->cid, c->serno, c->pppd, t->ourtid, c->dial_no); opt_destroy (po); if (c->lac) c->lac->rtries = 0; break; case CDN: if (c->qcid < 0) { if (DEBUG) l2tp_log (LOG_DEBUG, "%s: Peer tried to disconnect without specifying call ID\n", __FUNCTION__); return -EINVAL; } if (c == t->self) { p = t->call_head; while (p && (p->cid != c->qcid)) p = p->next; if (!p) { if (DEBUG) l2tp_log (LOG_DEBUG, "%s: Unable to determine call to be disconnected.\n", __FUNCTION__); return -EINVAL; } } else { p = c; } /* Work around bug in MSL2TP client */ if ((t->firmware == 0xff00) && (!(strncmp(t->vendor, "Deterministic Networks Inc.", 27)))) tmpcid = p->ourcid; else tmpcid = p->cid; if ((c->qcid != tmpcid) && tmpcid > 0) { if (DEBUG) l2tp_log (LOG_DEBUG, "%s: Peer tried to disconnect with invalid CID (%d != %d)\n", __FUNCTION__, c->qcid, c->ourcid); return -EINVAL; } c->qcid = -1; if (c->result < 0) { if (DEBUG) l2tp_log (LOG_DEBUG, "%s: Peer tried to disconnect without specifying result code.\n", __FUNCTION__); return -EINVAL; } l2tp_log (LOG_INFO, "%s: Connection closed to %s, serial %d (%s)\n", __FUNCTION__, IPADDY (t->peer.sin_addr), c->serno, c->errormsg); c->needclose = 0; c->closing = -1; break; case Hello: break; case SLI: break; default: l2tp_log (LOG_DEBUG, "%s: Don't know how to finish a message of type %d\n", __FUNCTION__, c->msgtype); set_error (c, VENDOR_ERROR, "Unimplemented message %d\n", c->msgtype); } return 0; } static inline int check_control (const struct buffer *buf, struct tunnel *t, struct call *c) { /* * Check if this is a valid control * or not. Returns 0 on success */ struct control_hdr *h = (struct control_hdr *) (buf->start); struct buffer *zlb; if (buf->len < sizeof (struct control_hdr)) { if (DEBUG) { l2tp_log (LOG_DEBUG, "%s: Received too small of packet\n", __FUNCTION__); } return -EINVAL; } #ifdef SANITY if (buf->len != h->length) { if (DEBUG) { l2tp_log (LOG_DEBUG, "%s: Reported and actual sizes differ (%d != %d)\n", __FUNCTION__, h->length, buf->len); } return -EINVAL; } /* * FIXME: H-bit handling goes here */ #ifdef DEBUG_CONTROL l2tp_log (LOG_DEBUG, "%s: control, cid = %d, Ns = %d, Nr = %d\n", __FUNCTION__, c->cid, h->Ns, h->Nr); #endif if (h->Ns != t->control_rec_seq_num) { if (DEBUG) l2tp_log (LOG_DEBUG, "%s: Received out of order control packet on tunnel %d (got %d, expected %d)\n", __FUNCTION__, t->tid, h->Ns, t->control_rec_seq_num); if (((h->Ns < t->control_rec_seq_num) && ((t->control_rec_seq_num - h->Ns) < 32768)) || ((h->Ns > t->control_rec_seq_num) && ((t->control_rec_seq_num - h->Ns) > 32768))) { /* * Woopsies, they sent us a message we should have already received * so we should send them a ZLB so they know * for sure that we already have it. */ #ifdef DEBUG_ZLB if (DEBUG) l2tp_log (LOG_DEBUG, "%s: Sending an updated ZLB in reponse\n", __FUNCTION__); #endif if (buf->len != sizeof (struct control_hdr)) { /* don't send a ZLB in response to a ZLB. it leads to a loop */ zlb = new_outgoing (t); control_zlb (zlb, t, c); /*udp_xmit (zlb, t);*/ toss (zlb); } } else if (!t->control_rec_seq_num && (t->tid == -1)) { /* We made this tunnel just for this message, so let's destroy it. */ c->needclose = 0; c->closing = -1; } return -EINVAL; } else { t->control_rec_seq_num++; c->cnu = -1; } /* * So we know what the other end has received * so far */ t->cLr = h->Nr; if (t->sanity) { if (!CTBIT (h->ver)) { if (DEBUG) { l2tp_log (LOG_DEBUG, "%s: Control bit not set\n", __FUNCTION__); } return -EINVAL; } if (!CLBIT (h->ver)) { if (DEBUG) { l2tp_log (LOG_DEBUG, "%s: Length bit not set\n", __FUNCTION__); } return -EINVAL; } if (!CFBIT (h->ver)) { if (DEBUG) { l2tp_log (LOG_DEBUG, "%s: Flow bit not set\n", __FUNCTION__); } return -EINVAL; } if (CVER (h->ver) != VER_L2TP) { if (DEBUG) { if (CVER (h->ver) == VER_PPTP) { l2tp_log (LOG_DEBUG, "%s: PPTP packet received\n", __FUNCTION__); } else if (CVER (h->ver) < VER_L2TP) { l2tp_log (LOG_DEBUG, "%s: L2F packet received\n", __FUNCTION__); } else { l2tp_log (LOG_DEBUG, "%s: Unknown version received\n", __FUNCTION__); } } return -EINVAL; } } #endif return 0; } static inline int check_payload (struct buffer *buf, struct tunnel *t, struct call *c) { /* * Check if this is a valid payload * or not. Returns 0 on success. */ size_t ehlen = MIN_PAYLOAD_HDR_LEN; struct payload_hdr *h = (struct payload_hdr *) (buf->start); if (!c) { if (DEBUG) { l2tp_log (LOG_DEBUG, "%s: Attempted to send payload on tunnel\n", __FUNCTION__); } return -EINVAL; } if (buf->len < MIN_PAYLOAD_HDR_LEN) { /* has to be at least MIN_PAYLOAD_HDR_LEN no matter what. we'll look more later */ if (DEBUG) { l2tp_log (LOG_DEBUG, "%s:Received to small of packet\n", __FUNCTION__); } return -EINVAL; } #ifdef SANITY if (t->sanity) { if (PTBIT (h->ver)) { if (DEBUG) { l2tp_log (LOG_DEBUG, "%s Control bit set\n", __FUNCTION__); } return -EINVAL; } if (PLBIT (h->ver)) ehlen += 2; /* Should have length information */ if (PFBIT (h->ver)) { /* if (!c->fbit && !c->ourfbit) { if (DEBUG) l2tp_log(LOG_DEBUG,"%s: flow bit set, but no RWS negotiated.\n",__FUNCTION__); return -EINVAL; } */ ehlen += 4; /* Should have Ns and Nr too */ } /* if (!PFBIT(h->ver)) { if (c->fbit || c->ourfbit) { if (DEBUG) l2tp_log(LOG_DEBUG, "%s: no flow bit, but RWS was negotiated.\n",__FUNCTION__); return -EINVAL;; } } */ if (PSBIT (h->ver)) ehlen += 2; /* Offset information */ if (PLBIT (h->ver)) ehlen += h->length; /* include length if available */ if (PVER (h->ver) != VER_L2TP) { if (DEBUG) { if (PVER (h->ver) == VER_PPTP) { l2tp_log (LOG_DEBUG, "%s: PPTP packet received\n", __FUNCTION__); } else if (CVER (h->ver) < VER_L2TP) { l2tp_log (LOG_DEBUG, "%s: L2F packet received\n", __FUNCTION__); } else { l2tp_log (LOG_DEBUG, "%s: Unknown version received\n", __FUNCTION__); } } return -EINVAL; } if ((buf->len < ehlen) && !PLBIT (h->ver)) { if (DEBUG) { l2tp_log (LOG_DEBUG, "%s payload too small (%d < %d)\n", __FUNCTION__, buf->len, ehlen); } return -EINVAL; } if ((buf->len != h->length) && PLBIT (h->ver)) { if (DEBUG) { l2tp_log (LOG_DEBUG, "%s: size mismatch (%d != %d)\n", __FUNCTION__, buf->len, h->length); } return -EINVAL; } } #endif return 0; } static inline int expand_payload (struct buffer *buf, struct tunnel *t, struct call *c) { UNUSED(t); /* * Expands payload header. Does not check for valid header, * check_payload() should already be called as a prerequisite. */ struct payload_hdr *h = (struct payload_hdr *) (buf->start); _u16 *r = (_u16 *) h; /* Nice to have raw word pointers */ struct payload_hdr *new_hdr; int ehlen = 0; /* * We first calculate our offset */ if (!PLBIT (h->ver)) ehlen += 2; /* Should have length information */ if (!PFBIT (h->ver)) ehlen += 4; /* Should have Ns and Nr too */ if (!PSBIT (h->ver)) ehlen += 2; /* Offset information */ if (ehlen) { /* * If this payload is missing any information, we'll * fill it in */ new_hdr = (struct payload_hdr *) (buf->start - ehlen); if ((void *) new_hdr < (void *) buf->rstart) { l2tp_log (LOG_WARNING, "%s: not enough space to decompress frame\n", __FUNCTION__); return -EINVAL; }; new_hdr->ver = *r; if (PLBIT (new_hdr->ver)) { r++; new_hdr->length = *r; } else { new_hdr->length = buf->len + ehlen; }; r++; new_hdr->tid = *r; r++; new_hdr->cid = *r; if (PFBIT (new_hdr->ver)) { r++; new_hdr->Ns = *r; r++; new_hdr->Nr = *r; } else { new_hdr->Nr = c->data_seq_num; new_hdr->Ns = c->data_rec_seq_num; }; if (PSBIT (new_hdr->ver)) { r++; new_hdr->o_size = *r; // r++; // new_hdr->o_pad = *r; } else { new_hdr->o_size = 0; // new_hdr->o_pad = 0; } } else new_hdr = h; /* * Handle sequence numbers * */ /* JLM if (PRBIT(new_hdr->ver)) { if (c->pSr > new_hdr->Ns) { l2tp_log(LOG_DEBUG, "%s: R-bit set with Ns < pSr!\n",__FUNCTION__); return -EINVAL; } #ifdef DEBUG_FLOW l2tp_log(LOG_DEBUG, "%s: R-bit set on packet %d\n",__FUNCTION__,new_hdr->Ns); #endif c->pSr=new_hdr->Ns; } */ #ifdef DEBUG_PAYLOAD l2tp_log (LOG_DEBUG, "%s: payload, cid = %d, Ns = %d, Nr = %d\n", __FUNCTION__, c->cid, new_hdr->Ns, new_hdr->Nr); #endif if (new_hdr->Ns != c->data_seq_num) { /* RFC1982-esque comparison of serial numbers */ if (((new_hdr->Ns < c->data_rec_seq_num) && ((c->data_rec_seq_num - new_hdr->Ns) < 32768)) || ((new_hdr->Ns > c->data_rec_seq_num) && ((c->data_rec_seq_num - new_hdr->Ns) > 32768))) { #ifdef DEBUG_FLOW if (DEBUG) l2tp_log (LOG_DEBUG, "%s: Already seen this packet before (%d)\n", __FUNCTION__, new_hdr->Ns); #endif return -EINVAL; } else if (new_hdr->Ns <= c->data_rec_seq_num + PAYLOAD_FUDGE) { /* FIXME: I should buffer for out of order packets */ #ifdef DEBUG_FLOW if (DEBUG) l2tp_log (LOG_DEBUG, "%s: Oops, lost a packet or two (%d). continuing...\n", __FUNCTION__, new_hdr->Ns); #endif c->data_rec_seq_num = new_hdr->Ns; } else { #ifdef DEBUG_FLOW if (DEBUG) l2tp_log (LOG_DEBUG, "%s: Received out of order payload packet (%d)\n", __FUNCTION__, new_hdr->Ns); #endif return -EINVAL; } } else { c->data_rec_seq_num++; c->pnu = -1; } /* * Check to see what the last thing * we got back was */ c->pLr = new_hdr->Nr; buf->start = new_hdr; buf->len += ehlen; return 0; } void send_zlb (void *data) { /* * Send a ZLB. This procedure should be schedule()able */ struct call *c; struct tunnel *t; struct buffer *buf; c = (struct call *) data; if (!c) { l2tp_log (LOG_WARNING, "%s: called on NULL call\n", __FUNCTION__); return; } t = c->container; if (!t) { l2tp_log (LOG_WARNING, "%s: called on call with NULL container\n", __FUNCTION__); return; } /* Update the counter so we know what Lr was when we last transmitted a ZLB */ c->prx = c->data_rec_seq_num; buf = new_payload (t->peer); add_payload_hdr (t, c, buf); c->data_seq_num--; /* We don't increment on ZLB's */ c->zlb_xmit = NULL; #ifdef DEBUG_ZLB l2tp_log (LOG_DEBUG, "%s: sending payload ZLB\n", __FUNCTION__); #endif udp_xmit (buf, t); toss (buf); } static inline int write_packet (struct buffer *buf, struct tunnel *t, struct call *c, int convert) { /* * Write a packet, doing sync->async conversion if * necessary */ size_t x; unsigned char e; int err; static unsigned char wbuf[MAX_RECV_SIZE]; int pos = 0; if (c->fd < 0) { if (DEBUG) l2tp_log (LOG_DEBUG, "%s: tty is not open yet.\n", __FUNCTION__); return -EIO; } /* * Skip over header */ _u16 offset = ((struct payload_hdr*)(buf->start))->o_size; // For FIXME: buf->start += sizeof(struct payload_hdr) + offset; buf->len -= sizeof(struct payload_hdr) + offset; c->rx_pkts++; c->rx_bytes += buf->len; /* * FIXME: What about offset? */ while (!convert) { /* We are given async frames, so write them directly to the tty */ err = write (c->fd, buf->start, buf->len); if ((size_t)err == buf->len) { return 0; } else if ((size_t)err == 0) { l2tp_log (LOG_WARNING, "%s: wrote no bytes of async packet\n", __FUNCTION__); return -EINVAL; } else if ((size_t)err < 0) { if ((errno == EAGAIN) || (errno == EINTR)) { continue; } else { l2tp_log (LOG_WARNING, "%s: async write failed: %s\n", __FUNCTION__, strerror (errno)); } } else if ((size_t)err < buf->len) { l2tp_log (LOG_WARNING, "%s: short write (%d of %d bytes)\n", __FUNCTION__, err, buf->len); return -EINVAL; } else if ((size_t)err > buf->len) { l2tp_log (LOG_WARNING, "%s: write returned LONGER than buffer length?\n", __FUNCTION__); return -EINVAL; } } /* * sync->async conversion if we're doing sync frames * since the PPPD driver will expect async frames * Write leading flag character */ add_fcs (buf); e = PPP_FLAG; wbuf[pos++] = e; for (x = 0; x < buf->len; x++) { // we must at least still have 3 bytes left in the worst case scenario: // 1 for a possible escape, 1 for the value and 1 to end the PPP stream. if((size_t)pos >= (sizeof(wbuf) - 4)) { if(DEBUG) l2tp_log(LOG_CRIT, "%s: rx packet is too big after PPP encoding (size %u, max is %u)\n", __FUNCTION__, buf->len, MAX_RECV_SIZE); return -EINVAL; } e = *((char *) buf->start + x); if ((e < 0x20) || (e == PPP_ESCAPE) || (e == PPP_FLAG)) { /* Escape this */ e = e ^ 0x20; wbuf[pos++] = PPP_ESCAPE; } wbuf[pos++] = e; } wbuf[pos++] = PPP_FLAG; #if 0 if(DEBUG) { l2tp_log(LOG_DEBUG, "after sync->async, expanded %d->%d\n", buf->len, pos); } #endif x = 0; while ((size_t) pos != x ) { err = write (c->fd, wbuf+x, pos-x); if ( err < 0 ) { if ( errno != EINTR && errno != EAGAIN ) { l2tp_log (LOG_WARNING, "%s: %s(%d)\n", __FUNCTION__, strerror (errno), errno); /* * I guess pppd died. we'll pretend * everything ended normally */ c->needclose = -1; c->fd = -1; return -EIO; } else { continue; //goto while } } x += err; } return 0; } int handle_special (struct buffer *buf, struct call *c, _u16 call) { /* * This procedure is called when we have received a packet * on a call which doesn't exist in our tunnel. We want to * send back a ZLB to keep the tunnel alive, on that particular * call if it was a CDN, otherwise, send a CDN to notify them * that this call has been terminated. */ struct tunnel *t = c->container; /* Don't do anything unless it's a control packet */ if (!CTBIT (*((_u16 *) buf->start))) return 0; /* Temporarily, we make the tunnel have cid of call instead of 0, but we need to stop any scheduled events (like Hello's in particular) which might use this value */ c->cid = call; if (!check_control (buf, t, c)) { if (buf->len == sizeof (struct control_hdr)) { /* If it's a ZLB, we ignore it */ if (gconfig.debug_tunnel) l2tp_log (LOG_DEBUG, "%s: ZLB for closed call\n", __FUNCTION__); c->cid = 0; return 0; } /* Make a packet with the specified call number */ /* FIXME: If I'm not a CDN, I need to send a CDN */ control_zlb (buf, t, c); c->cid = 0; /*udp_xmit (buf, t);*/ toss (buf); return 1; } else { c->cid = 0; if (gconfig.debug_tunnel) l2tp_log (LOG_DEBUG, "%s: invalid control packet\n", __FUNCTION__); } return 0; } static int handle_control(struct buffer *buf, struct tunnel *t, struct call *c) { /* We have a control packet */ if (check_control (buf, t, c)) { l2tp_log (LOG_DEBUG, "%s: bad control packet!\n", __FUNCTION__); return -EINVAL; } c->msgtype = -1; if (buf->len == sizeof (struct control_hdr)) { #ifdef DEBUG_ZLB l2tp_log (LOG_DEBUG, "%s: control ZLB received\n", __FUNCTION__); #endif t->control_rec_seq_num--; c->cnu = 0; if (c->needclose && c->closing) { if (c->container->cLr >= c->closeSs) { #ifdef DEBUG_ZLB l2tp_log (LOG_DEBUG, "%s: ZLB for closing message found\n", __FUNCTION__); #endif c->needclose = 0; /* Trigger final closing of call */ } } return 0; } if (handle_avps (buf, t, c)) { if (gconfig.debug_tunnel) l2tp_log (LOG_DEBUG, "%s: bad AVP handling!\n", __FUNCTION__); return -EINVAL; } return control_finish (t, c); } inline int handle_packet (struct buffer *buf, struct tunnel *t, struct call *c) { int res; /* tv code is commented out below #ifdef DEBUG_ZLB struct timeval tv; #endif */ if (CTBIT (*((_u16 *) buf->start))) return handle_control(buf, t, c); if (!check_payload (buf, t, c)) { if (!expand_payload (buf, t, c)) { if (buf->len > sizeof (struct payload_hdr)) { /* if (c->throttle) { if (c->pSs > c->pLr + c->rws) { #ifdef DEBUG_FLOW l2tp_log(LOG_DEBUG, "%s: not yet dethrottling call\n",__FUNCTION__); #endif } else { #ifdef DEBUG_FLOW l2tp_log(LOG_DEBUG, "%s: dethrottling call\n",__FUNCTION__); #endif if (c->dethrottle) deschedule(c->dethrottle); c->dethrottle=NULL; c->throttle = 0; } } */ /* JLM res = write_packet(buf,t,c, c->frame & SYNC_FRAMING); */ res = write_packet (buf, t, c, SYNC_FRAMING); if (res) return res; /* * Assuming we wrote to the ppp driver okay, we should * do something about ZLB's unless *we* requested no * window size or if they we have turned off our fbit. */ /* if (c->ourfbit && (c->ourrws > 0)) { if (c->pSr >= c->prx + c->ourrws - 2) { We've received enough to fill our receive window. At this point, we should immediately send a ZLB! #ifdef DEBUG_ZLB l2tp_log(LOG_DEBUG, "%s: Sending immediate ZLB!\n",__FUNCTION__); #endif if (c->zlb_xmit) { Deschedule any existing zlb_xmit's deschedule(c->zlb_xmit); c->zlb_xmit = NULL; } send_zlb((void *)c); } else { struct timeval tv; We need to schedule sending a ZLB. FIXME: Should be 1/4 RTT instead, when rate adaptive stuff is in place. Spec allows .5 seconds though tv.tv_sec = 0; tv.tv_usec = 500000; if (c->zlb_xmit) deschedule(c->zlb_xmit); #ifdef DEBUG_ZLB l2tp_log(LOG_DEBUG, "%s: scheduling ZLB\n",__FUNCTION__); #endif c->zlb_xmit = schedule(tv, &send_zlb, (void *)c); } } */ return 0; } else if (buf->len == sizeof (struct payload_hdr)) { #ifdef DEBUG_ZLB l2tp_log (LOG_DEBUG, "%s: payload ZLB received\n", __FUNCTION__); #endif /* if (c->throttle) { if (c->pSs > c->pLr + c->rws) { #ifdef DEBUG_FLOW l2tp_log(LOG_DEBUG, "%s: not yet dethrottling call\n",__FUNCTION__); #endif } else { #ifdef DEBUG_FLOW l2tp_log(LOG_DEBUG, "%s: dethrottling call\n",__FUNCTION__); #endif if (c->dethrottle) deschedule(c->dethrottle); c->dethrottle=NULL; c->throttle = 0; } } */ c->data_rec_seq_num--; return 0; } else { l2tp_log (LOG_DEBUG, "%s: payload too small!\n", __FUNCTION__); return -EINVAL; } } else { if (gconfig.debug_tunnel) l2tp_log (LOG_DEBUG, "%s: unable to expand payload!\n", __FUNCTION__); return -EINVAL; } } else { l2tp_log (LOG_DEBUG, "%s: invalid payload packet!\n", __FUNCTION__); return -EINVAL; } } xl2tpd-1.3.16/control.h000066400000000000000000000043521374460464600146720ustar00rootroot00000000000000/* * Layer Two Tunnelling Protocol Daemon * Copyright (C) 1998 Adtran, Inc. * Copyright (C) 2002 Jeff McAdams * * Mark Spencer * * This software is distributed under the terms * of the GPL, which you should have received * along with this source. * * Control Packet Handling header * */ #include "common.h" /* Declaration of FIFO used for maintaining a reliable control connection, as well as for queueing stuff for the individual threads */ #ifndef _CONTROL_H #define _CONTROL_H /* Control message types for vendor-ID 0, placed in the VALUE field of AVP requests */ /* Control Connection Management */ #define SCCRQ 1 /* Start-Control-Connection-Request */ #define SCCRP 2 /* Start-Control-Connection-Reply */ #define SCCCN 3 /* Start-Control-Connection-Connected */ #define StopCCN 4 /* Stop-Control-Connection-Notification */ /* 5 is reserved */ #define Hello 6 /* Hello */ /* Call Management */ #define OCRQ 7 /* Outgoing-Call-Request */ #define OCRP 8 /* Outgoing-Call-Reply */ #define OCCN 9 /* Outgoing-Call-Connected */ #define ICRQ 10 /* Incoming-Call-Request */ #define ICRP 11 /* Incoming-Call-Reply */ #define ICCN 12 /* Incoming-Call-Connected */ /* 13 is reserved */ #define CDN 14 /* Call-Disconnect-Notify */ /* Error Reporting */ #define WEN 15 /* WAN-Error-Notify */ /* PPP Sesssion Control */ #define SLI 16 /* Set-Link-Info */ #define MAX_MSG 16 #define TBIT 0x8000 #define LBIT 0x4000 #define RBIT 0x2000 #define FBIT 0x0800 extern int handle_packet (struct buffer *, struct tunnel *, struct call *); extern struct buffer *new_outgoing (struct tunnel *); extern void add_control_hdr (struct tunnel *t, struct call *c, struct buffer *); extern int control_finish (struct tunnel *t, struct call *c); extern void control_zlb (struct buffer *, struct tunnel *, struct call *); extern void recycle_outgoing (struct buffer *, struct sockaddr_in); extern int handle_special (struct buffer *, struct call *, _u16); extern void hello (void *); extern void send_zlb (void *); extern void dethrottle (void *); #endif xl2tpd-1.3.16/debian/000077500000000000000000000000001374460464600142575ustar00rootroot00000000000000xl2tpd-1.3.16/debian/changelog000066400000000000000000000156001374460464600161330ustar00rootroot00000000000000xl2tpd (1.3.14-1) UNRELEASED; urgency=medium * New upstream release. -- Samir Hussain Wed, 17 Apr 2019 12:22:21 -0500 xl2tpd (1.3.13-1) UNRELEASED; urgency=medium * New upstream release. -- Samir Hussain Mon, 03 Dec 2018 13:02:21 -0500 xl2tpd (1.3.12-1.1) UNRELEASED; urgency=medium * Non-maintainer upload. * Fix FTCFBS: Let dh_auto_build pass cross compilers to make. (Closes: #-1) -- Helmut Grohne Thu, 24 May 2018 06:08:31 +0200 xl2tpd (1.3.12-1) unstable; urgency=medium * New upstream release. -- Samir Hussain Fri, 18 May 2018 17:08:21 -0500 xl2tpd (1.3.11-1) unstable; urgency=medium * New upstream release. * Use HTTPS URL in d/copyright * Refresh d/control by partly sync'ing from Debian * Drop d/repack.sh script and refresh d/watch * Bump d/compat to 9 * Build packages for Xenial by default -- Samir Hussain Wed, 07 Mar 2018 14:37:21 -0500 xl2tpd (1.3.10-1) unstable; urgency=medium * New upstream release. - Drops the non-free RFC, so no need for +dfsg suffix any more. -- Samuel Thibault Sun, 22 Oct 2017 19:26:04 +0200 xl2tpd (1.3.8+dfsg-1) unstable; urgency=medium * New upstream release. * Package adopted by Samir (Closes: #786810) * control: - Bump policy version (no change). - Add missing lsb-base dependency. -- Samuel Thibault Sun, 04 Dec 2016 21:17:35 +0100 xl2tpd (1.3.6+dfsg-4) unstable; urgency=medium * QA upload. * rules: Enable USE_KERNEL, like upstream now does (Closes: #542521) -- Samuel Thibault Fri, 27 Nov 2015 22:40:47 +0100 xl2tpd (1.3.6+dfsg-3) unstable; urgency=low * Orphan package, set maintainer to Debian QA Group -- Roberto C. Sanchez Mon, 25 May 2015 14:40:47 -0400 xl2tpd (1.3.6+dfsg-2) unstable; urgency=low * Update to debhelper compatibility level 7 * Add patch series for local ip range option in the configuration, thanks to Pete Morreale. -- Roberto C. Sanchez Thu, 08 May 2014 11:57:42 -0400 xl2tpd (1.3.6+dfsg-1) unstable; urgency=low * New upstream release + Drop Build-Depends on libssl-dev (reverted by upstream) * Drop OpenSSL exception from debian/copyright (dropped by upstream) -- Roberto C. Sanchez Wed, 15 Jan 2014 22:08:27 -0500 xl2tpd (1.3.3+dfsg-1) unstable; urgency=low * New upstream release (Closes: #680146, #635472, #693316) + Now Build-Depends on libssl-dev for MD5 function * Update debian/copyright with OpenSSL linking exception * Update watch file to point to new github location * Add Vcs-Browser and Vcs-Git tags to control file * Update years in copyright file * Update copyright to conform to copyright-format 1.0 * Update to Standards-Version 3.9.5 (no changes) * Build with hardening options * Drop obselete Replaces of l2tpd * Drop 01_apply_build_flags_to_all_binaries.patch (incorporated upstream) -- Roberto C. Sanchez Fri, 03 Jan 2014 17:50:43 -0500 xl2tpd (1.3.1+dfsg-1) unstable; urgency=low * New upstream release -- Roberto C. Sanchez Mon, 10 Oct 2011 11:57:19 -0400 xl2tpd (1.3.0+dfsg-1) unstable; urgency=low * New upstream release (Closes: #611829) * Update debian/watch to account for upstream's RC numbering * Update to Standards-Version 3.9.2 (no changes) * Start when service is stopped and restart is attempted (Closes: #631369) -- Roberto C. Sanchez Tue, 13 Sep 2011 18:22:42 -0400 xl2tpd (1.2.8+dfsg-1) unstable; urgency=low * New upstream release -- Roberto C. Sanchez Thu, 03 Mar 2011 13:31:28 -0500 xl2tpd (1.2.7+dfsg-1) unstable; urgency=low * New upstream release (Closes: #578070, #589306) * Update to Standards-Version 3.9.1 (no changes) -- Roberto C. Sanchez Sat, 07 Aug 2010 21:50:55 -0400 xl2tpd (1.2.6+dfsg-1) unstable; urgency=low * New upstream release * Switch to dpkg-source 3.0 (quilt) format * Update to Standards-Version 3.8.4 (no changes) * Add $remote_fs to Required-Start/Required-Stop in init script -- Roberto C. Sanchez Sat, 05 Jun 2010 21:10:17 -0400 xl2tpd (1.2.5+dfsg-1) unstable; urgency=low * New upstream release * Remove unnecessary README.source since dpatch was dropped * Update to Standards-Version 3.8.3 -- Roberto C. Sanchez Sun, 24 Jan 2010 15:23:17 -0500 xl2tpd (1.2.4+dfsg-1) unstable; urgency=low * New upstream release (Closes: #494795) * Update to Standards-Version 3.8.1 + Add README.source + Fix watch file to use dversionmangle instead of uversionmangle * Update copyright file to new proposed format * Drop debian/patches/02_trust_pppd_to_die.dpatch (included upstream) * Add build-time dependency on libpcap0.8-dev * Make lintian happy: + Move creation of directory in /var/run to daemon start time * Drop l2tpd transitional package -- Roberto C. Sanchez Fri, 13 Mar 2009 09:58:54 -0400 xl2tpd (1.2.0+dfsg-1) unstable; urgency=low * New upstream release. * debian/patches/01_fix_makefile_bashism.dpatch: Remove, included upstream -- Roberto C. Sanchez Mon, 31 Mar 2008 17:02:47 -0400 xl2tpd (1.1.12.dfsg.1-4) unstable; urgency=low * Ship examples (Closes: #466512) * Trust pppd to die properly (Closes: #466057) * Update watch file and automate repacking upstream tarball. -- Roberto C. Sanchez Sat, 08 Mar 2008 21:25:41 -0500 xl2tpd (1.1.12.dfsg.1-3) unstable; urgency=low * Update to Standards-Version 3.7.3 (no changes required) * Fix Makefile bashism, thanks to Luca Falavigna (Closes: #453046) * Make sure conffiles are not left behind (Closes: #455023) -- Roberto C. Sanchez Sun, 20 Jan 2008 21:13:52 -0500 xl2tpd (1.1.12.dfsg.1-2) unstable; urgency=low * debian/control: Switch Homepage to be a proper control field. * debian/xl2tpd.init: Add --oknodo for stop action (Closes: #447990) -- Roberto C. Sanchez Sun, 4 Nov 2007 14:47:30 -0500 xl2tpd (1.1.12.dfsg.1-1) unstable; urgency=low * New upstream release * Repack upsteam tarball: remove non-free RFC and shipped debian/ directory -- Roberto C. Sanchez Sat, 20 Oct 2007 09:46:16 -0400 xl2tpd (1.1.11.dfsg.1-2) unstable; urgency=low * Added missing copyright notices. -- Roberto C. Sanchez Fri, 3 Aug 2007 14:13:23 -0400 xl2tpd (1.1.11.dfsg.1-1) unstable; urgency=low * Initial release (Closes: #427113, 402660) * Make l2tpd obsolete (Closes: #358799) * Repackage upstream tarball to remove non-free RFC (Closes: #393381) -- Roberto C. Sanchez Tue, 31 Jul 2007 20:57:23 -0400 Local variables: mode: debian-changelog End: xl2tpd-1.3.16/debian/compat000066400000000000000000000000031374460464600154560ustar00rootroot0000000000000010 xl2tpd-1.3.16/debian/control000066400000000000000000000015411374460464600156630ustar00rootroot00000000000000Source: xl2tpd Section: net Priority: optional Maintainer: Samir Hussain Uploaders: Samuel Thibault Homepage: https://www.xelerance.com/software/xl2tpd/ Vcs-Browser: https://github.com/xelerance/xl2tpd Vcs-Git: git://github.com/xelerance/xl2tpd.git Build-Depends: debhelper (>= 10), libpcap0.8-dev Standards-Version: 3.9.8 Package: xl2tpd Architecture: any Provides: l2tpd Depends: ${shlibs:Depends}, ${misc:Depends}, ppp, lsb-base (>= 3.0-6) Description: layer 2 tunneling protocol implementation xl2tpd is an open source implementation of the L2TP tunneling protocol (RFC2661). xl2tpd is forked from l2tpd and is maintained by Xelerance Corporation. . The main purpose of this protocol is to tunnel PPP frames through IP networks. It implements both LAC and LNS role in the L2TP networking architecture. xl2tpd-1.3.16/debian/copyright000066400000000000000000000012131374460464600162070ustar00rootroot00000000000000Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ Source: http://www.xelerance.com/software/xl2tpd/ (repacked to remove non-free RFC text included in upstream distribution) Files: * Copyright: (c) 2006-2016 Xelerance Corporation License: GPL-2+ Files: debian/* Copyright: (c) 2007-2013 Roberto C. Sanchez Jean-Francois Dive License: GPL-2+ License: GPL-2+ Please see the CREDITS file for a complete copyright history of all parts of the project. . On Debian systems, the complete text of the GNU General Public License can be found in `/usr/share/common-licenses/GPL-2'. xl2tpd-1.3.16/debian/lintian-overrides000066400000000000000000000002531374460464600176400ustar00rootroot00000000000000# The etc/xl2tpd/l2tp-secrets file must not be readable by non-root xl2tpd: non-standard-file-perm etc/xl2tpd/l2tp-secrets 0600 != 0644 xl2tpd: hyphen-used-as-minus-sign xl2tpd-1.3.16/debian/repack.sh000077500000000000000000000014201374460464600160600ustar00rootroot00000000000000#!/bin/sh # Repackage upstream source to exclude non-distributable files # should be called as "repack sh --upstream-source # (for example, via uscan) set -e set -u FILE=$3 PKG=`dpkg-parsechangelog|grep ^Source:|sed 's/^Source: //'` VER="$2+dfsg" printf "\nRepackaging $FILE\n" DIR=`mktemp -d ./tmpRepackXXXXXX` trap "rm -rf $DIR" QUIT INT EXIT tar xzf $FILE -C $DIR TARGET=`echo $FILE |sed 's/_\(.*\)\.orig/_\1+dfsg.orig/'` REPACK=`basename $TARGET` UP_DIR=`ls -1 $DIR` ( set -e set -u cd $DIR rm -v $UP_DIR/doc/rfc2661.txt rm -rv $UP_DIR/debian/ REPACK_DIR="$PKG-$VER.orig" mv $UP_DIR $REPACK_DIR tar -c $REPACK_DIR | gzip -9 > $REPACK ) rm -v $FILE mv $DIR/$REPACK $TARGET echo "*** $FILE repackaged as $TARGET" xl2tpd-1.3.16/debian/rules000077500000000000000000000042701374460464600153420ustar00rootroot00000000000000#!/usr/bin/make -f # -*- makefile -*- # Sample debian/rules that uses debhelper. # This file was originally written by Joey Hess and Craig Small. # As a special exception, when this file is copied by dh-make into a # dh-make output file, you may use that output file without restriction. # This special exception was added by Craig Small in version 0.37 of dh-make. # Uncomment this to turn on verbose mode. #export DH_VERBOSE=1 CFLAGS = -Wall -g ifneq (,$(findstring noopt,$(DEB_BUILD_OPTIONS))) CFLAGS += -O0 else CFLAGS += -O2 endif configure: configure-stamp configure-stamp: dh_testdir touch configure-stamp build: build-arch build-indep build-arch: build-stamp build-indep: build-stamp build-stamp: configure-stamp dh_testdir dh_auto_build -- CFLAGS=" -DDEBUG_PPPD -DTRUST_PPPD_TO_DIE -O2 -fno-builtin -Wall -DSANITY -DLINUX -I$(KERNELSRC)/include/ -DIP_ALLOCATION -DUSE_KERNEL $(shell dpkg-buildflags --get CFLAGS)" CPPFLAGS=" -DDEBUG_PPPD -DTRUST_PPPD_TO_DIE -O2 -fno-builtin -Wall -DSANITY -DLINUX -I$(KERNELSRC)/include/ -DIP_ALLOCATION $(shell dpkg-buildflags --get CPPFLAGS)" LDFLAGS=" $(shell dpkg-buildflags --get LDFLAGS)" touch $@ clean: dh_testdir dh_testroot rm -f build-stamp configure-stamp [ ! -f Makefile ] || $(MAKE) clean dh_clean install: build dh_testdir dh_testroot dh_prep dh_installdirs $(MAKE) PREFIX=/usr DESTDIR=$(CURDIR)/debian/xl2tpd install cp $(CURDIR)/doc/l2tpd.conf.sample $(CURDIR)/debian/xl2tpd/etc/xl2tpd/xl2tpd.conf cp $(CURDIR)/doc/l2tp-secrets.sample $(CURDIR)/debian/xl2tpd/etc/xl2tpd/l2tp-secrets # Build architecture-independent files here. binary-indep: build install # Nothing to do here # Build architecture-dependent files here. binary-arch: build install dh_testdir dh_testroot dh_installchangelogs CHANGES dh_installdocs dh_installexamples # dh_install dh_installinit dh_installman cp debian/lintian-overrides \ debian/xl2tpd/usr/share/lintian/overrides/xl2tpd dh_link dh_strip dh_compress dh_fixperms chmod 600 $(CURDIR)/debian/xl2tpd/etc/xl2tpd/l2tp-secrets dh_installdeb dh_shlibdeps dh_gencontrol dh_md5sums dh_builddeb binary: binary-indep binary-arch .PHONY: build clean binary-indep binary-arch binary install configure xl2tpd-1.3.16/debian/source/000077500000000000000000000000001374460464600155575ustar00rootroot00000000000000xl2tpd-1.3.16/debian/source/format000066400000000000000000000000141374460464600167650ustar00rootroot000000000000003.0 (quilt) xl2tpd-1.3.16/debian/source/options000066400000000000000000000000331374460464600171710ustar00rootroot00000000000000--diff-ignore --tar-ignore xl2tpd-1.3.16/debian/watch000066400000000000000000000002161374460464600153070ustar00rootroot00000000000000version=4 opts=filenamemangle=s/.+\/v?(\d\S+)\.tar\.gz/xl2tpd-$1\.tar\.gz/ \ https://github.com/xelerance/xl2tpd/tags .*/v?(\d\S+)\.tar\.gz xl2tpd-1.3.16/debian/xl2tpd.default000066400000000000000000000004631374460464600170450ustar00rootroot00000000000000# Defaults for xl2tpd initscript # sourced by /etc/init.d/xl2tpd # installed at /etc/default/xl2tpd by the maintainer scripts # # This is a POSIX shell fragment # # Where the l2tp-control pipe is located XL2TPD_RUN_DIR="/var/run/xl2tpd" # Additional options that are passed to the Daemon. DAEMON_OPTS="" xl2tpd-1.3.16/debian/xl2tpd.dirs000066400000000000000000000000601374460464600163530ustar00rootroot00000000000000usr/sbin etc/xl2tpd usr/share/lintian/overrides xl2tpd-1.3.16/debian/xl2tpd.docs000066400000000000000000000001101374460464600163360ustar00rootroot00000000000000README.xl2tpd CREDITS contrib/pfc.README contrib/pppol2tp-2.6.23.README xl2tpd-1.3.16/debian/xl2tpd.examples000066400000000000000000000000131374460464600172260ustar00rootroot00000000000000examples/* xl2tpd-1.3.16/debian/xl2tpd.init000066400000000000000000000035171374460464600163670ustar00rootroot00000000000000#! /bin/sh ### BEGIN INIT INFO # Provides: xl2tpd l2tpd # Required-Start: $network $syslog $remote_fs # Required-Stop: $network $syslog $remote_fs # Should-Start: ipsec # Should-Stop: ipsec # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: layer 2 tunelling protocol daemon # Description: xl2tpd is usually used in conjunction with an ipsec # daemon (such as openswan). ### END INIT INFO PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin DAEMON=/usr/sbin/xl2tpd NAME=xl2tpd DESC=xl2tpd test -x $DAEMON || exit 0 . /lib/lsb/init-functions # Include xl2tpd defaults if available if [ -f /etc/default/xl2tpd ] ; then . /etc/default/xl2tpd fi PIDFILE=/var/run/$NAME.pid set -e case "$1" in start) echo -n "Starting $DESC: " test -d ${XL2TPD_RUN_DIR:-/var/run/xl2tpd} || mkdir -p ${XL2TPD_RUN_DIR:-/var/run/xl2tpd} start-stop-daemon --start --quiet --pidfile $PIDFILE \ --exec $DAEMON -- $DAEMON_OPTS echo "$NAME." ;; stop) echo -n "Stopping $DESC: " start-stop-daemon --oknodo --stop --quiet --pidfile $PIDFILE \ --exec $DAEMON echo "$NAME." ;; force-reload) test -d ${XL2TPD_RUN_DIR:-/var/run/xl2tpd} || mkdir -p ${XL2TPD_RUN_DIR:-/var/run/xl2tpd} # check whether $DAEMON is running. If so, restart start-stop-daemon --stop --test --quiet --pidfile \ $PIDFILE --exec $DAEMON \ && $0 restart \ || exit 0 ;; restart) test -d ${XL2TPD_RUN_DIR:-/var/run/xl2tpd} || mkdir -p ${XL2TPD_RUN_DIR:-/var/run/xl2tpd} echo -n "Restarting $DESC: " start-stop-daemon --oknodo --stop --quiet --pidfile \ $PIDFILE --exec $DAEMON sleep 1 start-stop-daemon --start --quiet --pidfile \ $PIDFILE --exec $DAEMON -- $DAEMON_OPTS echo "$NAME." ;; *) N=/etc/init.d/$NAME echo "Usage: $N {start|stop|restart|force-reload}" >&2 exit 1 ;; esac exit 0 xl2tpd-1.3.16/debian/xl2tpd.postinst000066400000000000000000000016761374460464600173130ustar00rootroot00000000000000#!/bin/sh # postinst script for xl2tpd # # see: dh_installdeb(1) set -e # summary of how this script can be called: # * `configure' # * `abort-upgrade' # * `abort-remove' `in-favour' # # * `abort-remove' # * `abort-deconfigure' `in-favour' # `removing' # # for details, see http://www.debian.org/doc/debian-policy/ or # the debian-policy package case "$1" in configure) ;; abort-upgrade|abort-remove|abort-deconfigure) ;; *) echo "postinst called with unknown argument \`$1'" >&2 exit 1 ;; esac # dh_installdeb will replace this with shell code automatically # generated by other debhelper scripts. #DEBHELPER# exit 0 xl2tpd-1.3.16/debian/xl2tpd.postrm000066400000000000000000000016431374460464600167460ustar00rootroot00000000000000#!/bin/sh # postrm script for xl2tpd # # see: dh_installdeb(1) set -e # summary of how this script can be called: # * `remove' # * `purge' # * `upgrade' # * `failed-upgrade' # * `abort-install' # * `abort-install' # * `abort-upgrade' # * `disappear' # # for details, see http://www.debian.org/doc/debian-policy/ or # the debian-policy package case "$1" in purge|remove|upgrade|failed-upgrade|abort-install|abort-upgrade|disappear) ;; *) echo "postrm called with unknown argument \`$1'" >&2 exit 1 ;; esac # dh_installdeb will replace this with shell code automatically # generated by other debhelper scripts. #DEBHELPER# exit 0 xl2tpd-1.3.16/debian/xl2tpd.prerm000066400000000000000000000015561374460464600165520ustar00rootroot00000000000000#!/bin/sh # prerm script for xl2tpd # # see: dh_installdeb(1) set -e # summary of how this script can be called: # * `remove' # * `upgrade' # * `failed-upgrade' # * `remove' `in-favour' # * `deconfigure' `in-favour' # `removing' # # for details, see http://www.debian.org/doc/debian-policy/ or # the debian-policy package case "$1" in remove|upgrade|deconfigure) ;; failed-upgrade) ;; *) echo "prerm called with unknown argument \`$1'" >&2 exit 1 ;; esac # dh_installdeb will replace this with shell code automatically # generated by other debhelper scripts. #DEBHELPER# exit 0 xl2tpd-1.3.16/doc/000077500000000000000000000000001374460464600136025ustar00rootroot00000000000000xl2tpd-1.3.16/doc/README.passwordfd000066400000000000000000000001131374460464600166300ustar00rootroot00000000000000Usage: echo "c " > /var/run/xl2tpd/l2tp-control xl2tpd-1.3.16/doc/README.patents000066400000000000000000000035121374460464600161400ustar00rootroot00000000000000 http://www.ietf.org/ietf/IPR/CISCO-L2TP The following was received on March 2, 1999 from Andy Valencia (vandys@cisco.com) Cisco has a patent pending that may relate to this proposed standard. If this proposed standard is adopted by IETF and any patents issue to Cisco or its subsidiaries with claims that are necessary for practicing this standard, any party will be able to obtain the right to implement, use and distribute the technology or works when implementing, using or distributing technology based upon the specific specification(s) under openly specified, reasonable, non-discriminatory terms. Requests may be sent to: Robert Barr Suite 280 2882 Sand Hill Road Menlo Park Ca 94025 Phone: 650-926-6205 Note: On July 30, 1999, we were informed that the patent office had assigned the number 5,918,019 for the patent -------------------------- Cisco allows anyone to use their patent as long as it is IETF RFC compliant. This is Cisco's standard policy on patents for their IETF work. In fact, their statement was made before being awarded the patent. They complied fully with the IPR disclosure policy of the IETF. The IETF does not release RFC's that are limited or in any way discriminatory in their use. The patent holder (in this case Ciso) agree to a royalty free, unrevocable use of their patent as needed for implementing the IETF standards. If there were any limitations on the implementation and use of L2TP, the L2TP working group would not exist any more, and no new protocol additions or changes would be accepted as RFC standard. The L2TP became an IETF standard, see http://www.ietf.org/rfc/rfc2661.txt Notice the RFC was issued after the disclosure for IPR by Cisco, so the IETF fully knew about the patent and confirmed that there were no restrictions before it issued the RFC. --- Paul Wouters xl2tpd-1.3.16/doc/ipsecsaref.png000066400000000000000000004774031374460464600164530ustar00rootroot00000000000000PNG  IHDR;3sBIT|d pHYs-+tEXtSoftwarewww.inkscape.org< IDATxy|\}3Fh,ɲEm BsQҐ6MKn46 @'M,k*[dkF3h˖בs{>?xX$wKR__\.WkfHDCNwMk 0HAp !RHAp !RHAp !RHAp !RHAp !RHAp !RHAp !RHAp !RHAp !RHAp !RHAp !RHAp !RHAp !RHAp !RHAp !RHAp !RHAp !RHAp !RHAp !RHAp !RHAp !RHAp !RHAp =gB=k?o?*^?67m#:ZY6Wˋ__2Bц۾LXȀh7t.sjqp6uE+56PSCUZ%ʭVݥߣ/G50{'^$=ԇ+JTj~^~sBjGUc[Ok}d$W?=<~kQnzO\02F\V8eԡ$}Q~NS>gWvzSрs&$CaR}j$; F@{k vjm6IWy#xUF c!eԻɿ?#4"uLtWܔvMTzVެ y m%I,w*<^kwɾ웨=߿8E7<;/_SĈI񰖽wm 3:o꼥)W͐QO4==pU#8 eYmQI^w!7wGKrXm3MɿtU-3-"{lܼI<5=gvtc2u49#>7jsfI#7Zz+\9CaXֈmύv][h( |zÜV?\w+GppECk9#c M%/G436qXFlXGX1we!89h`6=IR;Y-w݅4̄Ш+F"CsWp5R'IѠ$>.x/)ST6>ǂѽs}Wrp`SvI:o)r ; Kَ˪7թ@mm W:*q[*IzmۼҺGph$m{IcŲiG5t:47oҍ.!ug/I)vQY:3u߄[;K 1E?TJVEouJ59nZsf$;g F,9j 7kVn)0y{z;/ 8>=q<6^X6_!#{7?ؠ$) ~}M*tO{ԛ_5@U?W,a$5Wݟ$yID;x:I>pMbwwo+~oy^e<;-S*oeE_o~]>g?r'ߢ`<"w^Y?ڮ]?ܦgoGWZ9P,{X ]&j,lQUE3`?^N녿 =Cs޵UK5(lĴ*2jzNeJ_YTՊZQ4CvEܓ34;-"%U P<Wcc H$FUWWEdpX`SfxR0 (PFe2aཎ5ơ_]2 C=zB_~EX,1uϩLSH1 *H2 C*//ʕ+rc`  0b1)4s=W܏iZlEuwNTKrl8X,$#0ѡVDhT?OTXX˗+''Z=CqdxS^m \iZoNoHKr۬v0 E*//$[N>O/VII5cSƉ'NCGM--өr۳ -J9790 BE===x<7ojjjKMqX`ٰaCr}-u\ʌki!iHyDQ UVVb_6M3f̙3km~X`bmWhmڵ!h׭1-seǓSm6,ZZZԤJUVVfA{ɓp^'Cq[6IrzkС[vHh2@X,l:}U]]jeddERMMnVYfMFLU p8tLxo81p b70 'ZNSa[eeeZjNgj!8a*H} ʁt9Ψ;J$)%@L$Uuu\.LT{{JJJ|regg p!q0 oǵ\_;S3Zi9z9:M8Q%%%kiɒ%***ѥ`q0ƙ^{M%%%jmmXJ1Jۀb}C!=QT[[ IC5ZV{ziLjCqb*(($#c24ÆK &gg6Kb]풆OI2 C jhhД)STWW|m߾=$` 8:;;URRD"#cc;uLEfb7 CԡCTQQ)SfZ`#jFpQ.JSmg;U__ p1tql6^Hd:ʵ&Yx<.ǣy楱:` ۳gOr"q#]ө3Ox1 C .d>1` ۇ¶m=i6LLn` K$&Js5WS"i2 C]F@p0FE"9~_ttUfz'#n&榹*`ڳgOr*o{ $#aSe*\ ! e$IoJs5W K~zU__p1ci0}w7eI:.]B!M6M. Ap0 vK#iLAhyy\.` ڳg%I-4Wsu,Ѱ44M9//Oi Bp0E"YVm͝.tHjjjTSSp)ci2MSOw5Wg3LiEp0)##C4 9874 YТ"UVV(!sСzpÊ򸜒$߯r͘1#U`4Ƙh4*"0֙tsUf⒆F"`Ƙ Vr++4%IEEE*--MsQ-C1'7Lr풆m,))ܹs\F` 1 C(â"w_gHsefwLVbUTT$7714Muwwk``((t:mL{`jP+=7v)--UQQQ岧?tgϞկ~+BC`<WCCn͛ ystr>gݑG,"4ק9sh.  M֬Y*33Si*H$nݺUNS/bQϧϮXkS[@e#,aS"P~~***t:].S`ӦM~ &7bYV|>uwwY&MbQyAfTg~tf@ V[#KKK" Br`:q6mڤn%HD"v566jÆ ڱc$XӦMSOO?ɓ'r\2MS'NPGG~% y<\d; 4MM2EN3688}Q[\~g5}@5rG˖-=ܣkz\_pXW# iݺuФIݰ;vL{QooN2ٳGd}/,ͦLpj``@/URR%KhppPk/$33SDBPVV&N("˥o@{:ŀKkʴp< PFF|>!8ƈC+ꫯKX, :zN8~Z999;94ʯM'OԔ)SH$۫B jӦMlrZpJJJ$ mn:}#ĉe^orw<=)(??_eeesa߯-f*a^q/k3et뭷ꮻ kx!!e:~nݪ &rF8qB?.IX,ZxJJJ+ݮɓ'KN>-ϧIRooyhܹx.Gk(GqקK}{Mv 8n$C ss---:r^|E檶VڼyO:ICމ'TUU\QD"r:V<޽{o+++K~{rH$+Gji)#>L$ redd0 % EQk}侼MMvҌrJ=C Wjkkefrgc4۫kϞ=:}Ν;3fhɒ%o+˕\( Qv]ϗ4%UDBC555.K={^Bi IDAT>nk׮]:q>O) e _hfǣD"cǎ񨢢BNS6M}5@p'g7eF\DCCvޭ9|۶mUP047_VeeeriӦbU1c֡5:eeek``@ĉӐ[ZZK/)kҥ:u\.uAE"y^}P$j= DFUeeOw 1KOaWƈ ef M[t-hܹC /b'a#͛'ժ+Ht]eeeWKKVn<N8!ݮ@ '*33S===Q}},JJJt1% YVB!~J$ھ}?.ϧ-X@3h̙5k\.W2|wv]TCC^ʆ=gdhPY;LՑ*ZMlx<3ghp0]^|EꋮGvءgZZj,$ȑ#ڻw222TWW0dx éS&7=ijj$eee)(##C>Ol*,,$b1[N]]]***ҢEP(6y^uvvj*,,T(RFШw?iOCYYYu7PkWĦ}J؁nQ8Ԓ%KtO ˡCtt^rw7MS~_[nՖ-[TYYH$".ϧ>ݻWӦMSnn~rrr588ٳgb$Czedd4M>}ZD"rUUNN<7vDVf$:uJ[l?njΏhs,S; R"?= oF~,Xyii4pa޽ViiB‘ ƍkɒ%ʒi:s挶l"˥ -X 9ѣxvV{VX1b۴kÆ jhhax<1c,ޮJ @:~ϟ O<)áRICvuwwk…D"ڸq?by̔$饗^RMMx+t^y#,^,ynO\hᄡ}zk„ 馛R&DTf+ڹs/^dwA;wN+WTvvLTKK5a„dpWRRp8M:U999na*ԩSTKKѨ%I4i:$ݮKOd.`P.K999X,2M3 ~9÷mkeddS媪$={VT^^.ihgㆆM0Ax\mmm| ںurss-Z07]w%ۭ^\ B*((Pmm>kҤIipiZz֮]h48p@999P(>@@_W5wܴ|n.]O>nݚ۷Ot:%-ө'NRP(cǎ^Cx\Waaщuuur\:zvޭaCeeVZp8?}B.A?uqIC# O555|!i ڽ{~mM:UAرCZr5رC&MQ__Brrr߯>|r8 BjmmUUUl6 Ж-[tg/--ղe˔uގ E"?~\r8:y?X,|^ө;Syyyx<# 5sL}[ߺCQFzgvZaIR,ӂ 4o<\q`xڹsVM}ZvRyyn|>YaZC=DhDppN<'xBOx)???sFiO~29z-Wiǎz'u9ICk"iŚ0aˆ;-_l}KDBNҖ-[T^^bq566[i[VJN;Zn,M0A999#3+ &xÇkr:jnn֮]4e͛7OX,#; KXLiӟ+x"8zjˊ㒆9s樾>HStsH$G!qJsso߮h4*&׫~*((ޑHD}}}n$\Rg :8{|I7Il7oF@R^j[oUif***=bhT@@Νf$M0AO'NЂ }N|mH3C$kڵzgF%IahɪS^^4sXL}}}ԬY ڪGyD-JX@ppuuuG?6mڔlfΜ*eff^HÑ Oc>s&N|9rD-C=wA$ɱcO!yvk*//tьL joo$ӲlzTUU1 Ͷl٢z*IS]]JJJdZ/kcwFѹs4sL&}S~Y,4>=*C1 i/~AICӗʒS/^hc^577L:r&OG}T^7O ` O~J$Z*;;{T5k,j``@=Nx@p09sFOϦs:z] C 8@ C) 8žF+cZ}Lm2vq,EϹI)%ohodΖvKKοV;IuƉÊ)E"M*e65د_qd$d}BYrsv!E<_|D7߷_Hso}LeN(~l'>o*vI  Yrr?&! 8F{?T썍|KHi* =-ylf*ZXzY$kE_U9ۤ~+8~B|W8pPV:fLWw#ۤ.s7?%)3Y>q.&Z*8|ڧOSߓE׬S+_b󎻿y9w>3GӷE.8PMV3"LynUV[oY*[~BCIr-9O);O?Su?|8ݖ?|VC=}xI#޷ ( Y%Ku$ܾ]d7&n?CIaJd?b~k;n,BK&$''/=9c3`W˪n ?X2R=rN?*2<e -D$I7FJ?ĸ:O) ![}?R${n+.>7wophUVJRx{g4#'ZB edg>|XRۇ }78 Z-Ir Z_~9n7K$[~qg$5/,kaJ sHI}X.k5,-v|=Yd[@C}`׭Wx-_u#w^OⲶ5M{Quw\dd)CEVz][j;<joP \!iߖRy .Z,##Csn..I-˶^{-O_uIVWFCC}$iΛ~\gr2 =\2cFwZd|ܒ-I*-6YaH%BX5!8 (?޸Iϖ?}hoݫPNg±s{2lO'Gڛ4I=\)Ϳo_y˛u˭7mUZr]p޾x d] 26V~!s5+ uZV]$:%'ܬiFR#--~]%Y]#!ACpNg Y~v.Y^ֻw![xӭ }$1eҞz\έݱ2)Ȟ#FI;+}hphUרsdVT}Ut=CayB?rDд*^U#mG koxGKpIL^Ϲ@g/f#Ir?5HR.tpu~dB^{,)$>v$)hdq{_7Cm1aÇIBs?=)}G^O肽56--$uT9Bpc!Nj5.WfSwnޭGK ~ZΦ՟}>?n^)/#%E9cW$5YHOWx{)!GpruV_]՟}|սyު{Cv+ߨ'xM9}023nss{d8JFjH߲2ܰLIoVNad)r8Ȟ,/b,O Q\+hu'ϒ(p*9O:Q){Nn)p?«VqdV}9PHmU;[:! SiS#/m :L {eVT(0wd>n<7]/qǴ7))ѧ~5/  Ǵ .N[.)cꝿY1}lr%ַӦH̐dy^ o"bcHOͪUxWz|ۺ@O=T>M [/aG qG(W_I6[{r1ZZ+ېwr0vهJ%nji2?q8nT9&MGni#;KGuBAh/G@ C1 8@ C1 8@ C1 8@ C1 8@ C1 8@ C1 8@ C1 IZUJJ<OWCa!@Oc… &O .T0a/$5k( * vuI8 Ap%0Dp !btsq@p !btsq@p !btsq@pЍYV6mEpBpЍ-]TÆ i"ڵk*]]f^~e3FԊ+,IҲe_kРA6mZWƌCnBڴiƏ/җ_~GݻrrrhѢ.  $ǣ1c(//+O着J555]]:!@7bNU]TM8CpЍmذ!Z(9ihҥK5rk+á| S;w*''G fM8K!s:fSmm&Nٳgkǎ]]q,UB PVV>}tuI8Ltc@ u˲r%8tc`0uCt6Cnlwޚs*]裏ԝ/-\λB~$46gy0aKT.RS+ɲL 뺇O[P(ե0EppmٲECef+{,iZѥv#U qC*eeeɥco [dGî4jZI:Quu~y׃XRis8eYLӒ(O?K u;زJ :`!@'hllԯ}DU+}T[-Inra[AeIirO:MT7ݣٳ;c.S:P oD]w8* Jqh:Ha'u||>9PH^W6[OɊ CpuoB;Y3 2ܷ;Abz~OWc>H^uuYJKKS}},Y"{j@3$Y^Wnkq,ҳ/C`҇L;3Oe4=VtOCˊ@4/{,SPPT;s1B۷2335c tIC6l߾]W6»ʙx?+'nh I2 9Xc}uھ}~MlΜ95kNvZ9^ Q{nwRd}->r:b)rqP2l fꆠ}-6eee%%t}1b~4<K?R{ד /^-[H,K)))JKKeY2M31 JK~.=MM"቎̞m} ҵ9TX Sf%CpYn.]B 0  Bá#UM}%W֞Rr+w@g.W3HK%V~p_4g=i1q'Ľw6***SOi„ }h֬YڶmzVKq;bxcR+Ka{a{4LM 8Zv9sqc,+۽=[o/BGs,RII 4vXF-_\iii:ujKeYZ~jlɴ$2eVG+ε{Ʋ=}LtţeYmj<3M7KW]|ʘ=a!8y<'H}]hڴiݻ^}Umݺ52p{NSF ),_"gÎx-\9ђY̌De'g_z Cpx< Bmw8pnݪ?P>Oyyy:UUU_]xi6n+)X2cH) 1ѽ0T}pBÎ΄9?CpkkơUuuuu~~e˖i͚5CjZl{b=lֿPG(RFG25Jj6f {7 *sW?Ӑ'x!/5557˲-)Y3eggk̙|zTSSɄ-9D3r"}[\fAbAO6[] Epy٪O9NV Էo_\R7neY0`f̘իWk ̾} 4uXo.?Nd[Mg-F)WznR n򲲲twiؒhvh4h 9N}駪رc5b͛7OV1 sݚ>~VQW[܁pˑ<ʑ<z|\~:UVV承iiiBIRUUUtFazz"m߾]@@>}l6^{5UTTH͏6MbWk[=ONN&H4 )z˕Tmc޽Iv_RCpX9sj׮]mlJMMSccc4ݻN9\.ܹSԧO͘1C6lмyiA44˔x ɾT~DMߖ/l]I6#z{\? Cpq:+RUUUjjjjVZZ*++ %)yԨQ>}USS#ͦ#Fh̘1Zh>8\| ebe[uR6[]eWo\ rlџt7!@OBp[#Fw߭#FhΝ ú}_3MӔѴiT\\۷+ vkJOO믿:"H,,y?,Xn#ХVf?eNyzyPRZ?i !8]x@ mv{ysh1??_$LiӦiΝ;wў͏y9/CO=ONOcJ\i9m\P T74)y}(rުSO=Ueq$9R&MݻUWW'I*..ָqd}V &';KtdE8m6knc-JȔ1*4*j5ĄDl6,SEy}p1{Qvv1M3&4lvkԩ*,,Ν;r4n8魷ƍ[($L&HЄ!0Ѿ>r˯\G^7eg  K} zC}8]{kU]]V[ĂM6MPH,KYYY:ujjj4w\ƌ1dk\qRʗo)~ژTR{+jIJzvm.Iq*7=!zr]] @K|#0T\\hp[nyNk֬QJJRSSeY֯_/04}t}Ltq{iW&4eZ6{'|>|Y񉌜bMQG 3| Q?PGNտJ$$^O<5iҤhpLhZYY6mڤ޽{K,{5`5*ppmڪpiEm@JlJU>E M C}?e\,07de˖i>|xt`{44 qF)777j:urss50޵k6=D!wg2\)COWC5 wvaP(Ni@P8?`0޽{'=puuuڰa<<OަM 5}t\v6lyU;{L'R˓ErZ!'SГ4W@)]4MYtyu *))/޽{v+4lyyaAAe׫7*//OǏ?e>Oݦq&[%#S`Hi_)8[/OE@˯MT8ՑW*##3&:țou֩O>N[nY0 ڲe|>rrr+++URRqƵ=⮊jWH9Zaˮ:w,U0ZYCܐF [,KVnIuQ]@ 8@_"ͦa[2}yf)%%%m۶MMMM:ujT_mج~ eZS e^ӧ34e@rezk5sd/p8WBp >S-X@2 #VQQrI,_|ڲe2335a„{*/8F~Р5xH7$+^Blճ5z.:izUVVvσJJJX:m۶M#FЀﰩI󗭓+ȓu`ҝJd4e5)u%k@'!8d;ws='%˕th*))Y\VV:M2E ĺ:A}Q\G%|*r6?Xy]$o.]hOJUTT fVĉeZ˞4h }RW$? 2~sh]U 88^|I+4ly=TiFH˲Р;vXijhhPSSL".It{@E\pXA~Ë[0BpVX9spfŝYLzU^^4\h*UVVjĈ8p?R C93Ic@Wi]]d„ ?~{9}JMMm0D\.Zeeeϗ$9N)+++&40d$Iez$՗kt~_atn 3 CW\qOp$̔QEEuGts[lp(IF'OV'iPk@7gWoN:I^7zr2aa(//OEEE>|Lӌ2 l?'oQ8bzNڵK_~SO=U_5r嶖)KnG_WTT(//Owz@t;ԪUJv=&4"K P0TUU.r= @OƌCdܸqztgD>ܗiIYU IDATWjj^BCCӋ/~Ga;O?OZ-YÐdy^7SO=y,e|x<P(zKg}vW 4c fS ٪Uii šCG@ C18haSدƐ]}BVCk[,Y:f &ءc0CIduwÛ`ع?B-8΄^jߴpZS[::o]{?–I9m;L?v{/W>׾ t7?zEfMw:urF/nyO~hR_Ԗhl@; :vuRxjtھTOm/aלcnT/+dүVM˫nzljwxVl]_?n߶Z7}PLĻT}*^=MO~H/Sfۡ >|@k&gc}^߱LnS{{Ki7j?՗۴lN.Ԙ}]tKt~$n8_XӤ<{5or`}yfjK*$>d_>F_0&rÐ7U]g;٪eѧCSfVBYTe9S屻6̕iY:`l44lJ{#>ڤ%fc_=I?}]ڤƔ"3vt&ݯ-_7D+aO~S}fXN]3FvOɔ$}YS87\5-Տ?s>+7KN;%Ӌ&uohv<ޑE& VOJv cwәOEV߫O_[I ]v}f{aG\W\_iYj %I#2~p:h*OZ\Z;,HW+K %O[m _~OӨ~2:Gcȧ}|~8Ԅm}^زHKvrMש}&|~O*7_je'(>1?Ws7KL|Q8vM(6vmC_ w\q7_YaǝEjz9ZPUP^))ŒTۦ&kcvgG/^ >v۝8 {.p}uhPZ^}?I%I  }g1G|ۖI\y)f)vg='\L._ZVlP8OK'JRIn= BCWq(E 6Eü}Uٕ`q$9^^$TL&)]inطun*]V|BW@\^|N=>Uܝ%UӋĽFёúnJ]9x~khﴢq"wXw-*B!+މG_[R7.~%1䋾>ꝛ0C ۪w|;VՁCS xr~Vl{ꚭv^=Q9.U}$_zd.->^?j$~5fitVgoyv^C⶙k$%=ݤq.0dZ}5.Cr76&UK"~U+_X,Ig*I_ZJÊx FKyٔ !ٴ@4-o7~?=a`+w\m|5ɍ.מʼɍ 4&8MUCNR iAJ5|ZKUuJԪkۗEwEwrPq]yE}U|X_~YDNV}xsJtgtꢻt'O~E:iZ]U_m׋[ӑoPIn_=L$rgaD -L$grRF{ '7&t=%W.ؤmYS conxܠ>|P7.k G]iw5$#J?^9uͲ?ܟk^3?^%i4|V&zj<iJp8Q= @[MO{>X5[42 -46{$)Ʃ7MKOLK*mw:T gQIpzpo%ib~JVmښ;R0; ǓG&_@C ]6s)]O6Ӫj 52fMj3T] >UӦ9k>LucF*adE^)JpדBRds ftؓry Ҿ]IHms}bauZdV498dFO8Xqq]BY[| 4fCa7l7Rle6o~.I::oTRc9q۹\RdPxW9Y4g޶ }XVN]^ ʿ0fEq@ݥ7Mw~ZXZ˫Vw/V4Y?y54ϰ>cEi ="sQT4jB~M5$a;I 4C*$`˄b1"OK$CvvjkkUZZ®.!d0v<|x~vu98z{lIq;50k>@wÓF]ఛG-u1S9p4V{ƻf=|ڼs֐!CADpM>^Θuzeuجmhj 8UO^^[JJ5e H*t:6 ?W O?>H{}ǷUse[N Ǚd@@ l,-ݥR ݷ-m{t\` I{xvl9mYI8$ϻ/9߯SKz<Y5mlZL惗7bT%=G{̴ڱ\~yX,ڰ+<Ң(ذm7+na¨b&.MN{RB!ڲe9x w`󶝴꠳OWw`4M PMU `Q;9Yx<9zr?f55())I9~AA~B!ĉkO`3Pn9Kj˥f qjq('P[[QVwv=tab6Cmyy*]\wa=e!Bرc7ocæF Wfv9bT{)Z K bGT`1+=@}?^NFa^'Md䉌?{B! ㏳h"rrrb0QCQ'7eFŭ҇/ qzHm yC bq+*mkkog1, AEH93//'Bm۶;E1mY( r\hݏ^YCf91u|:fΜ9"B!??Ol61#[3&@^y!N:8}8FX~mZoIy\ vy7NB!EKKKǢ(z>";7sBDEc@9yS5p}}cK8|v{cY!Hۼy3:~i'OJ,^ /g3ɓP[O 4 ad&O<(/4MLIǚExmpVnvΚRMi7mpmws7tB!İسW^}Kଚ-+wfрྵu[sdAe͵#4C!׾5Vq("jjsE\ScaqG/ԅ8IpϿg5 i[0zf^Z.㫊T]28xn|qBae(O=,z%VJtr*'Xډԣtml\]¹sv%p(bD=裼ko5reF19J\3f#|\5)iqJa8W_;d" !n-UUD"F;w.۶m͖s%XacS<1TvΘ4~X" fY5GO3f b'n3 EQ~}EvYv;?0ԁtnB!Q4E /&k xY#==9 o\{B>x5#=5!84YbjM4),,Q]]Mmm- _:Vk|gE:6٨*/fɆ8H0Cl6faԱQnnj~pcx(C,LDy7YjΜ\ʹ gڿUEB!_籍O/kaiv9.4/eі_#7\ŷ:VQ!zWiooG4(^۷su=M8q"ͬZ;vFX,Cn V5v[T q,$p!vSQPTN52W]|>w|6ܞÞc`a6E5ky] 9rR,d^3Ȼk01ϟ?ϦM(fn* =m}.B$p!vp8*Q4NFRÙO'0?7էjƧo3Bqٿ?FqܹK.x83bÆ tuu Uunu"8< ff0t } nsA:SQD%N/~yg_%s,~gO0}Lf IDAT>bUBҒT  ?.Gc8>3>#]6tyC)((f!CN~~>P(ePY,n7|>1MFHq T(xBV$*!v]7pmc]*Fظtn[8Ko ߟ˧-vŇ8Qebn ږ]ӴI]44M#B vGog~,~2E3")7͊FzJB!':;;ٱcp8ٳ>;#7Mf6l[gP>ՎXBN$0Cl6=DwN6Ûw秣+@Ya.%*/bTyo,??_ͼl 9.;!e±g 8EBG/-%wH{ᗸGٸe;?B{1b(.. #jĉ"js5bJ8(}z88NL7;cXi%.ih頥J ̜Tŏ]wY ±'B!N@ ӠPC>q}핉l{3}qI8hg0͊f%oyi综w5_vrIW!DQ6n܈躎jeϞ=̙3't:{/U7 4B,#PFt!Q l膉n'/?"r=D":+o启+^w3 [٬xspGU|4e} 8)Bq"~Z[[imme͚i)gʉ[E9[I#>㮞C{\~,Y4 !O=@ "p8~QN3#X4Bu5c qP,Ӏ5?/J',%EXa+ࠀ](c_ck]?TS+>`h#}iB~71#=qJ 7⦅>HOG!I4MV\il}1cƌcXl (k8$:OӅ3IQYcYAQ(/), >;G)v(:pC F&LboeBXOkR |!RmN.O7#=!'W_}v'0''`0HNNNF땨( {blV"))80TUnozbFWЌlض,Z,h84 u3zh>8ŒwVTbح)JÔu>"R!飥Vgn"[tl2_8jZ{`J̈́f UoED{Uشo~|PPP@aB!N}ofvR )+UJ}KS'iTN@ B깥nmi %-y9SxX!ĩ'@UxaCCƍ466bDk8#Q,6rOӑ3HAEӴ[' %njaʥ գW߈aPI iZOUUc Zm<4ngϞNwPQjB'>BvE#=1̲j/`U/{`"f۶m@%62kpƍ躎i^L/YZX,Fm Ǔ8I05}@$95diao* AqVM>.=B#! jEWkc>y"mA b"!6lϾA+Fz*ɚx>˶TB Gy00 EQhjjbԨQ-[$dN`bj[xBa)J_oj2ch&*eɪMluX,FiQ>SJ{w}} 9iQYw_Y8G躎jAZ43&' anr8#8TT]z !ȌZ[[||=0U*} i,Mڢ ·=#fn)LW0+N荨LY݄$)WN'qw3o)/- ||߿!ਏBqbb16l؀(D"g…gD"v;f6f!c]bYGV; q 2Ixv;rx^7~709f`FZ]|b aXD =jjڱSwD,7M2Bdi|uU:(Jh4:Ba1䁇5MX,ɓyw+ l2/h& {;?}CFBH0WVV>z5*ʋx}ICl5pƿRbb`7iXl)WetlLnwP|jKB!O~kgb-驈buy0-t""{qW"I'jub{I&Ûoy%KX,tn֖t:3RaZrÙ^;ic{JJ- cQ5Z8i]#}*FnLEEѬ냎r9WEC$/HơB---}ʑJ='J`&?;NRIprV" &>$'+ yN}_H3b*Ȗu#s7'in>&O}C#Hʊrjk1nt%8 !Dfse=wRCn%!P({V## b&b1^~e&Liӎjh4ŋ㟽㩱7 ||3[!3):EiجtRT1O,SDE4AC( cL.\yzB itvvⷃ--8›ZbHG4M#(ۓx %$z2&} IOD_t<Ӯ? c=z4ڛ,y{%Þ6\P56ubeo0Ќvnr SBdi,PGVV.@ 'tR4 0hCQjkkF۷ffoFGWpD7@QnL OU N9߽qգؽYZ:Y6ՖS- cH??+ֳy.<^ǃ$\r҈`4QO>$gy&'ON;,^8{>qt-h-iCiZ}Mmhaf=Brj +UNgnxF{\uhSlwN@A Nd !KΒwWF(J,&ވbC^5ngBU6'P;֮C1)|먭XBq4o?c:#3:z<6kEEuw`h(_n>@ N SOфi@4&L@kk+=Ozڵ` v飘ԹqV\!Nm8 _\dM|s)Iy%!㰧TJ49vlYO^RmWл;   Fh11`Ty f["k!ĩh˖-)ɺux߯qbdYɰҫUbI{'GQx99/Pxl~±I%柦_X}{ &ͱw{rs?:t"]<2:"VF&G`%Fa1܌kDﬤ[p]Wݍ'܈ͦ:7nn3uT6oҥK 466bو`e>q1|7 m@FHLaF)jRf!`@Ÿnw"b忦Q݄wb**f @kkO?^aeSi]cZC`(|"|>^À;6 ۭB!-[&`وba1%>z^T3oA? lV ӑrESPSQ0MEQ=,powO1'/[У/uVnO1W}wx !8~ u]篏5141z7 8Oܪڻ]M =ԞI d⇆4}K/iJXT{/&#^MGb={Sz řEO^&f{!?N~B]ģKS iT)* N%B8 (8m|,*6M@K'--xVvfnjl!QF oyIDߓ}t#k8 5҆n'_cWk>DubB$pAvLϸÞCE7MUЍ̿=-̻mp]Xjh(@,tc00h&Vd8{<λXYB˯<:\/>|PӅb2FQ5Ϲ%p(8,]<;tj6 Z\nP2 ByLyLS+o{yavʂ{^AI`6B 3 fn4JVU%mїWSzz .!ΔĴyT_!FBKKKρ@;B96gr4%m媉JVUiK^e͇T.[!] s]EXӕ'-ZI$<#|f$0499bQ |_w}MzPڳ!N a[Y91"?T=e1L)wf+ & 7gwOM8­쵏'V47XK΢xab1tEԴ6ciț7_yB+ fDv8WL ES} zơEUX2<\&ܳKk*n+P`g;&*V3 >bD^{~klӮ{ָ X%&x8L .T5p`נ GƬo~1Ciz/|o "&MTA 'Lj{NcŊOqϵ1o$p(8<4T| j+rlP- < .ƵJihbgCxsS#>n7bcj* ŗ`{;3`t!YsQAAbrsӻ0?bm76U2Ǩv\)!3fDy%3}kF1;aaOvF}JsˀXJdL/abum3ciΝ(q9`{ ^}4؉FIͩ_zSͻ>Le˖-de!ŸyCj MZrpaP{Q[5<>_6w :ͯ^`l^LO/c˾xq=oŜ8w(.{?w:`bEǺd4XM^A vM[ͦl"3ncZbL^_,+ϟŻw ;҂=i IXsUIn$,j3\@Qxr%{%teђ-DB)s{/:B!Ye'?~Iv м4XSÓTu5;)+PMN 밯=BC#j-Dg08SQ7?xurJ8yӫvGhF J5˚1pk9n%Hxj'dhƯ"= ff#lL8|yzΜ2UQxr 伙ZRgk( )UPsDKSBPZq:#5#!8k rBG^M<'Gz:Bۿ omn$iTӥy{U$ 6im8񸬴U1+j8zԍ"4wEmUARE@W Lt@@3v(tHT'fpo'Wж ݶg>IN8!İav, W̛k+z2?w4M?5[grSS^4SiZOyPopNYpL/29t;D!q/+:ϴӽl(iʖj$nOPƊ?iM67qĹ 9帉'X9a}G]9q{U1eiJڜr>rZp~="}wwGz:B1oG_YpfM+anYa=LaRe4Ŋ(vn*vK*+&w4ҩ,4MյaA.1ڪ|:Cl?«w@L7mFn~i9Yty=\yyy\z;vp]:!D8 F0ᕷ7r|gNK3mBǔ3gMiǢj* ̓Tc8t"8~Z[[/~euFy8LڞHÍyױa4Hr{ :&%`R/!虴=>AAAcxtIL 2M/þ}Lӌ_S-PJ7_xHOE!▭\<,{ct[ i*U[Wa^^B3Ɨ&}Yln Re'׭1j TYSkx䍭mGGf пWҊm;nI~AE ,u]ImBKdQUq;r,^4| n.9w:5grZT ']ơWF$8BwMGAHOGӆ_5_7#=!ixoW[JnvsIACsko[Oy"V'eB*btqَA_Cݘ|qT4쓛7eTZ>qE[&ҵu m"7G"$pA6P8w3_yggMi,~g#&T7Ξ[پKΝY01JH= 3ތÁÁ* !Ȝ`0g(S#=zKz 6H-!Ĉߡ,ch#GCmVxm-߼y )Φvf Qyo l! XTPwgRe.vڰ+S9kByR濦(x<9."XXCG{;!ŅaXۨ!N8 fnGQ?Wހ7f((\9&aw] ;m{XffΛmESLTYQxɷ8[4pUe,""܁Y{ QjB8+HrKB)P\ZAI,M(=T)NS{Ƶ|p/~BAA#=%!iOȃϾC^W\uD,|{UN67xe!0n'(|ܼ`8Br\v"1-Eo_\v+n]lIńX,~U%ICBOduvQ]Q'5xi:Li|=gԌ&gΛU˲(-rx`aBrJ$U`aѴI6}f$P(G>YY4!t?>Q+'ڴ[fJϙMDS(_V`WϸB YoLƪaɦFj*)&:@QzgEbs'.aOSg;ui Űi 4v+Nt[. 詛m3֗?k'8:8̠R4w|ꦫԎ4-q ={y{ϮVo $$ 5ME!BqgV_[6SBڋ둞4-񎟃 =gѥvl̨_Φ. cp;96){:)k&!"1˦QkGUQ sjQ1҅(64J(l\GD=Eד 8/UἔB!a)x;vߺ/vrN,؋PjY% epZOIQu\:kԠ P[d>h4+0̓#aU7YNrsU!u+ϼp4USЬ¦m. g~OaRjk/΃?6m.(Hp?G>?~ 7s"弴|=(;=qxI5|v4M 8JUy)a*U?]P-|oNt*SAsMӒ2eUe!8>~V.[΢7א7PIQ_(4m0Մ}+*楦.4 ^Ӥ9R?ϐx>0KhO؞L!1ԛ44d00J3]`$a_w6  ![ W.C~D#좥+Som兕mh+E^ssoxC->.QMy~Vҹbul6 ?l 5XEk~x)@nS} (].B8%cD9cL!;0zخIp}ro}R7\u1jka;]qXVeIrssଅrݻv1{X>yH<鰳|vT͂a|w[,eJM59nڄnc~<ƓOdni _qٖ%~%P!W0wyD>!NVqcO4 UUU dlCU!ݞYɶ-حN-ן8Yv D.4[ESBiƼ|n^\`7xi>{n-p 40‘AM8PYrgŇ%h(IL> sYg=ywoC]uj E$^x \w<ij誓o5Qvs*UhDOs4'pjC!8Z---do^asyRV{[J44JoR;4TsOydIũeXR z,+I&Mt2#''WKs7ྙRKoH ޏ%9O߿4ʯURn0MPy اa[bknL=^_n'q!葓CYQ ͋jhHR4A[}+/\ɼI%;cUY2o >%NDg\;).H@0D4!  g(?MM#@B $wEi(blwXٰ7g;.MRRU"F}"N5SNBYoAV|eU4-sg_s$Tpp*jX;ۭ|%[x%V(|ͽGbP 'o/?EB|zÀh'>9c-@V <6 3OnVt/u7*+1@ *V|gF;@!Jh!N2YN#'=ڠ޽lډ 7aYz\x=T l^*k}^v626j~PƦ6/,^ex5T򒃔WQesS$%z1Sh(#^{93',˨^j^94^11M[Ss Heφ%M[jxOzi:KVI6X@$ Hܵ=^ kM50me&d*֭]Kie n&+{@SL8..'Nd¸QG,@0_`عwF>iOVC]VxyR.lN(IR?J.-G{",C?"=n|! 1_/~zzS\%=1ɶcnԤغrHOOep{Ri+Wй[8:Ѱk=7?xZ &B8AxJJJ(--e߾},ߴȲ1(Y @ mS 'YoW57-4ڇ!6b>p6P1i6E]3XsiZX>V3AO_SZoD\/MS[]yQU5 Oz-C M{/a"5ԋ/h^2mmMtܳ{KؿAee{vlEEAƋ값eһc&YNt6 JǬ7l6G!Ga,x<%,Zx4)q 5D0ɾJL~$( A g^h!ZՈf_A1 <ٱ{/w>:eV#ڵM1+w*k=xds :$mǐ# k*PjKqǟ۫<4@pq_}F h4DDC,9y]IIjQfMͽ^* C9xġl0YS ٸi{mӣ@ 8\Һl2N=hg"t/=_HBFGbbbb,m;;L&111R0t]ؾcq[( =$Ņ n7^7zuKaX^T*NCL3 %xġdlc Ixb+$8̳n [oׁrؐ afLϼ_q7YؖC>Jj y 4qY#%9(p}|R# IDAT8Bن5I n4qĆnVAxZSٖ%YO;͝g(B8w$9 ڋ 3Fro ҵm/(O% `ݼ >?>3mX%ÆehI)׳~,]aD8ogDшX/B8H7> RuAa݇sY:HjG_: {B $֤` p[4lp7#J:Ѭam\ѠVb`^@ɨ_ aY8M\3sS.ݹ4-c]J>_|`O@Cj+$IsTVUqoR썣kfݵr/M !!H0h3_f.Qm y2Fr;wnQ_wo&%)Yпk y$sh:gO_PeZ 7eʬ{ẍ->9> u8 K M NC !Io/v@$II[Yr-|-Zl2= 6۲a !xI&>>6Ȗ.€C}utݾb okr;d1Ve1تnN@ j*l1m/!Ȧ8jNC "bp^ ׋]{x}7w8BhkLݱ86̤ v|:х`7$:pX1,_3Z;gXT.fM6Fg)26UYXiJJJ(--1,!Eh{( NJ8nwCJDkP1RuѽXB횲;=:w7(1c\MFkb988U9 ^x9̵?TAdq~tqP 䨳{7P; {E5] kcܜl@ 8L"V,nfx.)oa%k:w) cbfY9.K&ӵG+$..8- O<"cƌa۶me#bҹ[ORjJ.bu>+u# C@ hJvZ1YR@ 8xB8@p| ãgg󼏹tL>y%aCGĆ `0Э@ʔLy'AiLדs?GQyC_C*jX,l޼Ç߆;! g_r=:ۤCWےR{u5PoUbVe@ h|1@pիWnݺh#aUne:~ʹ)0}援MTΖ-['55;wv#!1n}˶Y3W9}p{<$ueS ̔17N,=I&[rCrye 5.rssf;cԭ7' os[kgL OJcP ╴9N8-J:+,˱$$I9ToԛB3/-|^ZT3{^T8nAYk^YuYt-EZsMC qڬZ>m15ؗX;Ol{)6ow}b!''2z@p!VjƋO%˔Q=xl8PK%DǎxhPBmu E*IR@(5eجp?>]-à'LqDh׮]yTUEUU<.+EX[o] zөS'.]ʎ;0 tޝ86l؀j"I]zANch_b {+v컠g?;JPQ,11&sL2K/#SӹoӘr`4FƘiө!Y _a4A+!clNCpq#@ 8Ĉ#HII sb|jkoW3~lٲ233INNf۷F?ҭ6pT!}fӧn 4g1c">o  $= O˒?0z`wd(~0tPL&,vYj$ѭ[7, 6lnDC=󺒖ןg>]¬cqIoi7fsXsR 1@9_}?sǾNC "Fe!@pzѪ!Fjmi-!k^{hMT}Ksiɵs( Áf,,pxxVnOzZ*O>|>o-g eڅVx^P;vb $I۷o>)((͛72( {:&oNg=~>,ڴisO@ t\.j\(Ƙh"Z">b <5gO{* 3a;vbajΙDETsq9YէʿE+lDeTt+z~^4>ITk/GGѪ;w׷?Pk5u+ *{f~t#gzŸڋ`fv /fEG/h!GdƜ=m7iJJA~'YC- ;s#YO̥P ^m۶qAZlڴLPU[6aBb" }pn`T<\no=s/m:rk@pTe(ﷱO7hDxoY?CUVaZ<9%A\_}{/_q̨Cݻi3P rA4JR+׵1pƌBB>% S7v7[$IțM4nݺQ[[mصkWػwo@^Cy.UHaRNys:Z@ !?biTC |uEAQdEՋ$Y`4b0EAe_D`0$)"KYݨ_n#Mdd)|^s IrKc ʭTc7( EAQŠv`0̠(ސen kfK pJ%hѿL&L&F1`0Ab07b ؗ>_P9*nXt9 wA_ÇFaSbax,]ixVn6v=x7mFY@ߒd>kc>ݢ8ޜF-.zh#q$-]@X/47b[n(v 8^} )) {oz9+~#~ ˸f jx_G#чH^UK_(zW`[^<+Waas~i>|{ yrW/+`2+x/EnAWI^atՆwնUTl[F@ H >N |E sRm%{vn'11nݺQSSÖ-[HOOK.ܹ;w@VVV$.=zcc7 ֒3zS'6}΀@ C"8*+.G6E; @Њx6@ 8NeL4G< "YX~%?ϷA۷ 9g4Y<,3_'Iǎ&slmET@ՀnfhN'ηI2u ))/4qB =/t\gT01Mܴ|[+/Rg05{q94 y{Hq`P0~ͷjY/.@JmC)VY毿Σy{Qmc !2111>":>-{+hֆnj |:w Ixn<3zm"*+h߾=yyyo>h۶-7n,BQm"3{.Ǘo=3p Ɂ~l+/YU=vڅdNvqV*J ֮(w u@mUVa4À~y+qwݎa)+^[pfO9)1m{DxoM?h55> 1Nn4<0$>fb8 @> tkQwD2}ljǂ?&B8M6Fjac`V]cM=T2{=w6&0rp!YY^w W~t_8k|!J`~qFPn/BEX0 hq`_N|[qtƱ}mn+9A?DDc !e = _M+bLnϛUsJo`(5VSu#t-[HII{۷Wع ]x%$X|\o*7nV}O=$F47~ kAC1v-S95oh1p-:Gp%Ǫ4n^T #n ؑ [[2hj 6;I-pMwmaؠU z8lVS)) K|V ,^V]_#q0OBUn܄pe bt.Y➿00wv<L9}r fNdvu LdWĬQ@eΘ82|qF#g|hޗkt2EJ"2}V匌 v؁(xнp֚3cut_ןs G-^w>:Ý#@Sz&G-kk0f%~` NINC 2Zv|4@)gA(]fx 19ۋM㸱D+AK,rN>a1S@SUj}ˑڤ injs7ԋRr\mzV-.n$!%%W"73@p~ɾ]EAv"cu~]xۥlvI.](++c˖-LP>~^G_ʔ1WRi38iĩp̛7{~ y v8%[70ej\7 ڶm JJJ(--E&fG;F9FۄȥM UooQJچ]v^oBWKߏ{(Սtihsׯ'z} [~S~?VÔ3;V7>~r)'QPP6F 8TĈ?rL]|ҷ7ZU~tȆ԰x׮c1\L# LZU% 0|X`{-7`:saE`0R;ol]s/eZx4IZ&hnO :7~7nxF8<}LTyqљjW>_DYLԱٽ~1!55.]pAvqH$O}iOO3zك-b՜5z(7^v.guv0oqȟũL^ `hbtXa3rbfZ#GD; qœ9s5k`Z%\| 9?Y )7_OnѸMSR}$<"gea~YV $F1\ @![wgPU,E]ir\[/TUVotҥmUUU7j'#.. .P^+k2ѿWϿhٲj1vغu+%Pp}Rzfɶ%l#5(**'0k O] (e[F9vt`R]UX8lݾd! ;Zz4 {O>԰l2?~a$ߗ0#_ rJq*@}w =qk g`:$NR|]Оa:DI,Fھ#} ׍**B7zr};D@XQr:u_jRHONo'9Nb~ ىWW IDAT\Ζ. zOee%؆x`n  uO>~UVR-ĥ4=ݽ@ 8w|O\sR ݲPU'}r,ʊc~_^NmFYj-;N aK0慮$^KGJ7@mC]7M gaFd آ+%1z o¶ 66G>>{tkٗuVl5X2A%xk6oz^/Ν;p8عs'ѯ_h_MQQ ==ht#I&XL \ܹ~Kzx׭G霋P \'{59Q֕r st._qRmW܅pD{7nٶQ;!n"B8p8F[DIHM bxiBE 䦉})޲=;HNNH44k;]ɧb0(j<7W'oiC&x9zW<: ]9/#}ېbUjUd2:C~ĈãS,!5KuB[# 'EKKۆީXlAm ']߲,r` J>_}޺Xn Es}*u}w$q43BaAv;b5?B\ G||<մk׎#GruE\۸5>}:w&66kF;c﫱^Wl LDnqIuOfY9= _}0t0UCnQ@eum{~;}acC2ќN<4ڮUVDNI8fT`iXܿ_s|u(SWFG1mj<.\x*LbߨhzeʦvBF1Zf ,qFN<؊3v \.?$'Fx憨uvIF&&13{ ҌF%.qMK|'T CcB8EEELhsL^Ws{η ʿ YO=pyMnr\2dAڧ@Y}gQYϒehV7ͳt[ع(.<w=Du|^'MPSq(t={qs]@̔ ן_ 8 i#μ*9H~NW>w)elZ Ө=;AV8S4[AvlT֪2a w:qqqQ8RGUU}-ñ޸=Z40bhFB/"k'F]S@ he$6^Ŭyyjre ,p8Mh}bLڧg]㞿JeSm4#`uulr\h7eS^65RƟfR3O>w[cY&Gm^"4W\]mfAYރ! ڟ}}X/J/vd$?~èv|s&3^Y& 1W&toCZo7^1AV[0[xG)-- --tQK7nl4+W2~(eC<{]ϲ8^|Nj{ @`vb`q;p:l 0?e\_~iAۤ${CA>jGvg>٢єܾ C͔q>wޯhP0SG4j{͕hU8^'{.X>|gEp?]Ę3Le&9xկ M=7dI'` zF T+ts y9}¹Q>*es5΄^s|\C/LRJpxgTSbGs~8,\qyԩSSx۷/wF4vMee%{Sg׋ܩc)6>5?]g/J ?d %/g0뽈sPz^Fh+ozrKH)9t-&f`:,dn[v}~!㒝;w7qrNن1Y;o4Lm'b;P5jl6cjfuvNcjX?sKW\~tlRh{ضu7/0H̺8Iߺ>Fs)Ʉy}5-pn ؗWNxټQfx1D墪ڷoOaa!ݺucΝNM 'B8<5n<{oic1tytL>ONeq9+L:1@ X^/ÅR}_: t5K~}}judP:/hTCzP'@% <"~0}7#(! կ3uġ@ HYCEo=G|z'\n=ێͻJHɤK@plL.9mvӻ{g2 /6]xM8iXOG \vhx$vĿѢю#Vbv X F =h;! h#v';).`jƞw)vjqaĀt]攁=omiλsʽyHwlsbp!}onxq1䷁HpcِMB8`6-tyh"8q\N!,ơ@ X 4t$R[[ݸnL6:`h̔8݅|rƷ/%;M Ü"7 k *v{#u6L?aN a glj8$])N wCf5(I!EAArQ~WZ_OTYR]i& qv1w=m[p)--4#@p|Ӕp(> h"F@pе}"(%r#L`vg+gne ^^6q hXGӁd0F; @p arEZ{(کwU,]"hơш@ P UUINihq|!? `rU>䒅TV<*jaN\;FoS% fQ@#A X󇱃lh"~9'_+Q;g>Kc߬jLBؓBX0=i|-9\YDqZr;b ^;1TQ}KZ;<9Vèob@1JӴ'Sꯗz~&fD *-M e ~lġtN/!5iܚSGJٞ3ks FP֫VjZ)(kM#voi=ē>nͤ+f[>?fIr|6wU#S.7ov&Vk&)#@pb!C@ 8 TUEBԯtKX.6=u]^G3Iu{P zQB믭%FDLˁaBD$̅X' [{ 1[k($%(j=L0voڢ!u¥.Y1Z'"$ V]Qƿޘ5W^n/-boLBRhu^0 f[U:o`6 QH@ 8¡@ ijpX'> bb\ 67|6{JP+4bA eYFӍV6  Hv*R0~{pꈓfZy얎$8x A\l y&P]} V~չ.]džUY 'B8@UU$M )<ʴ$͚(Iswh+ɜ[Po?/܈@Z woш$IB0  ުh!q\̳zN9tرcm۶36fT0X@ 104>b$J*y\~F |L8@ 8¡@ M͛B/JĊ`,qPQ?pd- P4T)8:$%7#j!^꾌i4j>D v 0{T+1&) ckZpuZ]ES}z\aae9PЫ^?~º ڜr;|RHOOo R챐?IATTeؔ>\Ͽ_9nݺ!4ҥKc|[^^N6m@ Z1@ "IxB.^oA1 zAp[K5yLّ6d'%}'Xo^l#8|Pݎh!b͘M;#`sͭ1Wqw8A(J1ZwsB%-<|λzv} B,YB^^RSSCff&oQC G?p9\xWjp`˅gj<˖UTZ!n܄_[FݻE%5p|uネGQwEAEݹ hV[m4hՇe<󝏢{R*~/KEVxu2ʜQ)(X;%ITk zQqPKܡCR[XAdĦfcm;#ک"jr۽r]R>Q &`MmE$ sfxq-wSYy侧4Ǘ_~%--]v1k,RRD _@ 8CZ?18 a㴲r>S'L%'B\EY!Hh4 G# .RlߍV\LҒMj3^{qp0rnM6/ͷrw]X{/z?t1XO}i$d b~v!hV+O.5D ?o"vc,f[>p:<^TBBڤMF֘k6-$ȲmwW8{m1;Ltڵ I(((;d׮]O@ D?ވC3 Swj외)1әg`:kS8ndyrsxwwٳNii)l;8G/ "%±,ǡ#iؒhBM72+ywZ³ڵwmiKێ,gE (w e?Veh) $& Hmͻq,ْ,#I|s:?|\TZ]H{oXGu$l$/tLeলU%7I"'QBy&KZ!ֻP4g^y3+Yd8=Y1+G74X2̧k|̚E'2,D=N@ 89([npuj[Hv'AJM I 8)= ߣl|Ӊh?RQ+ܹx 54P?d͗\h ORܯ g {ll3ϿlK||4cFna $ ^|wOx1~75t)O<oG O$9 -Gsq~)-Vi$}x#&^<1tX/D7dv|k PUT;^֪F^b={"()̟o/$R)e/حH~`4H' L$VVxP@rbح n۸Z0Vbܵ%fS {vEȍ{xX SU1Vn t|~J.v `NH5zw>wJ3YN6,C@JawDٖB}`nxf&G~ t6lУAQзc>-X^YN7brvVq)) Sq.wyYÈaaap^B!~7eLS&ἱ-j=3WU8rxq'!g8Q}OLЯ/ejvw~a~ZDN< x IDATܫC-Yw*~V[q؎~ l.=Hi1}P+v5"QV@ UU49i-MeJZ7"TkҎF}K<4{VT!]FK(ك dffMՁc4҈^xOi!?C#R|[̫ޓI\ν XV|aRoIC|9E$jo}oX;N=j =٨;ٌf|qN-w{xy"8_nm$S2PSЌፑƼBofD%S.ι 8sD"F98>+V Y!ze6 }J]Jpi~|tN"˦cl G 8~,uCef|˖뾏O|i\#VWMX5No2mmgI""Eٱc'¡V'Iꖭq_ PU5x$Ax|*sB|/ _mqp՘B# C%UVhR9kT3UPrz%_x?]{-_|q4.ǜKpY8>zȩ(i T{" [N >q?!1\Nܿ&pM89(-²sܣE]ǗSa9797q3bj1,nA{RtZ%XO<8 5t^F?0X= Ӂ/-{n&)))qi&8q"ܹd***pB8CB8*r<T@PF÷dj$ zȨ@9' dzQ@ݽCYLS&"w6XIw`>d kܯ ia wWQ͆D| ̓s-gg쩍+bЧ4L퀦9 SE7h_G՟!/)`ڴ$R@cMY6֪>BQ!$Q(C-!}KqGqiB4!Fħ!{Q$Mk;NFz&](Yz3'l<=CcIɦƐ9sowYV^CϾ5wc~Wue 7tjbdWp᣸?c2ύ@SSk֬ѻwoY~=guKk  -[v;~Zp %4?iQ tP6n y3X.8A|C~$}I׃5X9}wcvOVK)ыEjNx}T67`~u﵏χQVD2T"=^'u2e@(5.-QzD _lRXQp@ 6FY^ pqh4۫}7.a>c1lρq Mkл BR~GYAh>*o? 8EVq* OQov"7o&:}!A5x"u?Σ4^tGW/X)lk 7%iA%9Ryx&(Ivm***/oh` 'q;^يfJ_׮4GHNƐh$R7'w f}zqq!CR84ͧp<@ΝoO`;)v%\O4o8t>ՂCUW_GH6J [ Vb6#5 ez={"})zhц[y_EOY7_Է{n- /#GwMr&(JtQ;Ci/pb:T\kEWhf MA 7<a)- օ,F𺑼njo{24}kz0ny.Xa\'oi}MP$#vU5b!H$@ SMCeNotM8\t)K.`fȐ!uᅬb!77l틪u[[[ilIKUmp2Yښ/t\0;1x͙q9b҉Uh28{ٺuk\*.A8$C?KQlšr!`9Lo]DVIvuXb;Do`408d?77݊簜sV08}97SMY &\<_t$bؚ=UלFFAO1}tO|J8wb0;>`'+%cb&1 PPrGv{o(FĐ|jB;v k$a|eh8;:6 Q"pD:Ks[(fCj*_%}ߌ0;-!n ;i:k >ll=[lKs?C}فM7U843gLnn.@'F٪liN]:<+-<4K k&3#izP)k\ty'ﻙ!4v`4y=nwn(p(. Z~rnQ#]w-zr;mO-݉ـ}~ E|23aW^0g9w uW%ʒerz9$zm%&bh͸Wp<}{z:Z}CT?&g%kd26l0c(+WyHf3r> #6aJmm-/ /H~CʲQR6l^27a$>^b&2 }[T*|9$Jz$T矹0Fob"_:3d-*`Cssxt dzJ=,pO=@ <:kyu`1lX&Gzmذ| w4fZ)OorZz7nJ5o[{7L'c[k \y7C{'Cw\덜eX⾹8b6mԹ!̞={5L!8pz7`dh-*v¡ZSCign/GJO:_930 *l IJKtpLohn700ޯU'™(iMMSرVe 3c>fy75L<uN c/t,瞅!%$t>Q [6IQ]\eL_&1!,uYJ ]untD/ěF`E5{zڰ_nj/WCng|WuX?h~a8&@y|UU V /hnwNEƶm¾/ 383uv޸q#O?4cƌ$A6<.$f*>mT)'МP F[vNtB$jJw5GĶK=_ew(s+o7 ni0vb?`rGKQc7ӏzvnljHBZC܋)gZSRr&{d.8c%?mc+VE\WAYΏhoz_H;Zxz^OGq==>Zy$q\߶0A(F /| j4+$$2zw[/f ۧIc„ +PvvExhR͚8< 9LYÿTO-}0_yG˹_N!Ռ&cP[ H0JF/ϾۏyzE|-臚"m,cϼݿ]9QU'|N>d֮]˪U8ꨣnA|u ;5 .Phnnf4z=+d>hBӕld# |=3;n5l6=H 7pV8i^#p{ W֭GY)% {>f-rF { bi/i_w: j (km fecϾ+{@X0 g滎¡׋yaBh S_}qH^:wħz)lw&DC>C$9H%bfXA[Em﯁$ \:FWowCY d$% d'_@ykK ZW\ qU<Up`;#IeD/>5%u7u혖< E]Bh: }S*cذaL8PPPbaرQngȀRTUeH=yl=%vEH4Z6U|o%Kt%P d79+C~hN'>65zEA[`:ݨ;vFݴ M8l+`8o1r|uۏմ<54a)$螀~ʁ_C`njp bᦃ\ A'ѱX,`6裏X~=6 &슼6;}m$T쪍u=U 69rConyn&5-Ύl 搌8|=M^w\SК~ʦ-z͕asp4Kyyg*p=GЧ{K?ߍ1Mڊgg(W5%qO e LMCJMEY57#b1<PRww8aiG ο ׸_ f7_y?_PӅ95xuvÆb:9|BÆ/F<&b-ui'Y ةh:SeO7VWBG]eYKWhvką$`1P+TJ]]qб&g9X3ۢ=$Ho2r'^kDB ﱄW =T[hlBmBGrH4*XSغΝ;#6~5Md2QTTΝ;ٸq#ƍ#33Sa,YԩS7Ϻ[M^fgnf4 ]H.+GxM^k:nK̂[IMKo_=+V@ ~Y8qy(|i$?hK'\.ݻ1tNU;Ks J?OÇ1MHqqe"k~sW$<4Wsh~fg1Maa@= GL˯nj&GLCD~TUE]3e0V,SCr_R%I«K]z5a.R$HF D =@bEKu ivꯑᵴgذahOAĿ^޹]9`CͤINNfӇ|-Z(L<9hu#+MˊuKSqCC3+ʱƺ#$jE4`#n {m@ 88(äeg9lLy([`()8~,rnN[j%u8jDsM4l%b8xƑl<ɘ>%(֣`(-0dPHȄWHOlނoh*1qԈ] ;ݎ1a@]O}wa|h|퓃ur4N)tQV2`"y](lF?7&7u<&dnw Kf:@,)l\[@pXPP>_~2j(jkk5k}O>ua``RZ[[Yyx{@mO(xR۞џq3|@prP ]AS{c8 O20q|ϿCiI XM> ^oh=ܹGv<]j* ۡmů-rG.mN/Eť^کς3Nᩙ?<cZhB\CHTi(,$Im"C?,e>)`ϡQ❽FM^tR-mY4a| i):do6)..͛73rH9ٲe 3f`ҤI$%%E]{oҕc;U5Y_>,)WOHs'v`nL,|#by F!)*(@K*"n^‹LBP$U<1C]IVJNVX\#]lj*a3o䆝Dn"k0jX=IP+Wue~A*jSU5 :?  %)eB!ƚkGsYsؽ{wpa~ojj*,ZK*L4UV1w\Etd1ahrԮ%޺=R0Xh.}>g;vU8 [4Gdah-˚ 2zd]dǺ H<{! 9?ٟ}8 &zݻw;[,JKK~tadbƌTWW`\YI \!vWr} $k`7>$,]c@ P Aee%+hPCi1N̛=Rzǫy\ IDAT9iX>pU .6Ƣ.d=w ]44v ㅧ L(++cر\hߑ@"Bk!iZcſi yHaKX/Zگq![~iZH[gJkwN \3ԇ([ VoX4}ˣ_-фCѠXVNgp,==B/_իQU\&M͛={6'IW3͌>:#YJĽ ^Wp&DDZgK@p`!C@  5gs >X g 0F6n‡Eu,kPXѨbM:$T> ڀ P_/=OBӶ @p M4y oPRRBMMM,Etv [TTDBB . Y0`ÇoaBFƓ< Xvj,X"?)t Jj1Vh,A4a~MoWR`(ڃŽH*|u<lmVڨ` $=u94&a XGO+~ᰱW^y3N.nC(f5s%pEQWWU؞$dY"fѷo_Xz5NѣIKKcƌ=J^v&cP9Ĭ{ӝC$`KH!WNKdj]G@p0#C@ "O%``&ˇMNp /aff*OkZU4(Xi\4KuM@s(DÀh[[q&)Aqq1PF-M2rEep̿)g'hAJ ȝcД(:)w$w܍!lɅC픕qҧO"_Tl6 ٳ'8ɘ1cHJJbǎhFzz:&MYf t)JKs9,c0Yp(3B8nq&_둈i!xQC_bf֏^^XzE_F7T=9](L?Bs͍;,krrrRs@ 82iȤq-0m4" l6ZZZHKK 372***p\L&Jnn.| 6lfWh؇uZk"{srD Sr-$Դ#>6q(5B8nK8ةw ClWxVn8Amp}hKAB*w( S 7_؈kqZJ1KK0e^ٽ{wT@T8v;hFRRǏ??:+KhVVJk֪n+Φ&+RHdU|;ms@ DCUոKyK \"'ISQ@G 葃NvA pyMPRF;zġ?4v} >|xϾ@AO[Z^UӴY,B\tJLEsh]^^$hnA*Kz8 j?/l4ڍ!0uI>iXKXӷ!d2qUW~z^}Uf3v=}lxitR|>7iҤ5LW9t@)+nJz>9t-҄ݵ g(IJr!RFD A74&4x'3V{bYу} zS NURUr (梧,"b]+Xti]G\fo7A9!{ʨ]lhxl29r$TVVv1 QTTĜ9sXjU=ԯebfޤlĜCD]XqG2 8P fp(@UUn4 oPxu 16,5BI`O3f@6 ztaD[@}DWSSvD%;;>ɸ*+ C$A|qz(1Ÿ}aÔ&Ldb׮]hngԨQ('|!5:l)"G݅9hJb Jix:9iZmL`0* P fD@ tJv4dGlLtƦzDr%)J<$G ]Pҽ*Eo҄.ZхB p7YI'p}w zĕ IEb_VQ$UE qބvdޡH[t19wnxta)!ǕZBD)RR.k֬aРA=﯅n&ϟό3HMMh/: CbQIIIdeeκuhmm8doҕ Ssz TSR+$$V.:t$hze3P4Mf2vX oi8⋿sIT{|L[խ_3Z4W12i8>w^˪|g~ڳ|{:2sa${f@w'fU,eîRj7M*~ڳ=Kcb.*9$B8nI$(H ,(Ż~Gp]^ptC(PXQU4tMhhЅDzϿogoqEwvv;WߐXv>SITIB 046r¢D8`R/.GInM]DP} ؇ֳ|ӊ`ĉ;v,/"[l!333L&7 6֯_Ozz:,SRR믿&###j- I ޥ+klm#z!Z%P tj/T/oIQ7[ vȢڍ;"]Ӿ{u7z}Q q׹ջa)M쮽<ͼi.}szy.T<1Z!7-V5wJ`AuV1]4tGE€(G6s׭"w@w2 YF?r؈Y0`rbaȐ!f>vѩ?#%f1(H t*$z-4o;wPlm(KQӒ%)d` ٬rۅh(1mẟ_7>{60$':gܸ44D9^XɽcWXQ1ʖxcw|WVFo+ N 982{0Cf 湝 mDġ@ tUU;n+kG5 lcФP`x0GYУ葅蝒MfM(5ɯA[UH A|ݛG y54M ^赯M*nB~EU6/?ƾ&8-+mӇ ?x0bPNRj}@χ$ӚPn3 j#2ON%[$ G+^˪LUܢ!kgp~A0م蛘K׶~zXȖ*2,I\^zLX5Pj~kmv-K4az$#y4.(> ,[DD A7UYd .cEs+8K9Kws.J2 8y \#FRj*_ky^Wd OD~'{rss$).Ѱ}rbb"۷otL&9sпzvXBbXjJ 9 ZwD%y7%x^ dX( aQ'yL]E .*mun]*ǜE^ļOcf0rթN ^c|]U;#%=|>j7,yy>ZZ|qsnģoo,)G.D<-Mp#C@  X1H`1t"ʲ?%[$8 GJjj*/!GjhM9 z m. IF#wn{Eҧa#2|J?:a̘19W_}RSSc9 ??46oތdnȠAعs'֭c̘1$&&F#V$bQA/\ӐƶlќFP &Urei J0q4MCUr1d޾AL2-IdZ:1[|.NFFVwcndjIa)ȒiTeKtMldxj[]qU"k,Cf.]=1oTP (]"{L%x/AO?ǎeڄvUbBBi}vBG|f~Q. }3]3 .bm;CRRf9L<8R~{nvIzz:$Kzz:K,d21j( LѾ/fe4dCCɖi"H.fRo &EPg%Ȯz~3.SOA$$RLE4~~[pf|^,Kj=r%dYɲ&Gcw,ܽ S Dp(ݠî\h$Si(Gbȑ|MFEUmi6p Ho^L/nnpgdٵk= yug*x `!xD3ᢋ,{osd)ͱq믿O>+W50V*sJJ rZ[[IOO`0P\\LSS_~%EEET+޿ %Q8{xKc`I/hFozuQ`i.Wn>{?e_ L1;Fܥo+]͑~,ztƷ恌i<=n[:w9[kG4GnŢdQ#4`&+|UIy>"h]P14M ]RhAM4תge1p8WKhkgii߮M2z:N&E' @bFq(ƐXgt@- bLJq.-Z+J[`vktPMDMQC`tvȂd̘15ӧm6G\'%%CEZZyyy\.͛GVVeeeaWJKK۟VRn  j=CMZeN`ʸYD@ M^'"_555u1] gK뒿_T-yPn-EGt\EBD A`Z'yuvT2\S!Tf~#.clڶ u0 4&i~{7zCu|t^#طL|G(i@ 8Ѽ"9dY/=nS4Ҭi$Cff&555ifB<sΥ&0a999~oN ᩭ|B4TdXז6[ȳ'ӹ?#$^1@aԸ9h8)DCAp(=Ȑ!CLnݜ&pT^K~˯KIIIHH॥KvlLN&)Md¡<$}n$w\3D/+F[%??[oQF1e9hjcX(((`0PUUKLL 60o7ƌ);N ¡@ 0,s͵,0L樷S~q_nxMޙ1!C1pmx~fYu*jo3e&iE a5T]]Q>.# :Fj60g/~Ux饗PUra (BJJ .J:(rssy,T=w!)qtY yyGUV~x`e#u|> |cק9RuSf;SOEwnK/A:&/ ՜ѝ|.IԻ[D{~N 8W+gG$ to7  !HOCJ[Qٷ lf!L-g$bЉHտ&#>?\a^}kfuuد鶃 b?Տ+66˄"++{7|7x#IаρhcV1S>w&:'="BG;7w>f4sK#o\l&:)>7xvD:b0H!bjiiaguhE1B>7+eNt9yGr<OۯŽn9 E?!F:  !ss7B5諸btlzg?bx $GN{B!$p(BRygΜ)ihj瀞xhx0! 5-╈} ~ݳ;#TGgΟ3p?bD+))'`…xޠS㰳&n6L&R%b$p(BB Zڤ@A}`8AXt!Y`f7]̛;{x&k&55۽όTWWSPPwIFFABCBQ_xx)n/PX8bG媫`0C~!iImm-]w]tQF-P!C!bںc/fgb!I4Q/^̋/ȴipWUӹ{;vlF)P#.BQUVѪ17>3zm}}CQ:n{tm$(!"Z U{@*=3\/ND{Gjm{՝(k4sLK۳sTŸ1UZロ5kp}Ѐix<ia !8ȌC!bY2YӢ= !YyG{ ())ᥗ^b477/AC!Nf !̗+3bQv1mʩ8nYB!pB1x^;<$tړL~OC֥O0UozAߧ|&t01؟W?s(A)̡E[>ҽOw[-999$h(@2B!(RZZ ΌE'سOQ GO]5MPU5{1];P/3|t 4pl>ĿpcAjscBhپex=!D?dơB1߰ Ⳣ= !Ӷc~hC!TSU'K^ +J2Sy{͚Ȣ3ΗU$p(B"߬]=(B0Z:;Bۯ/Vw-Gb2[*ʤ ӎf%#BQd{N,ӏ~|[__PSm$ ~Eƾ"f${]gߎkM~NF !*K_}3q Fc~ʦ]{р 9IX-ffKg8L&̎ЅHP!U~J%"I A8""@l;d4-do!}(6!ڶXŒ,>y v)in--d6SSC4bo&C!b0G{BEc0"`/X)HS2. @cwQ+-|XVżc9㷭a^qqv#IN}>>Oc2΅$C!bx<`_B^>W;) "vmekG) F:^l+gs{F7{!#΂qq-/awdͬqX0&=>r S8k;!2!B----@*Boj`@1Ha֥uatәu)r"Y Q#S]rPŒOqO)M79?TM+~pIL8qoC!>V0.+gZ6ש,˘cl˭;?;͛LKt3-? 8<sЊ̽-{-_<4 !rRV21@Q͆Fv(cc 7N׵b06-u'b.-3lٍ:,}-,{~>}s /1sB8\۴W3'fL}Ue8)tfr\~3 穩uy&OJ0YZ\G2thaaaB:^/-LP J((B`P p}]s  jliO1T]CMr fNYBcU|bԓc2+RKfiۑ$J hIJeYڲy1el$_n$-a8ˇivcQ%_j7vJ@\>A_W4nYw6m>Vp?o}߯5 JN~^|&}1f'c!8мblyktW!8 T͛?B{V-fTUcSy=owވ\ fә+l^:Ӻ|KqU_^¸q7 B 8|j-kvoͻ9۩v5dqrlVm.vUߋg|r7oUĤ9:ukΏY\'&l}5zx!l~cHmm+:cBqpǣ$p(ᮽf%򉋋Pxa*7/'i鰠ik[hMie3, n"4Pib7bFR'y ]up 3ryq qZɲoyj8sX ծ&L`٢;=x=q*W;,{RDw%oUn 0+]}i_ #/~;UQj彪5,\Ϳv9󽪟xB!FTRSS4  iɊ.)3(%YOۆ0j F]m0)J5Jaޟw"zORiuÝ;aymjﶦo\]ڸ' !/?pn +G24a,\ſw/iGC[~/4sO-o`T|cчq͆k -}~~qYPʄl !8Eٯ#!!PļT"\!7_᫷_Ĭc3PU#fcx:]) ewbs7awXhI^&0 ]߲WOG{B:Q g \j˺-L5)q$s#<݈[+YV-iY1^Uk99sƀ}K."yZCeO̜4`W{m_7q\?!E!D2wMÙkn櫏Oi؍hD5QU-{q_(Z7nAu߬YK˒)$S^|_SuQwF{BJQ &Z~-VԏҶ*N( y̮uZ`\^ @3=Viyb%۪8z_rY϶ǭy#<{_e⴬ ~ѹu.[0yB!Fԛ>W +SiA+,Gppm`'C5C8-1PcMJ/lak=i; JIol@?g wBرu#K_xڲ5(FPUvնaLde[sy`ʵsfVmutzUvjjqU !> !6"GDeg#!f$Y،f\~/Cj%Vum1*;yz͔Bd3 h(8iay aD0Q=Էps$Ek޹x)O0D ´  qnпkOPP_P={:>BD%>q( V7 +UYaCRH&9\8À vU5Pv}FWsB,'p %Ya$YblĄ&[cö9Vjpmod = B*75b7;CBD-+_Λoh4ߢ/BÎbfWl aOZp;b2ܹhP8s nN4j:LJ 詍9B,&pXjWAEgzgfbϱ*q~l{2OQ#b͞Y_8p^ L2U?Q!"i k>|wK=K|~UKX<1Dy(NEjQ*5h[))H&u~œEwBR&pgSnۦ#c6: hPrxn)b)((@kyg>`2J%hML2j%*aRn}~Q6s"cV4MXṠBbXs0ᾩ! &Lqcѧe{Ms)_OOִ{zU}~\k}UUIII!%%%̝ !ľ/|ݸ`l0*3S,~_Z sd+2(⚽+310?hXB| &{Z\5*;cH1vMRU%r~i37,'..fζNۊhlj;V.@$66ZvI[ U6AuE 1fjW26',~9' C3j1=!M;{ë>dmNN^{*< ;?Udy-Kh%p~Z&vEB!"rYssb&]Y>w'eK'uXGp0cD/Iq&iS}z&&8s|￑lzy)o IDATD}PCzv>qxj\A/oYc.wkhN xvhŃ8uYb3sESPt5L=?C6dGs?Ƕc[ pmO_%egvSX#o(ЗJjj*3_UQ >ߧfmuJ(uzo;Cv34-tJk}~޳5e_2` qqW()$'%k'l^!&57PŁ7\r8Ai>l}ˠSuõYpT@oju._piӪҐ5]v8U?0WS5ƲeGIJJ"5Uf !zǴWogB|~?mml-E^v>2ILfժo((OSs;9i8cMy쉸wѾNHH"uNxt^jmDStbgZ*5.xuX-f.9ufY8k#/? uvvb٢=5y~ +귓Hԉf ?gMۂȔN.j$>>hG!FK3@ gt?>_(E>po3a}܇zA58Ѹk=5T23^;i3&w՘] b=[/I0ɺ6C jႅA8| y}0.=CEG?HP[xYN8'ٸq#8=a^ǃىjnh Ymu><^7p~[4, V5Yfg6Lkd{i|ꝬXdLGj>߽ D !n8tIP!"vZH)0P(U`F|F"~:qubsboكojuư'm*K ,Hi@݊ǣ)SCUVr{YG0Q4s/AN/ 2ο^~/nӦE{XB!@4~zݕާ,$\M5 H*a1=A(M tg.uA#^?i2u7\23IOKt\BbF-%TԿVqn.};Ơz?k}9om  UC}o3 %%%8h| Hh4bXgWֲ rގ ''wޢvzlKk9姲y qy91cg ~dfGD;VwE()H@Vv_\1d8E{g)}qrX0}<~;ƏB!F|R^\-X!n{?xDgN  uޟča?`̣Uq)\pbMΠuw5t5( L]_Rlھm;߮eӺX 1hW_~d$:ޏth+a5neSxiCEk<>4Bu,Gj1& s &" VKfrXF4ߠ1>l_ō{H A5gc-̞ٗ0" qQFR妣(>{=~GG=5pw6VQbhga``-vb hf~ (*:tj,z ` ZC>lG7D8[%K?cBaqq3q w5(J.!Ґ{pzK}Az~;p}4|3K.EPyH-6^/.3L3f̘~ܲy&Otz@mDۍop`8=啦Lʹpt#vj ۪;0x۱8|t{P,:* %NgqETUUU?S Zb`0`41t2 AJ,F?B&i^r1*5od &}3sgLUAClMo hIi8}V>_ra"$,L6cx|_Nfl6jmOMm;włbl6cX0MwhiXNTOsqR cj\?/rjv(lDэ4hhWɘzW~  1BIpiiiw36f2dvuaGO@`01 ڝ\|b~[hoo !8Ǝ˱'ҺsM2jxڛ{Q#J̈d21i9N{/{>} M8SK=!(7eq]۫xo2͜}ʱ4_ѱO?{aɒ%e:AACUSPQX,x|*I>h$ [Ӭr316LFpF6VtZI =vzq38T*H&#Ϗm+Hl-~ܓOI6vU7~Un6HB MGG---|E}5SWm YOOOg6Is ۷RP>9DPR5Ue'/`D|G^FZJ˫}.DipǺTh}~kƯO_¬K[3^7=~ױ_r5WGLL!BX3Iv`61qU?d=lھq:(B{{;( %r)$:hhj]NBj&6zj*ٹi%ߋ8FOAU~5hNf)~K]]LzIUaߞ_V,c敐; amkZS9_ȵXyk$BO?0G|S0L&8z}u}V!aڄ.XSu9-`,RSqT4]lyq$vϨ.dPkaCK ?puC]W_PZ WP__ S0(l;^ MZi\pwC+Cy/wkd2a6q3暫YzWYx<|r VTS][h$59L+&?'ۍᓵ;S ,YQQ)Sز~ ec$=+fP5M$(ACUUj p'yA46!D$peKx%oʢ#琝qP(~gϷ>f߿j.agDbyE&&-_:*)l ysl-E-h< vxۙ={6)))B!zcҋM&.#_xc]'=A?==ռvRҘ7o^е֭[G^^.۾~@S_o?n/'610OKb\˯clM<~O  X,rjjnfkY9qǐ1T@pmkG8RRR$p(vrMWӾ7xNɜsYX6TU7p_եr 'PTT@YY6ldRvlmØ 9c X*nMnuSf̉3%, d6l?y3&1sD@x|f+u͌/ C!6mbr{u`YW0\]à`n[p _ۯ)A \utzR<>0VT#/!.8_"Faס0QPS]:A05   n|HѴmb;x?1zB'? bt-YǟĂѺ>lim_o}֝*fӋrASqݘL>g;+.RSSC#é=qtif7ϜsQU-l0v\ga5Iqg]Nr'h8yc"y;IOtr`Z7FQڞHi`Y[+%/#}/!!3ؼg=19S=oo\1>3t=?EAQh42a\ly!|IX :y_J\pD#8?H]J2z9bbOKdpļ#Dc>Ufg!߯%DZpޑ^8f<\xi}#Z? Q=j;[Q|ƂɌC!횚''Gr;}Pͤ_}dV@0_J)v^ަ 6p+6pL9~R嫘j7R<.5mO%xAߓoS?LP2  U{OڇY=qEPP߷~b,Fݹ|4Z6}H&<$&&p8Bݷ'}D%xdd2Q]SO]FBR*)iiRC8lzg~*jqY8廗ɗvBBd0|ΎN3h(J,BC>5?wWKL\ _4BOW8 ~\f\bnS^^Nbk+{3t\>5o0~Li'۷/%%Dv|q "tiȪ൧iZM b@gz[ݫ>;ZOW/rO!8N:;L6 ݌M RQrs2LTV| jh2ap:X9>X+`][z7O(ܩ`~4W^^~>?焠cb0|$L+رk/ #)o? !8$%%ǿqG_6fVt@{G'i$0mT)> Eal^~w8A+s^[?#~O?t&Mp"Hvv6?.xWn CX,̞VԻ@kk;iN`!_ؾYy[B(fKGC;oh|aqh*( `0w}<8٤&؏QBrrrxΠ(d CCKrzc2< 3”㙚e^hiDuѓV=iiiB ~v7\Եz=h4̑k:V]ʦ.)sq8+Gg|,sc>P76TUgd%r sَ}fjHBRRzQz7)~{&_K άOB* J튢I3UthH59J8b$e2 A=bbc[2ʪr[f}1EvOWNwֽbq>VX5piu u)!Rޯy[ :B.--n%f*~޺Zb<ƅy.?{zg. .`| o'r΢:o1>EB.UorY4TM|mlul~ҝ4]Qj")gJ*)1ٵ{^q UӄåiH3zۭO=^A8 ضK+8r@RBq1"dQ̔D`ӗy_,Q~zuL?]H@o IDAT/R_6JʺAM6֛ܽRnJR"l6N' 444C\\|59NfLmoރeҩMBRdMu.=92>/[?u\z\?B!D FjG vƲ q%7qⓎ^#.i~ {j].^>jG,fl::MWE{BH=Cٳfӏ;eOK@1(`>pWT˰'((aߺJ`sz)Yotكl&77ݾ._zZ*i)-;"̱)gLyϢF8 AQi]\}w9~B!D?$p!͆ 8v`wbrSBjRg/K],:r~ue,>;-l,k,s7))wO?@`ZyB19Nݼ2#8\96 @)));v 륬8233bdPqcǐvy͋] >InRJJJ2!BFiG+}Enc[iw>ԷPFnFYiIɸ1R{>k.IYްa>9iIJopҐ `B0N9ΞͿzX|tz(‚ hhh>|~ZZZhii!--I_V+'O?'k =(V^ZJW]C~F?ՕtzB!aV+ 1\M]HMC+٩&1zn_iIOSDee%<4~!@!D~P0yB1wo︛g`M4{K^(H F1Pqqq̜93sL>#RRR҂餦:rrr=/!>y3nZk p$gԽ 4_CdF{f&N/jJJbh Yi(;oڄqBDщX08cwV4kf54b,?`{uv 1 Oֆ/1͞+߶a=[ 21MwUǟ}}&7P:Z[ZkVkժժ?m-jŢ 8Y 20B>?9Hq]298;26KPfeB> ;p`Xnod>VBLeadrV?;xs&Kt|e ^1cPWWTWWBii)nitq 466vhz7K7In#%%Ef !zDŗ?8 mX7%{;7=8/3tP7(ƶ"h1g tۈaĽwAwGhX3.s()msG:=wa;C;q7q/=} >X !4ݷBYY>j2c.@u-3v;zjE!!!D~?MMM0>>hí[D޽Q;9CteOA0x8BM5WBFϏo ;B(ot?}4ͼGvxF_z{fvMx9=m XMW`! K0Լ4o`:hj_اLªC_5c6y#fUWOS6xjfϗblLE?&a?m! rmzB惦a7%1}rB(BFse+%)ۄ0`nbuuWbl/ۉǣ`c6op ~ۥGp80MpJatak1^}Ѵ.u6FVZ/U.j'KBVK222x/ɧqσ`MP|՘/[jVnEE$&_Kmۆ&SWWGNN~ݻwM]]uuudee$0˲hhh  nP0.9s-iܽ lpٕr~[2P- }:ϗ= h6,gy(j˛e{i/~o_f&>WWmrگi&Vo^%~Sn}hCK(06l$ϧq]1SN+/ ̏~]=;&4=o-IBgYƆ?[B[zty$4ۉm60+h<{[ s\aUWc7_}/;?$_֩7{Ũ}KYxy>@Oc?Þ)DOఓN'exHMIŦifeļQ]̴rz 7SCBӴwޏbvB!qk3_ȠC^x IHr* bkFV"4Zui!-[wޔDQQn|;w$--jv;999B!~? ٳ rsszg݋(JtFhG ]cu)PεUd'pU&++Ԙ@[!zJ3ї9s1wĄjL+ S%[o  ʫN<>&4P33O:}טfgt,iaª&4o8~6hqgEh1a8~tQ44Pq]w abn=֚л:=vShhf4]v9_uUpܽ@U>xy/!g@prA`@_ '( +/G_͛/8IpI-3.)))8NH#!Km}#( aMV7D*1bu}qI$SXXHZEU{.@D!5BEQ8393Ybxjm) sSըnq()).EgҥۗaÆQQQAee%~bq8ڵT,ˢ8ݧeYr]]HX@^%Xq ٗȑ7Y!Gm&(ᅋcj~i3ӦĄ-KE+*^HSޘ{06mTpyO==sWt| 8=_i6y1 i GIHjhDs6lVO? :, cgOk~D̊J ?~k~M0 lƢff9qYW;#KFҶ}≄?\t߇Gs$Ӊn8N  P$Rz%+4U]e #W"* [辊o6eۋb;jN*.y}9QL=z=BMnnp`\Ҫͅ_b}N+ȏ}S&{ԄY ;5v-qO?>l|w{cŸ|DG񸱍Ұ7K =SbϹ#Pն_|_?a2;wei&z}+lupzwv8yZ^_ƗQ\R'B-vR2멮g5/W.蝑Ffz**aQg/vFDCసK.8 ˉaњ?6M>?_|*zŹ5@Hy!P v!C1}:۷o?̊f %nI= Zv UMEU#oN$xvxOs))qѥ 00Xd yyy mFFFMp8999$$$OKQݮ;Ųh^$ 'qڔoC+/"5'c_sB2޻x F/ّ1{ GfNV0qΫD_л8lT?$s}~| J5]HpmVYvfF*v;X 'O~[ F6hఓN'iVì\9 EV~Yݥ%)F'w:}szc%S^ E EQ zݘb(T&J?/a{]q(ߟ"c8ڶZdE7`V}M׷ h| q~W,}-E*@ϼ55)lZ1=WfE%feaVM-M?so9jZ&8$8HCx+P;ŧW0Ll]e(BNf:y躁iљg i1-p9r(j=nhW;b9B!z(L8N: Ǽ xh(È>9 dJ7P[E,[CRR7nСC)//GQ| 8Ν; m6̔:zRǰî}#aM'S;Jiٕxm }ߝoVr2V]=GFpx}LCnc|xm0Fs#ڛ jn ΋9\_xрN_s|Y]yjT#%Ʒ{ sYQ8vUs.{1X8Ip'эzvnMX󐜕I0t^.i)*7j* +(zQ4'mzN&0PHׁao,@lyNj !I^-3/>bμ+1G2.eكf5 Pw}Ivz2  QWWG~p:w^3f ԰uVf[]]uuudffң?o߇B|W(.GkпZKÙc}`?8Bt\4 >U_t˃mf[uO'~;1 RNFIL$g~|ME2`;iZD+/ۀ;(޸uF4tU[J9ovزwX DxxGCT!]kpҚCU;f;v4T'6ƀ}*aE]()6nKG0L 0+1ˤFQQ]ˆNCӴ.(Bǃiw[jj*ߣB/Ug ?~xRsQط,I#Ld۲HIDII YYY$&&֭[ٶmF"77׋g޽$''޽{"''GB}MMMr.EQHJJB<۸$.GW(.tS>~<ބ?3Kh6@Qp\p[nD۵fcBQfl]Kg1"ו?c[9sQ=/Ԭ4 }RByǖ,iV]]XujsAksAn$;swӒbf4(@ B; ĠA|ZUkֳ~B|!LW_lySs9dLn}oѧOl6555v⨬/$99Cuڣ:%%%x^gA}}}--VUj d3<1eEfK-ؙwƦ4X h}/h#G1(iiX;JLdɮYp Z‹?6qBLh /D_z,8Th7kj;ǬlkP˷oeǾIu7zwh܀W[G.PZ(;#ɬRk(.ABǏ@4TZ2q5LW#@@4PH%#ť{k##9D ,x4i&M"7ظq#+׬gOi &bǝY@Ic=%$!!@ GQ^/ | $AT!Z W} mfe%M]Ѐ-!ZˌDsPz[\M#mK͉ƎR _?k=FdIzw^db;_ BiT#cH~._qKFBbY._G}0mf@Y! @/ -蓕ANf*[waɉq"B.--KW?x~~?;wx7in%%%I0Ӊ餼;v0dN˲سg]wӧO !ıL_]O P#pqdFah#Gfe%1#=(YgF:?Džmk*[" T%AZ6 @_udC{`ڀhÇa@%%;1\ا}1BϽHߘ02qЉL"l|۸yeB=v7)1qPJvGC} #a<LIىqL . =,s@MhY/7iRXA&@4Mq(vSPP@AAgq_Kʸ`B|>zE8={PPPo[ؾ};:k.***rdT.p}]4KEE'Ng(B)Pnj[{~s\o iƺ}W$:;~=+7~9'f5qwdD4#<\Hp^13Bz&l <,VU5ZA>88/wx g#"c8˶#ц ش{Q1K/^+?4:s1fd](ҘM$8 3[KN'9)]Ŋ8TMU:::/+ IDAT^z&҂T~5oD nf ' ٲ}'I8VB!zͫʲe˸zhFRR@@  ~z*++ϧ6zEVVSQQAzz:EEE$&&һw09)iaSP@\\={SJ!l[ 8= t'y1+OC2?wWcS!'fp$$+M3ƍ ;;JQqsW5;|G`tr$L\ 6qΟ\zӻ%8t̸˯blHӏKP.Bs^!Jr/\^8nk1jOZDŗ"9 ۘQ1ǘ;J?{_u[俅[8O=gq-DO ,ҙCM_e;x(ʖ*^: 0ќ.,uvѧwa) !n0ax饗x뭷nz+;v`ʔ)9%K2zhJJJ%##ZeQ__Off&mo<p8LMM s'xbW!sOt]~:7ofidggMMMv>˲(++K.?2DBb(%l؆ vqHjпZvJj aF8`?˯0 @S3ꠁF@># cs!X>qcF@9Ha54 c:ԬhǢw-ı#veaWhū[UǩeP^VPv4)ֺ :lXܸ|NO!#XC(5H DޕLJ=KBc]||Kkx: %>\>&j6n`dlBBmqxbL.mllrguh8tP>|8{aϞ=aٴi1QrSUUma1sL̙#B!w]qc5 ݦ xaOʚJq%57؝X X3=w !Xf۹x뭷@6Kysssqlڴe˖aYG&))L|Dk"655{n |G_8n9eY3b}=n9B!8Ipqp8(/bLMp?US UUaGCֽ*^.nu_pz4գ(vgݬ }8[ذl}uBcUZZgOSqKrIKKfe,YBrr2#F //KYY`x1 Gqq1%%%!:{l~5B!Dϐ]`Y88a@폦,(v =R I/8UJF})~_3:,mg#72WXx>}:ʅmB#`ܸq,\_|z Cvv6gzTTTi&\.Æ # F|><.Z0iDZZiii=2h& QWWϸqB!CfvAK Îjnu\vpd*'hm|ZUaZ ӊ@lJf?5=۾ !ǒ,X#Gv 8Nn7uuu|TTT0j(rrrzXE fz +++ٴi 6P(DUUUik.>lϟ/B!0 rb1xEfphG7Ю|ʠ fqEA5bXqEK?wQg{S!8<?0?<00 ˅|>TU@\he1n8 p\XEcciesN46EQ0 n !-ˢ޽{3w\fΜ-B!^v@Q=4TUŊiZt-66jyĥg 5ԁfjiZ]?ޝBq41g~ ,x<R__@46o̲eHIIaȑdddqkim6vݦ!ˁJNKK#99=[]OzB!A.p9]4*9er)ƾ #X\]IK\TM Ql,%|#>V!h:Yx1ӦM p:  UU(,,d 26竮6oLMMM!K{Z;QZZի_~$$$5a/ɛoI~c***;v, Y Y|9+VSQQAaa!>/5EA4㩨^cŊNII 9aЯ_?\.Wò,9X`SN֟B!n . S'²Źeêq*qhW1 TW:pvGaJsC RVYiE>49[}0G^^ѹt! ygxPU]ױlr(**0 O<@jj*}O?J àh7fMhnn7O?6AQ4 rJl۲,q:+tM1aB!IpN 4Yb=vN_Gi;Tٲb)k*0o*ܷpG>hn> B2|pϟϕW^'( Q__Onn.RRRʕ+ ɓIII!D|5UUIOO'`;@ @UUy;O!BvΜ0 ]7t&N;//9k KQj˔["B$4ԎroI`٢}݇GyyQb!\tE|ᇌ?@ @8ЫW/v CPUUq8躎㏧o߾mkٻwoSZfN0$ 4M={0c }F3?!BZц0,^9L?ϿLFJ"g2%_3'$%mtHhhYVGC }t4EYԺRK(B/s\ڵoZTU%///(l߾D1 ˪vXeB]]]Ȗ.˖eQ]]ѣyꩧpB!;MҞ.pX:4wt&._!^[qCs|45vRa0#51 EUb\,B|ogq]wEW|S `ƍ$''3|p^oPQ;-ckNss34!B?F*wB Xv+ΙGݕ;y;ʪy%U,Ub5[3p:ȄBc)¢E8톇555|駬_]c@:u]믿.B!8,vD:y ndM!b7?)_>؇9W /4l ʱT²ZBM-ơGf !*^{-sΥ_~芃<ҢܹŋGha˹3}tLҭ!B!7IpNnux=nvayM=2]qΤ44yqgT5@lȇ#Q_iUpX!BD%&&O2k,iiǏgĉx辭.C3[?:`(PB!e8\N;?>_ ҵ8y|r# '#gp eHIb쩬i _:*,TSUcg:] !]5x`}]iǤI?~|fcq( :RB!PIp\y"Sʧ7M4͌ms*kYq;y(i1=XReÊߨq(BC5}t.\ĉ AJJ ~: >o߾iB!BtD.=z4S/Ss's{X>>XAy ; `Wy ?0l [fjX{| eơBqxwu*躎eYѥ-`{A`AA^z) TVV{B!K.vY;,Z]ēϿM8o8Ν4՛mSƶqpGdơ[PUU}Po='"i? 83vB!Dw_ io[>OΛoɓȲfEQp=!BM$8<.|+;+\bid$u qd's|vWԶi*# dBa캏ۘ7c$ga;K_k7jJp(Bt?EqEE;+744Dnvi,Zk6.l6f͚9r$#F8!B!Crw0\5pȁ|Fߟy9Zܲ裪ʚzc*_*ܵg/0  OUI!_]wEAAW_}5@[ !B#ݤf{NRTU3/ qn dނa>?EXz0(N^*jٍ{GN9laP0x?8kH:bcB!B!GFKp(KIjj*xyFt1JwCy[]Ϛ 蓉- [:TO׷ %fǮ ǔ؎Psw6=ơyD B| 4E]t"B!DvSN⯊/qpy0~X>eh *;JwrUO?O>}H'o̩$ &s|g|p|9B!*++CuJJJPB!hv]p8RTTw)'(,p!e*MMM*vn^IsC#]^k~^."aKG4,B!B!z8A `olOM0tw?X]3[а5OR*'Eh6;6%LHdXT"[aGkUP!B!B|Hpx\zOy0`1g8O=RtYrg(Bza,ZmLy`x"V%8ԴnsHp(B!B'K$?_mގnZt3R<:xÛncoUB!B!u2[4Mvx躎Tn]% I8&nά~Cl@մC˲+B} `ӦM2tP14MBaw_ rA8"MT[8 -5KZnB!"G/ۍyl 6|ʵi ` A ?L 1]~=۾PZ7ۿoޅ駟f„ 3b=\Grr2gq-:CGܹsqݜ4Mn7n;]v/>`#Fv8qb4@|gp\ve:k׮駟;gÆ =r5vy'PB!"%ג^VukVR f4F_O۷a4GBqtTWW3c */_N0dȐ!s9R[[ˢE:u*7t`hYc>Snx}}#o[ouw͛q\KA_ҧOFUW]}_Έ#9s&UUUm[~aB!c$8d4r}VSjN?G*68B#1c0gN'?8uuulܸ{R˹,GyS4p@nV.袘+{#2++k>V3=C=y/^̤I(++cĈن^{-v_|/Ϳ'x{Lu!B.ఇ zoxCղLK [ܲr3|܉L8"N~Rdkj58CKDeơBqw}7;w$++KruOzz:=o6>^z(XMC+8xꩧHIIn!f[(/0 8 NoiӦ_p2sLx /_b<=qIB!S$8A֮/ _wzKu3aP\;=2 #7gؓp~7pkj TCou}mߘqBqD[<Ì;Ϙ1knP(mr| o6wxvih:,3g%%%|Z>S^|EΝ˖-[ά BPmeE&]),,dܹ,\vrukjj˜9sؾ}50:5^4sq[8[^@ Y`*_}ULf͚ٳ7o^t}ի?<|6Y IDATl믿oe̘1"3a#`g!|>>ΝKeeA Xj ֭k#Bm%aB<\|@h }NLFp^ӹ7.O65 [ܲ=h'dEQ9t4 ^fHm g9JƇ.;fBq$=я~ԩcNٽ{7JQFvq$%%1eÉ'Hiiilnn'? c8۝'vꪫgʔ)1c O΀+0po&O̙3 4h^xaL7l0n7gn vӯ_6vݻwLRPP 9s&SN%77Mжb n7?Oijjbԩr2c :p䣏>v3& Fw}m=q~@([lvs-;nmIMM嬳G?cǎ夓NtE]%\W_MCCk֬'$;;Sj 8p` ym۶h840 _$%%1m4.9묳n{98ȑ#IOO磏>!BlEtŲ%d[|%e6baW({#ΟP\̊^𓫮'99sZ2u=15ul+C]]III1'r`M|TUeZR,ks+ݓyRe8Bz5ϟ@BBv[ʢDgPM0kגСC|b e<,r}w6f]D]6q72LNjYYk{Yl[snڴi;v>Gnn.gΜŋ3[oʼn"...HNN&55srAn</^`߾}DFFrڵk^'!!T;Μ9C.]|^ֵkWetkMxwe2Dۈ#g4lؐrW>lٲgy0bbbX~=۷ogĈ׮*KbccINN_1lذV]Zpp0~)PܶmPz777/^b777°ah׮;v$))׳vZڶm˞={y4i-[sΤӻwrB! 2[=D1鄸"̗n#9WɕPn/OBecP 'qǞ@Rka=ahX$<3#~i xӾc禵 XV2:~Ԓdt9A7xu/Byyyfԩ5zŚ5k0`+V>'4t֭[j@qsθZ_[?^`̘1̙3~jRNbcci֬}ʕRINNNNNU~իWJlp2,_3f̲e;ٳnݚLnJNmzHfff{ ɓ6xkt^pSL2qDLb^RR{}k̙3y*B!ĝh4eau*⶯a`8YJs7 -YhPGОmՈ>2Odpppcسe8:jʬ0z`bF>ꫯYnBRInѸUGnck>M\(޺ȊC!(O^^SNERJT>SƏ_j:t˗K/JOOݝǗYuyϟB`񸻻SPPg}baر宒矉#::nݺI 0rHJ)iwvv_ 559sT*8q"Wlb6iӦ ul63uTf3=u]u߿M[OBW^Ѿ[g }P\Drr2G%44ԸvNĉ˼n3gʕ+״o߾XMFvMxx8ƲsN?{KQz!ovqq!77/VMZ}ǪU*% o޽{ׯDEEZZwuW!o{:t(_|:|ҲeKAAA̘1޽{3 !B4Iބ 1V:Ҙϖћv]!;;iܸ1YYY3c0ҥU8G7hf>;G=C@@ :.=7ʂ,lY.YCDHHVI&4GLa˩Sfcɷ`4RoDTD!Nj-ۮlO>󄄄Tz%KX|9:߲eHOO_0ٹ~pBjLqGGGԎ4hЀ-Z0c 6mZg nܜ^J>8hHj.up3{vյل*( V8gGIq"9܏% ^*NOOR<ի'Oȑ#)It$RRR8qڵ#88H.]d%ڌF#{믿g'EA |=4m֭[?7GF;vP(ӧM 00ZZQQÇh4ҹsgٲe ӧOy.\HXXӧOjw<}O(J"""?'N< Y* !B&t.$gOnA뎍v2(=(((@ѐFvv6cZILLɉV+N<˛e;N:m6c!L$e/<<u޺=xq>0<+o߾9rӳgRΝ;1l۶ D5[q|}puueҥ,_qoӻwo7o^._̨QXj 3ydn8~OX,*Q__ x{{p,B!w YqX_~>_}ch[-Nm%817FѐEHHdff~qqqӰaC݉';;І87哟˦8ܵ1L{eҾsw^!ğMCTP9{N޽o(ix5wz<: F>q BԐ,YfԘt{6mڔitRcK*$EJذa~aYYYѮ[_^\" )ujԼ:SB/Vٷo/Ԙw}l޽{cǎU8С_T(s֭tr?f3)))TJ1deea0ˏ<s… Yfwu-66Zmۭ[7J%6mוw&!!vԩSiݺzԩ߿ua0IP( >BϞ=y'P(̝;NÇy+=#8t:u}T }Of6"8,wjB!w"U^';DZެ{w#*H-1ѴiS4ij%))P2228rٳgpB]\ iڞD."ƒ_Lb颹XVJ%]3zrB;K&ME^}UvuK.믿`VA;w.& 6paT*wum۶/\lw}3*?̙C:uJ%J8;;sV$?p1ڴicŜ;[&55՞pkmΝtҥLEeEsUZgϞXV}r+Wd޽N+pI\\\;wn ڟolٲ8q+VT*?u T_%.]JZZ-]v`ƌ^b5W# !B8{<̹, Wr Hp\Gq6Ա\xN;vhĉX,BCCS'OoWo؆XbD:g餗پe ݮA!D x $55.]0m4222JIJJb 6 +<1%%#F"zq}QaOпRۑ- SLaͨ-Zg֮][-;;iӦо}Rm]vɉ{b$Km{Ar=j/)eRSSKڵϯ.\v|J^YjEj\\=5C!aur7-^gq&OϷk`rOo&zt,>0))$ h4r),K{* 5φLYw'P͙]?x kBqrLQQ&Lӓ`nhР}ߐ!C:ujoߞe˖ѠAz!vJ۶mIJJ"00I&[oѨQ#iܸ1]taذax{{o_tSMnݻ7<tܙzꑔr R[V+J]}L@Ϟ=iРDFF2l0&NH߾}ر#?8;v츩缞>}ؓ$.W-yj۔Xj*~mW\'{SO=Un?Jqpp̙3 לΩS5j5?ZGͻKZZZ3c BBB:t(:t{+b[N>#J%#((_t֍ۓgߖ-BQIUI>w #4ȗG0ѯSS^ڍc/|.6^]Yh$!!z퍗6j7kljt.ȃ]4>6b ?ßxV{_!˖-c|8pgrY]wŔ)Sر5ضm>?#PĹo,տ^z۷^x[6lȔ)S4hP1%[###ˍAMݺR*|[,\͛7۫$+J |PÇBsΥ:wLnݰl9XWWWV\SO=Ŏ;Xt)P=7`k,]@puu%::~_jqqq)">>> >RIC ʕ+( zYӓ2ՊO-8tӧOg >BaOVz1**zu_x14jԈy]sEdӦM裏_8}4ǎI&M&M}=<<^ի%&Ls=GLL 111<å*)/[ٳg3sL-[FGaΜ98;;o̘1SOO?@FXd )))>4%g y{{l*z+%%%q) H8<4o޼ܳ#*,,D~a,YrUVBB/^aÆ ڵ 7777oFՕ\Ν;G@@f8 iٲe~!{?NӦMK%#B!j+ш^auX,l\+rw4:ps`*d=d[ m@jj*h8{,JX,=GCo BAҥ+l;GѸI<Bܼ;!qXUMUSC&B!ğC9㰚T*o')݀wd߹ڃF;1$ʟHOۛFq9Μ9C  㤤TMZgM>z u %nݷ|1^B!B!"8fu=qQ kÅBՎf8z2D9BBCC%>>,7nNl6WN΄5]-|4, lɅB!B!߉$o&Z2g0;J58|=6;C Ξ<( jU]S/~X)y+cЩ佗ٱm-xZ!B!Bw#gY= cS38q,3iWrXj7_|+={Lhh 8_TTDô K⊄O]$o=B3sssX,\ÚfB!8J 8{;6QYZd%r23y_;TJ%aݾ6 ̩SpssIœ ؈`l6&[ ~j|J!稍CqgġB!Iq $xzamH1E|0+7>27wñP*D0 IDAT4n^O||!BQ;Iȧ_0*Ѩa[9:.L֍w#'`2H>wy7>nl60V-Qos!<ܫh4~L!*,,_~{{!7o'=zߟ`bbbntԉ}qiüy1bDKtt4@ѻwoپ}{jO!B^8zۇ.a7_q^8b02}z{3_{uѺէGF/:!5#==ŋ+5f„ 3dRקMĉ:t(ZR͛7͞={`tŋ\&m۶Ò%Kϯïʆ nz>!BQ)`@t,.^ g 5՘Sڷo^ŴL 5B-V-ڵ(l6[={dݺu厉[nxzzTjjM6}iwvv&##TN:EXXXeロ?u7{axx8 uj;Q!B^8:t]Qa|vǮi&bPؓ(Q!Q9s&ǏDr{;cw=%v^/ӮVKlpѢE'''۷?ߨѣG3zhݺu#66B!TU COrgA4B!nХKN47=ժUY!BAV {k: !+Iyxx^n]l6iiiDbEJW޽B!SȊC!B ;;{}z=\לj U!BBB!*)9>Tz5_!BQ$q(BT*V+W'33w P ŕO!BIB!(I^tttյU&qxB!ݤ8B!4hѣGٹs' (Ӿc+=Ν;ml?<3U,!!!7de xwoz>Qу%KtB!a8B!#<ªUXv-SL)Ӿj* V~\]]INNѣDFFj@V%^OZZMqrrruNQ;O 4CB!D ġB! `ɒ%ojFUjYbo(#Æ cΜ9L8+VTǑ#GӧfͲg4޽;۷0攔8zhEV~G*_ :]v1yJ'IGll,#GO!BsHP!Z?~'xGҩS'̙3)**bĉe ݻS*˗/gժU 8G},,X`ܳgOf(.2gx+YsAAAV{޸q#WYfL4隯Nnݺ 5B!wdhV Ni'_yn6lr4QnG4F +TXH:T!hCݢMǟ?%:}xݾmڌyn}d5㷞9r$x'j.aC0|4; s\d韡1S_͖a,[a9Xg6g:8Nz5ݣa޵Ӽ/ӹc䠺esT WAw(Z~Ƽ}'J1-[^>p Z-ͰY,/V+ƹ p|-=*1vmȹo ֤sŬGӫgc lR [!B!BQ97|OJ% DV4ݣK% KhG<8دcֵT>nsf,ǎU*˹dL U)ih޵˩DnGֿjqw6q8 RfC>(\]c:rұ+E~tӂ|ܞ4>YP*)ڼˉE1&Cۘuگ$+ÖX%HP!B!+[~`+8h9~Ud;([0杻Pi%͛?N@-/[vNbW5n<k=j~a(gM+_&6eXN|kf|^@ƍSX/TrLqJ[2튺[m;mWTRib޵F溱+{z틶B!B!wG$ r: !-lvYX.ۯ9~<&O{ Qh;FU"rP"# 뎱> ħ5T!!.XPwr K>Um6Lق{ r( oK+. @VnUH*R2˪ƍ ִ(|FS굷?1B!B!RaUb8XnhIJxrBC*f2a2 uN(nLE] |iwخd_j{ᅢGqR אղ=.(}S6kjJ?_u+{jqJ?JԸ: Rpsv%%B!B!-sGqXU@ļ ?Tbd{zu糦]&op~߀^=/?_A_$ipϾ@VMk W"}VI(<@a!E11-PE4TW]ꔌ\a!B!Bq{MЎz Ӽo5 c֣n[n.E1G5=K L_8klT8O[h1݇nܳ_oߞlM:G'$I8}XyO>J&QhuEQL3y>)>R T_g^}ne)'B!B!jDL8Jww A7Ty[Z9s+,b޶Wz(h wne(ފZ f3пbveP M&)Zkz:JOOlF#-/[{jtq#/ ^>ޚ=`ʮOIae=ϫyBjue1nu*B!B!nBܪ Zm݀Ӝ/Ox 93qQ-e6~@X/\@=׵+q6' ^pۻ.vm+%-0؅-/UxX!*,1$Qo=qUam^ʍcM)B!B!nN]qXB냃OgJ]/xCL h-q^MY֋?³.\{ͼu;+SR(vK5F׸WZ/] iq˝z};B!ղeK.]W;wBQ+WZϜ8+L ~>8z==׋b` G=!qC,`6l%N[3*2s* lySlƼ8ɩn~Y}W;l+w^󇇡pu樅B!Deկ_CңGwB!ZLO(x{E6i6w>lh[8i"CKa9y>pJ›޴nuX/7 7aZ Ôi@q Q;vf07)ۓ4_x-Pt{r "+)yK_QaCAĴp1_'?>Yͩpra[5bű;q@qE[_{B!B!Z{ơMNXO(nnrsjEPEF[.CQP3 @vw3O`ޱ=PzzbζǨ69@铏{d$'8 kzzq) eq"#p#_H/c4NNaCЎ^fױ&hVuFk9l99(q^_n4v!BQu{e֭;FS!6#Oc+,DY~}qYqڧmڌ55 UpwCPTe݋**0ϿG4U֭{qMѽ85)|q{}y>GQnvchzt+;ק,hZ,'NbDuKt/C[fv0/jϭ{|֬,T0h gL~ļo?lQw;'N0|2󎝘㎢[WOB]NUPU_(н8GEgB!D奧3m4._F'{GЄBq(`@t,7 ƍo6Z,mՕVۿfB|||j9V9r$ .dKbb".W,B/dر\pB!pdB!5ɓ̜9͆ VZaNG~~>?<B!n5I !BIMM ÿrtt$11Çӽ{wƎ{ B!٪,B!4yW0L\J6lYfM5F*B"C!B!ans=lj'WJe-h4|1'NT˼B!UY!B/'`٨W6Jے+KӑiԨ|~!BZ8B!o3fpy{bt:N>C=Dݙ0aBnB!ĭ'?B!y饗0x{{P(n  6Я_?~z!B8I !B7 /#G DFjʬY8p xBq}UY!B,>cf3AAAX,[rj1n86lԩS鰄BQI !B7`Z3g޲'ErYOnxqpp鰄Bq٪,B!D-/` 88cx3Z-7o{|WwtS!B!BRgΜaٸӨQ#VkLT*F#f͢uִk׮CB!8B!nNcNqc0%_lFRѿL&JlB!8B!n;˗/00~-G%$$^ftXUf(,,Yfn:k!W8B!ؽ{7Gpp0zdˋh6nȑ#GjٌB!?$B!_FVX,6aXTTFaO?W$ %y(B9$q(Bfj:!D-QTTٳʢI&6ahZ)**}XVVZfCTbX˒4B!,8B!noX, ZbTKq[bv"""Z{!hϏHbcc1j,=iXBPB!dBql߾z;v舓G租~w|Mh۶-zCaFRI~0YBQa%nYB!D͓B!D5KIIaJRT(J/_ի7n-[ህ5-773gHTTT>l6SXXHΝp+WWWWfsM'B*ġBQM 1c'NGG ;88`Z2e >>>xyy戅5)//ҥKIOOYf(Z0l'[nEj-Si IDAT-VKB!D$+B*Z̞=7|Ri_j5EEE?a$%%U=5jn:ŒJ'%%m6Ο?G'rrrh4DEEGrr2aaa7]dlUB!8B!*_ŋxyy7Ztz)&L@AA-;~8t:{%1fvEZZ6ٺ[PP@nn.;w&77;vFz4B!,UY!g2k,4 ޷qqq 4޽{˛k!j]v^~ի G͍ \S!c6ȠUV$''n:7n\&eZQ*wLT!P!``ʔ)|ԭ[F߸+J ?+WX7.%%VZZkZA* Y !$!ٷٗ4c"[z2sruhGEE555X+>Nz=IIIT*IIIA|B9$8B!7GV6qSXVyzHB tzJ%}}}c2^(S=$!FnP*tBEE%@4ʹRdddd0I) 6B!Yr%555Sr/t!!!v >}:l6388/NFl6cٰZrAAAZf&lݻ믿Js,UB!<B!JKK "11UYRÑf>dŋKYYׯ@B$ !*555OR[[KRRz~tќN'kעP(0AUϟBX`` tttOuu{CJBӡQTcSNɁXj~Gs<6!Z$B!*f_|dtbʢ78J!!ĥS*,XBUU??? vioo'::ٳgсNZMPPDkk+YYYsBB!P!Uwɓ̟?R鵁!j%22vލ f[w222 CӑJoo/h4z=j`,{x. ???t:jɓ'y[x:B!<,UBJJJRd…fCRqM7Ů]`0LЄ\ugzzz "33Plt:lQPPdBTb4h4Om !{fflB\*++y3gYYY^,p`ZYd uuu|L6]54^R#wRT`ZbQQQDFFrqzzz DP 7Pٿ?aaa$%%T*ikkc…O;Hee%N5VY(TJ]BI$8Bᕶlo͂  zvIHH3gΜB! 9~8 .DQ^^B`ѢE ϟf B@@{lkkfl+p88|0M'*_eýN篇^윯@B!BsNyiiiq7 ;wWp G^^wF2k,vE&皫|}}9~{Rz=hZ-Z555T*|||P(0000e'OPY _Z!q}}t9Λp!Z Bp8زe L&wZ%""£+V+fKRRR®]p\Rk³gtVKff&&IJJߟLhhhV{ƹ 8P ~cf1KnȼBqP!Wٲe jVfto2V+UUU466GPPv,Aoo/IIIm6 nOSLa4>_|!|}}ɡ}F||<3gd̙Wx9f0zoLMYY'Ol>_}388H__tttpQ=Rqe+ۿ?}Fq8b2Pڵ&T*~~~cu9æ&~MG|mBu7ì0! ^S!'eB!JBVP(X,T* JVjt:q8\.Z[[`֬Y^qZV:::ܹl FcK,nsa\.lܸsxb233immNCVhVXA]]w>ٺu+Ji>xDy7Z?ç3KաB9$8BUJ{ypWjj5Vnb`p\viii!**ʽwds:yطo-bWdɴp =|||馛HKKcΝ466'33lioo߽ϫVVΝKLL Osɜl6{졦O|Uckz7e+|"Bx BxMnjݝEU*pt`gXϏpwىB ##}1{l.]'Bӹ{erdRRR3g555B`0`0hnn3f{/Ƒ#Gر3BçG?u>?BoHp(Bx Bx۷T*>}:v> j___t:v8&@.I dggS\\LEE˗/n{Dc!8_GLL cX픕QUUEzz:vX,?ikk#))}K Z[[ 5r7δN?^ %bdR9-Bx Bxpuב/j|||h4Z-CCC8eEoo/:VFCC`޽T*$0*!<߅RIff&III߿r\.fpaHIIapp1MQFyh4za>G] |*_B!P!W9M"&&z\. ,@Vc6Zh4 }m6V˅餫^BCC?N'MMMz)..fJ y޾a0Moo/ӧOGќqzzz`t:n-y ,Mg444zvEWW0'|BTT,^&z{{T&z]r?2-j8Z5*B#BJLcc#O&::pl6yWfFFqW%4Rq\XV1 R(--K_uB1 ⢖GGG3gٿS8u#++ Nx544 ?dƙ&>Zx)<^R#إg̺uhhh`Νtvvq]wcIߤO %_')0#x.R5Ԕ>B#B!ʹn,|,ZuAAAt:ػw/MMMjV͆p/cnBq1&;Ar7_/py1w-홴-o?ü(xW-z##!|"Bx B\L&;v젵^ʗFtt4F*𤦦ގjl6cXL&bbbL[³)I ƚ9u۷o'.. y\{~gtt0vÕ]6߀WܙÿW)?-EV(SODDD\څBqRe!Wx͛GUU555,\iӦBHHMMMZFբj1:t1 (J%##cƨh ^`':BkG`` {/~=RЩL߷_ y`]ܱ f ao>J ~!]B!Brζ6BCCȑ#TVVB`` f"**cǎK`` ]M800rL^^EΜ9 G7bwgעQ tPUQN~~>'Odyo}||߿^HGGsH ץ³a|{޾\s}cȳ?ˮ?\XP! !*( zzzl455v-ZXV*++ll@T*y;___Oh`{[{ji1Zi1Y W*z >Z|+%|3OSo/[lo!d6G0L6cǎZ \.XgABl*4oJalؠ4p(}H=%u<􌁮A˖륺Z!2 !TQQQ,~'6X'=yǻf6ʺxYZ=oXÊU7/חC!=#FDD;/Ý_ߞ_=l-_jAYapc&_݃JvHII%1, ]Bqv !8NJ%~~~TUUhHKKjR\\` 99233immqLӂl+ RHMMnp\B4dGy_gɟ7 ~!QlgJuFpxFB) Au?傧:_Ll\n%5*C%KB"B"!!*F#AAApEyy9>>>dgg300@~~>$%%Nxx8ǎClf7 .$6)۪:yˊ-'(gG[?[5Ru(g0Y{)Tyhx!|CXsK&Z!UB!P!W9Wxb1TUUa @P餴`Ϟ=hb'|hHNI+&54o ]0hxŽ;y#.ot:lc>j<>U|s]oS|S߮_ 攂ܥ^r`(sB9&B1FPǣ gGKZZc`` Wr(,,d``뮻vE]]݄ȅP*=yo,?E=N* =6m /ƍ9nB8/N wY^ϛm bY0 N;",,lB>X%8B!<B!`,55~ koogƍ|gdffNoo/JEpp0&B_=J!sv5;\.Ν{&cbr>c fΜɱcӟĦM\.VzϾR7@<=Wρ⾯3 ,k!Re!^חիWΝ;9u0Ux233ΦvQhZZ-3k, 0F#fRMAlils(d8 IDAT0!p{諒"8z(UUU3nCCCX,t:ݘB8}̦B5gcEJȒe!<ٳgsFZZRVVFEEdees2Zwᡇjw\lrBi vy`]v;wem|"]B!B󉍍bZ픕QUUEZZIII8*++X,Mx^vZ8xBSxWsa$O57;¯Bx>NVV餧FQQPVVFvv6=]GKKKc۶m<3L&RRR<|.쭀_H7 pϓM.!Hp(⪣RXx1 .d߾}>|˅l&??#GEJJ CCCTWWÕ;CP/kw:cvS=U+mVΟAZ/.Mot`~~>NСCdfftRwHXTT޽{)..&''T*|ySRR29ʦH3p x8+]eB!P!W\n& c&##.Շǽv4ŝ|?)זƢP64vqLJul0WK;fp۬`,y@qgn!S"##fٲeQ8Q7=FWN GOBK 'tm0hբG&{gqb`摽 %8s}q9s0g*++ybVVr{rzzq˖-G||9P(ιT9((U,IdS7bywK77߲+Va(B%BkFll,єq, lذ8,Y2gJI->ZBj:-6VZVZLMVGPPIqq1Lbb"K:t [KsA򈉉9#11'tc6ZOh~V40(B!P!WԥlJ 9pZ/^>v!FMAKzcL'uf&xDVMAwP(ƒ͌3z( 3ӧٺu+呕EFF{조\]8҅ 6Ɋ+8.]ӧykG9111| ݒ/ddP! !& VZEjj*vu$7fxYefcwE*{''?a+h]wENNEEEi&Y|9+Wb}vXdC=2wH8|qFWV TY! !_~}|reP(A^_/ͽ.䋂jDO{.ݕv׍ o!&ʛ7oRTTıcxwaٲe_'NGdffſۿ; BI#BrQ`0ʾ}ؼyE]Gc[VnusBsv(/C-}hԐSF M65*BtjBuBujXDn?{Z-whmm'Xx O>hܲrJvMAAdee T q Xt)<{cG7xRzkZ׌Y!Hp(⚧jAqMA8;/~ h4t:y衇h4S=LqJkJ_lf۶m.ʙcKa…䐜y뭷(++#440\.6pV\Iyy9k׮! !$8BqMl N)2Ŧ^65y_"Laj6΄Ppm{׿t:tczS(߿;3x` G*&CCC $%%q뭷Lqq1%#Gqa*++IIIaɒ%deek.=]w݅BRz"Պ^g455Nj/B!% !+t:bbb܏MdC?R.: ZEA'MR< hp:gV(l6x >3#kt_TTɓ'),,$!!e˖qwOii{ rff{ R***$//\4 ]]]gyp8X,dddd⩧"0 BqeIp(«L Ns= DBuR6ڪ@N;1EZ~3+Jя~DLL ?ω#jr뭷0f rrr2w}op$@RQQUw_惁"##ʢ{ĩB!AC!<ՊZ}q$\.,vOϦl<:s1g8H iA87 `0{Qդ 'N|x ze,!]nFqLXQQ#GHOO';;￟r^ytQY3g lf``L&_筞B!P!W]AFcc#DGG|rO>sN6%}V(}7Zm4vs8(d?̟WF=B]i~tUX'NCCCr&uJBd3~)w'br>cG*8p%%%,Ylٹs'%%%:t]b ؼy3Nsʫ ].mmmDGGMww7wq !bb$8B{1JJJ(**zYl:G?0f(_4#Y3sN(?Mʼn35vsDӐ!+ (US0Oǚ DUOP58qzO?M}}=,y O?!O=zbbFSA8~qݻwSTTҥKYj&۷SRR2fn|NJt:n6eٲeW|B!t !Z> csjjj8v .$77󞣫f"##/:p7N~Uʯ*[ 7hcv0Fp|  li:M<;v +* ;駟]_]`` vxx8w}7+c*ofw9[RPPeҗDOO۷o26xL|r7 JC!GC!^k\wug9|0G%--l|||z(?xb:::.j9o5YykݏkDj k9q#SP]TEhZBCCq:SR`ٵk7pwu.AZp!*jcqqqQVVK/DvvnsO?9uwFrM7](6'N`Zg?#00\_! ?~$B+i߾}L&`xNl6dgg3sL:ʰ̘1"## \.,X : rэ|=KR Var\82;6ۨlmcr8PgP)yl>c:::ƌad\-[ TB{{;?8EEERYgz"jRVVƆ  $!!ajIq8h4$&&rvӧikk#((ohÉrQWWGuu5'N`֬Yhf``sOll6G][[B`pwJwo!v~i Bxc47aƍ>>$%%LB^084_A+.!"Ο^{ "l<3{.J#m6nJrr2aaaSEFFvZZ[[Aӹ@ gf޼yMի5k̜9Imm-h"ass3---ZAwsQ By$8BF$v;7nԩST*&%% jZ9~8FV6f N'v3c!ˤ`wPg'? F!22KJpxmذE@@p os;r#_wttSZZʊ+B S(dddj*hmm3T*bcc={6{vژ9s&z+fԐEOOs̙p``GH`` G?"11q B!l !JcǎٳIII?6j,]$ ZcǎQYY^gg6p$k g!*\z<^a!gO/yf9oj5QQQsOG1y*++y'hii!$$-w诧"8p8@-Zt_f3{a׮L>X~7РYhѐdlO&HG3ϱX [477p8}mB^.+&ٰaӦM#**x#BArr2˖-O>رc|ߟaQJ%=wկ8u!!!cIHH !!}]6Bbo>bbbHMMfӟK~oB!. !Z0--t())O>!??˗fٶmdggSVVFVV?iiioSXX8;uΝ;hZ|||`0`6bppz{{X, #$0|cO9y'_l6?昌 ػw/o&Ѥ_5Q(X&n.!KIp(«9^u?NVV<;@>,//?dƌX;oNii)eee ć~x֬Ysn21ņ\K23򗿤]ax>Sra07```@x sqFz*J+VÎ;to}qjkkY|9Ǐ'::~^B]$8B:;;yXt;WwHxQ{=f͚Y~='OdӦMp199yE $4o%%%̚5 ???0@)%%86oLWW{IH:E*=߭ʚ5kx饗())!$$d̟Vettt}}}ܹdbbbxgB!vIp(k޽{)(( 77Cɣ>:frQQռ[ƒѣG(++СCOۚ0Ӊ?444jzH^z3f˒gΜM7Ė-[())ARVϨ $p*o~twwsryKP7 v8lڴ ___/^B!P!q/ѳZl۶Brss"33Gy ZX`K.塇{ӧ{MHWTf͚Eww7O?WSg}@||WN^ի_GѠj/zVBBB~FEEZ9\a9uK.İBe$8B}={6˗/[napp[R\\̒%Kt@,..j!++K7- 3gdٲeTVVrJzX^nNi\..l|||ظq#v^IϢExOAѸL&MMMر%K`gX!$B2:[r%|}}QTj"Kwqk׮套^Pioogǎ444… Z<MB$8B{1(..:HLLdҥ_z}]##T o vHzz::O?TͫOP__Onn.*jtl6;{D@@vFoy Xf jP:;;뮻HJJ !KHp(kEDDx1`QQTUUBNN?G_A933tymHV\Icc#_ט?T\.oԄRd˖-̝;Not:8/_NOO_gڴi OSO=ʼn'Oxx8+W$33s&B/#B2:H^^MP:Ç`$%%QPPʡC,aNOOg|_NBCCukŊ*++Sbb OKTWW^xJAA?@ {+?3[Ns… rrJ%%%Ȑ44UXn[ӄ +ݮnM|.#n׾}dXd,-!)']n!>t\x<:suV+7n p .@>$I ꫵ{n/A.((Ђ ,a>vZ͟?_]t﫸Xg𰲲R!!!Kc{5k){HWYYzEDDl6fjbnr[>OZz0LW&׫M2EVU˗/W||&LpҪ 8JvvԤtkӦMzad@|f-X@W]uzj"HW[[.\J.!I2 VPP OjjjTWW4edd`0vEFFjzd24i$Veػl8Qwu)K:k2*--> ԩSUVV_Uhh>leee)))IIII Ҟ={TVV۷k;weVU'O*^>s}>vʔc*88X?OGhx455_dq&IFQfYFQAAA}WwnG8ߡvuwwkɒ%ڳg6lؠ,EDD o ?~x<͛7Oͺ袋N7ۭ_T.Hy]V Ν?PsW ^q}@=DW^ќ9stg ,ϧ͛7+**JK,Q]]zM8qП/|؍r$m˥6婩Io񆲳,=(!`2wkVկTUUhdŋePsx/_׶mtgJZx˕ ekkvܩ ǫSFQVտlSqFEFF*--M6OzjjjR||rrrj*(??-Apƌ{G[lO?-gÐ]r%jnn￯u9DoTnn# ߯;w*??_X,z衇;p‰s:ںuPuttpd2),,Jpp---Z~┚cz~[[^-Z+WAf:"8SLѯkZlzWTTկZ+VPqqqCT=쳒.m=^.Kk֬Qrr͛n?VBB cweI۷olVPPndZX, uww|>׫IIIIJLLbA+wV]]&׫ZY,-\P+WTRR,YrZcC#Zttzr\蓛o~ ͛׏%kooe45c F}׾Fh8LfEGGh4vSrr8d2)88Xvvܩ;vhݚ={\.>3-YDCG!C!`T>}qopnPP,XsӸ>O+VW566Sff`N[ X,ӕv.K/Y>o{{\o5)SrJ-YDU|>)j#jbxҀSAQ0[]v4RZhBOx^kwY9'4TY[;Ԑ&C0\~Nn2 ?֭See.\ݻw+''GK,)ciCŢ9sGDD4 Q[[?X,|}H9Nnvf͛7OWr-K> e_7'_9b|KSEd0h^d8GwQ>Tkvȧw-J}[_7_ ^OK?Bz5FA?,^\㟟$btk͌s,U:&I?j~ S/+**Jlz OckllYf󩹹Pxx\.)t˿w .@7oީyA@ȶ77>\uM+Q9TߪwoƖ]*xv}Ѱ]1p]9v#RUլ?{Doؼ/{?RMWqlW;??*h]5vBUu55[qBsLJC{W%%%zݭPI_.<8=O77=3P~mu{ݺ,e?4$KY Az}Y?UiyuLzyP~<28SvSO|wﵩBqA_a===۟V$=qM}0U?͹R n}Ѱ!\qz'!ѨJW^QzzRRR_C=]CGp8h"a7H͚5K111jjjRwwJHL&9uttnAiiiǴW=O]:h<=ϔ'Ir윀d[eOVhϖO>-Q%"z?'IF.M)WnTƀ=T_8q͋,IkXX l6[oW_{׿D5$$D?K1pIWssh"m۶M+WTNN5vXjjjjRdd444(,,?ޡΨ47۵RZs(SQ %٢Z47fq=?C'<#l6+**J*,,Tjjyfm۶MӧOWtt&M$˥͛7t*2,(gGolw9^Cd0*0Չ)P1HzL۞|`<|w}-0!iSw,j56$Vc'ҹC0 4X,X,ڿlmذA7o֌33gC[lep ߼^POj$IQl`R;S{|b2a/>aY?*iޥV]RO~4jH0wʽ~h4ffB>OYYY2Z~|>f̘0͚5KڱcG㞁5I;$IGǘ{-21{Áyml %b4#`(pXQQ\.OkjmmUDD zd45c y<jjJLL;܂CNU>=m$}:=?g!&ˀƌ0i}u̓meϨ֎j~znGљC==FC0*y!!!Zr8r\***Җ-[tghҤIr*++Txx$)"4 6fi֬Y/o}p[;܂Αw_i$%Y?HP1wv|jqy:,S0U4;&Kc$I@S,h'pT9$$DOh'W_UUUMlv_.TppUUU+%%EuuuC^áo#Irx\{ln$% , #ݝF&#%s>W;Své8xbAAA;vfϞ$XBoەqƩÿ`0(**JAjnnVbbb[pHgPjy6IRzh€LEÌKd{k'Og^U!w8lVVVeU}}-[w}WAAA:36\.IhTTTUQQqdp F]=n$ݚvϫwkJ%I׌_01=:HJv갤y$iZS6/Ѓz>}N*˪{W_G}HfUOOa6e2l=\7*O7M8O^ݧ_UswfDiV>mPwA-s섩 ORuWַmC{Ձ.Ӷe\\ ѝ_[צFStps[^$]7((`hhUUUi޽r|*++SyyN3g*==]eeejkk"}yp=SnuOr3{⌛/~6EiQtmԲWPm.r2tG'<plw,`Pjjw^UWWvT[nUnnrrrxm69=Y S O?c)H/W|j43ЅXyw9tg걲e}=a)x\vLuzDI>m7C4CF/$_WWVPhllҥK( ݮr55]eff\G]]]ki&-X@'v{p}^1wp{{nn|>w}% ^oUQ13I=^SwVߦuJlMK<*lܩVMHQnT#Rzj:C6C0HU]HHM&nK:::j?~"""msɲ“NU BQ]6kp]ݎwVݴ)M~U}S{5ww:%oNx=[B^[=;GUMg0Yf)55?p |pjPq6-_1~.{S<>Lqf}\Y_4n׳wLoh٣K?_8KVjKkVԮ[ Ҥz'I랏>SV\A_|JKKSrrv59a,U@8<>4n;5%G_VIW|AWY/S Cu4NZ==+׎KR^T;jgvw;ՏҰ5q:;;}v*''G&L>*Ci^V?nМow,=K>t}B1 zC\:[}gV7lӚ튵D3q$-[_0heml;1?ۨ}G}t;|@UҼKc!:p6ءXPPnv=ڿGBp8mUi9Dc!2Oˮw(IH?[ Jwïޔ$]RXKD[.Lʓ$='I]jp+8hvyTn[Y1smn0G9bQll;#l7?BMed@}FbBGߪ"85]͒x ~$Iu4l&PÒ{j9 7~j-z'z A ǚvI>܂8*CE[':8oуNCc?ށu4tao骱tcƢ!j*KRii^x{cP} 0Fa`o8؟ޠq g}58US:\q8w\͛7Oڴinݪ{*##C11>|>߿_qqarop!`ȋPjHQf]ۧٮ/dA% hSgoݚ}#kI.M)8'atƿ;uig%IG8qz3gfΜ<P[nզM EFFq ٬+W_^?Uy!`0tc"ݻ=-4X.ϧg*=,ϽoV[ɶ(ML_ K7fUvwoKkޯ]/33ގwJR@y<:}$izxR#&$f(z l;8/4g|Unn?@ܱc֯_(+'rxϒ^ѬSb>ۿU[izxΓXӄ%:/'\.#ժNٳG9995k p]VEEE*,,ڵkU__ hر2}cujպx>nw}zGK/UBB!tp8d٨8#j׮]ڹs rNNZZZ?I%%%*))Q~~ PXYYj;V}*~ 'm85{8ӕBթ^7nNj=%{Quu233p;!zϟ & TSST;Vqqq*//WQQQ yPUQQ>3mٲE}aN:C0TR7pC%EEEZv***TUUq)%%EIIIڴi֭[ٳgT:s}o>xi4FpFފ:K***7oVXX2224qD9N***s7PXVV"`98%$$袋.֭[5m4vmC=- `Tz C 6h̘1Pvv:::A)((W }^u+$$DNe.K&IK.UKKL&~d? 9Q7+,,ԟg[AX^^EGG+==]999jnn+grAA?ܶmneCYuz٩\t?lN뮻3^xy^UWWDWKK233h"%&&*99YQMMv┒&}窬Tmm4ydf_^ESLѾ}4ydx侖.SKKJ] /?ۭ_T%>>^.K 5w\a+ۧ+11Qiii׾}ϫD%%%w=+PEEt뭷0Q!!!A$feeep襗^RQQQ= sssXTT)99YǏWrrvڥ 6hƌ2n4{lf =T`PQ/דO>ժɓ'C=檪*(55UƍvJOUѸq`&LpJ с=ٳgkjllS!x566jժUU]]<TPP$%%%fQuuuhTZZv}R8e]&ݮ ; =3ez7?IMMM}xhݻW֭ٳKgϞ>ڵkvZڵK1cSONk…jkkbc=p&u.]K/T>y>K[P%guVqժU***R[[l6$ reǣ۷kɚ:un3$dZz.\SSn*(((jϞ=rݚ3gÂ544P~"""4f-]Tk֬Wy<>v!ժ jݺ딟?_%&C6C0EGG'CiϞ=2 eddr/PQQfϞRK/իK6]<!'|RzUQQgCghn---*--ռy+ͦ_W}GCCK/ Wx0׫>H?$;M7Dh  5\J=V\)ニ:,,,y睧 ]x? l6K/)'''°аB˗/ӕD=#8$dZz.Κ5k裏JAAAVss.bwQNNFbccu-(44t f#8 /^z%y^h۶m3f&M&}d tӆ d-X@K,Fp @op(@p !@p !@p !`t;v=ngPyunZ$)CoUb=<ɗ{z_V7lR 6IR-Znwy>Y|Ͷz'*IPZAFљyT}Z7EݴczK{?s>%ȬS5^g5^g?zy}>^򜶶;t;X_wcz?_.Zu>xLw;Q[zs] O$dХ)$yj8g`x"8#J]UF1h9DV\ԸS8qlg*.I*n*?g`xbC00M-W>{JwK.N>KTrwfECNRtp;Jsb4n??^7;k9Dsc'y'A _`ԫq4K&X{$IRmW/v!Ha jjPc`cϖoVKw60Tj>Th$Eۧzۡc>lo,u 2 0l$EP_^HaońV1*o[ݡ]uZ8Cθa!Re0 F>.ocOx7ҏ7K#|&>_.`T UpI^Jil:1ird>)n[?y|^3׵y`Q/:Fj:( z6T۾zT%nloҎ1Cq钏~] O֚m/'4!.K%Iz$I$ hKS dAEM; \nRl1ʍ8Yv 4.$NE?iC2wcƹ2vViQU7e. h{DԔ}*iZ8C^Oݱ=>oI5a/sz]* vꝚ}Ѱn[ɗ*lg`daC0%ۢu}B=C]zfw5;f6=6]KSg++<}T|;׿ IjEEn˾\+6P]3~z_zz"CuӄAd]Gd]|vGaF͊5=$It_? =^#5;&@f}On^\>Y rҼێigꅹ?7>\{V{k{Ɔ܏/q4ezJ{;jk1ՊYVmh٫):3n:n;$-gmSS fj~d-M^V7l$M OR-stkMc=jP9DySluUҼ_r242l6!/ !@p !@p !@p !@p !@p !@p !@p !@p !@p !@p !@p !@p !@p !@p !@p !@p !@p !@p INPi7+4H Tn?EIENDB`xl2tpd-1.3.16/doc/l2tp-secrets.5000066400000000000000000000033421374460464600162210ustar00rootroot00000000000000.TH "l2tp-secrets" "5" "" "Jeff McAdams" "" .SH "NAME" l2tp-secrets \- L2TPD secrets file .SH "DESCRIPTION" The l2tp-secrets file contains challenge-response authentication information for xl2tpd, the implementation of l2tp protocol. The format of the file is derived from the pap and chap secrets file format used in pppd. The secrets file is composed of zero or more lines with 3 fields each. Each line represents an authentication secret. The 3 fields represent our hostname, the remote hostname and the secret used in the authentication process. The first field is for our hostname, a "*" may be used as a wildcard. The second field is for the remote system's hostname. Again, a "*" may be used as a wildcard. The third field is the secret used if the previous two fields match the hostnames of the systems involved. The secret should, ideally, be at 16 characters long (the length of an MD5 digest output), and should probably be longer to ensure sufficient security. There is no minimum length requirement, however. .SH "FILES" \fB\fR/etc/xl2tpd/xl2tpd.conf \fB\fR/etc/xl2tpd/l2tp\-secrets \fB\fR/var/run/xl2tpd/l2tp\-control .SH "BUGS" Please address bugs and comment to xl2tpd@lists.xelerance.com .SH "SEE ALSO" \fB\fRxl2tpd(8) \fB\fRxl2tpd.conf(5) .SH "AUTHORS" Michael Richardson Paul Wouters Patched contributed by: Jacco de Leeuw Cedric Schieli Previous development was hosted at sourceforge (http://www.sourceforge.net/projects/l2tpd) by: .P Scott Balmos .br David Stipp .br Jeff McAdams Based off of l2tpd version 0.60 .br Copyright (C)1998 Adtran, Inc. .br Mark Spencer xl2tpd-1.3.16/doc/l2tp-secrets.sample000066400000000000000000000001551374460464600173350ustar00rootroot00000000000000# Secrets for authenticating l2tp tunnels # us them secret # * marko blah2 # zeus marko blah # * * interop xl2tpd-1.3.16/doc/l2tp.png000066400000000000000000003734631374460464600152110ustar00rootroot00000000000000PNG  IHDRK0; cHRMz&u0`:pQ<gAMA|QsRGBbKGD pHYs+ IDATxwwu/]]V%YM `!@HB!r K7K|%nlc^%7[j$V߯xF3<3琢oG<r_R@e@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@u u[6 ?/'.beqIg+v{;>'za yM펿6,>Uߧ)dsO0ϳ6xv{;>'zm7Eovڝ˟N}CyY۱9|vͫz{†%jk0;q_ۼuul}UX}QcMNyU9GiC[sosDg_ysGxU9yA|?~+ ?ͼ뵪}noގ@Vֱ+}TUUUSBBBBBBBBBBB%8̙3'~6mZuQ.0碡!fΜ?x1@sϕoG1eʔ7n\X".\UUUrRExw*B.^z)x⨭!gĉ˚.nݺ4iRY&VO<1 BW*_غ%.uvaZpepccclܸ1nᆸ;K{" 8䰐 Z[[cy[U!U5kx\kl3fLL>T f(ؿXzus=qmAؕ6a,8ý'wu9ucȀ]: ycÆ 1mڴX~}~N+ՄO<#G,s]jn?s]xdM\<}bo>M8+  00[J`>k sT6a AfpVoj涭{޸\!_̏7x1d;+-[ 暂O>d̟?L,>ˤb*_YsssY/0CQ߽754Ƶ"}xyuxa1S\C0dp/Jsc=V(Pa8͛WRuk߷5#~bM\д4;8`g(bŊx#!C0+3$3 loo-['Ͻ OZ^o4^3z` _U9$Cŋs=W7.^z 暂 ءGpmٲ׮qƸq^8gdS W>\WWW̩.!QJ… c1y\/ø(㯼uma{vU?1kkK`/YT'4l!* sԩS7l 6m7l;/qW[&Y-f͚;cر20\jUN8 $^_-mmq%`qO {VFUMU]/gr+lٲRӧO/E}g) uYb.VWo9jW^`7/>)Z5;~sJ+̙S,-_}yu98z}T֮30\`A 9sfԔiSL~c@ CǫW6Vs}`ܿ! qVCKԶo)3ܺuk.^8FӦM /P={ 0 xgcq-K+9=> < l捥:0uV f e9h$뮋AA#Ǐ8D  6İaJ6[/;~c㺮ײRpnݺR-8jԨ*9?y$ 8:plڴ)qHmzÀ8z]t[] 1sȋ/X&gGg# aKv/|HsQj' ἭXT ^vejgem[bͽ⼟joov[NQckpw~l$ a9p#_Fs1w=UgqFTUU#=,貢.ܻCGc/N=T`C0zMMMڵkE{g^ ۷`s% 5k?2%9O7nUcݪC4\ml>|x|,[ioxG *|0={vWUݰ\,Y_LFTo[s0`@ 2G?|?.ke+m xT ze"o>7uĐ{y1b ՇN<7nӧO/ @# rk&/_cǎa(oksO_>۷n&3?0!~p=񠇂uFCO;~8z!a 7s΍ѣGǤIsA7n\[lko5=qCqQ5lA'T/G+ӄ} x̙k׮--MMM]e;SO=U¾=#:uj&k:j;N?6ͧƌQղ|M 6l?>@/2`\2M6}Հ1شiS|+_SN9%<2y3ܵZ0e^կ~wP1oųFXp݊E~1m'_B)SČ3| z)a @7e$,XPdB_hQ,[ y衇Jp w\i#ӎ`>:thy晥B0{I'u{םO,\_{zI,8ڣ?[spN@n뮻+aGӺ .իWG?Qyn̙q9DMMM _|g?[ʺ &x\0xY]x11#_pS4r>եE8 n@XdIk{;қgP/~ĉ^(G}t{w/ vFP-c[n)!d*N<.fm[_\_^~uh-jժR$0`7rҪ|/\J 3$3fL}eHsssq%H@0Wzz4(N8ᄲ`i׶ԿlCΡ$gVPWO'ZW>$Qװ_AZҴ3ghՏ/@/& EK/usM 7x~f_'+q =qחV\soqE{3yW Ɂ"G}ٶy~C7{W,\OվvhX8?~|9v^z/a /ewwkԩ]!`pu_4 &O\B uJ;pgX6|M75^ה}Λ* 3wk#zyYҚ  jkQ~uthW>oo EzmOoJ+}kem %37o^WߕW^YPlҥ׾7o.mY0`@ǹl0ğg6 sp˗/%̠0oY)y.y80yeԷ-mnuۏgqFW{2˥^ZT-÷ ֎?u bŊ-^8{xGJ+oc6`ce`)`s&l}Ç_Zs۬}o9n)ַyUz9'(bC=ܶcNX6X![[m~=:ɬHw)ømu9s`-[3h˵ [oYf/' PaaVe{ {2<2*6 ~ϖ!$`ɗՉM/Mo*{2Uf;sYe9_4p@GYo;;D{՞&nCk7wvn@d_7zҚЏ ~ӟ꾬˪\oٲeemSN9<_N~{3m600+SN iz>mfy5הq2|__( 2`.?CYa駟N;/y40jnŭbngڲ\?1C (@EȀnqqǕplOٳK0wW[pg}vi/ۆ3P1+rl3; g_l)YՃ9$ÿ /ۃ3(C*Jz҂Af{@5\~{ݲXڲ*njKk ٲiۯ~|7pE4aZdI݄ J v7wOSgsLi',m wqG -ۏ33̊ r0oB{zv.`gH!^k֬) J/k-AcuYa!g9>9'#8.VwĔ Kbpu{Z{;'g!i@LN"pOe }~_/\y^Xrĺ !^;[3m3̠-9d$ײRmo{[9n^wu1[;ü8gȊ|UylE2xPؼ.T[?u{/@Q}Չ'X[ط;N?KZ~577vl͐{-Y9_%m…e۬ˊGyR!b}f(A]r|__*WZUZs-w%ʚJ321Cƍ7l+1lhyՀU *>+C+`V{ݭl?g>S¹o}[%y׼5%|. ֲ0øl].0MWn[N=餓Ja駟58|W\Q>gnad+G`mm. 7lPOgkk_ڲ"}5>++rGb7|s* к^w\Yx72 .Cˡ :e!\VTl[zY^v)|¹.aV.X{9$16a̙7{͛7Te09 TqVfm,zyFʿ\?0C : F*Af9 s ^xRCEn+g%b9$|GJa|9s }<שЇVelfYu9Pc!;d;UygwiAq2l j/= f[qy~N`YEbV 氒,z9(${0J0dy 1=}g2G?ZBF0bdO~2z꩸Je]~;)mY͗;zmo{[r5ה/)SJ+ogU{Ykz/\/+s r|>0C·~~;={v s ]e{p;s 1T'.v6 IDAT@ 벭7rӾVYuk\O0ceE`vY&M*e`\vՅ>2m2=H8P sZb7bY@ߢMxze vK,)vepn:Hdmw|->f A^޲5(_Vf7cƌm%m:dm[n-mY)ۢ3/Mr>袋uo& C%ַsO xG3ό#8UwwD~(:}\pAyS32 *8' LMN>묳b֬Y].`YkfUy}{K@& ܧ>x//UwYkw\Loy[J5bV0`2zho/9& 覬'?O=T|(CF,XPnFS}s=ntq9wwv>/ϝ;7>-\rI9'H@}w;d(AO?]^ˡٖ٢fl ޲eKFU98|-kP+e 嚚b7ۇwgKq % ›y/袲]wU!#97fH8iҤBJ+3̩9$-ZT] =;'x3<+V( &m}8|2Llmm1u8묳qw02+`oQ'/|vZ[pa`\_0[x;C Zɪ _c=cǎo}[:Cpdٳꫯ+2֭[O>dus}QFEccc{v fI%}Zw'@$w7'xM72d$+֮][&ϲ sJpsss\%{ӛ=P\x^K00߿|.A7xː{921+xĉeɳ>_cȑ.(0L<9>ϕsHYzuw}]d𗕁f~x zX'f W\Qt8epy_|qy 0 Ȁmo{[wyT.[ r)ַ5;0 Jp}ZKApӟtEpK/_ BBBBBԺcÆXw[b?ec`=LԿ EUCC=`lԧcf_#ӾӦL|?zh{֬u5Ι53gĀsTO6ч}K>Q{I}9wza /Xh_W^חFqԽu{K_ƏOD.jO=9Zwc},]w>߉cc˶}oħ"{myD^G1+˾.hDW.v ZwE0/oFo}rkԽz͏\߉O?ƨ;m̪3vX帿 em?PΫӭ׺{.@_x폢]/_tjK6Eʹ?mkf{Nx i˖GՕUスO^C0/z}{Rw=cb'_٦;ߋƏ>ﻣCyl?#g6;c/^}{u;0>7}^O}2ZrNϛ_}䚂6b{keVw?^]|=hlb5?3@ߵz />n n<‹epˣҿ~E9|Ri10W^53,?NmO]'E˿[/jO<[7 .'Ѿ|EԿ .oӏFˋrz]w!?ɫi>;b_|+Q'6~bwntޥjۭcWex饗s6^}QUUUTDe0=%  !  !  !  !  !  !  !  !  !  !  !  !  !  !  !  !  !  !  !  !  !  !  !  !  !  !  !  !  !  !  !  !  !  !  !  !  Qs9g{ @ Cٳgǒ%K-jk,& bҥQWW?]z0r-q=??`pȐ!. =BڵkBBBBBBzXccA! av8(P!P!P!P!P!=gsqQ@qƝ|r! a?|\|Q[[֭E2dɒhnnG裄=o'|2֯_w_scƌ)@Tغuk1"N=Ԙ2eA?뮻T).[,N8$>Je @kkkʏhmm5kDGG?@% Av[\;MЃz;vNc=p z-{nr)e3gNs=.0M4)nXpa477?#NЃ6o[l) &Lɓ'0a Ta Ta @lApy~W\uU;=j*%x?_+-G+/7~8>?S@T@`ɒ%}!C:9VgOŴڄ8Š+sskcచhoov눪mیog]m51c4a +/]OS^cOjȗVuDSuk|Ï\UUU1m4# G_qDc3JؗՀP'OM>>οLJGnpZ :,2p]5Vo ScØ#7>I̘1#ƌ+;\vm׿{N?v [nO[_^-k˺{ ׶GØxyB|o. 6;cԨQ] +_?<@2`y[Ǧƣ=k%n5tnPkcܓ=Q[{=qG!C?//@$ Ea7cuwUտܱ_:4N޺(ٟ?qYgϛP.9sfL>._>HKvWcU7h!{K rCxؿ\Gɏ ihh(ÇGf͊_>HT\_r,ngFSM>M #Z״{>Oq|hmmm}0Xx}_go~O _M?Q]閸#.y~[OpѢE}A a PMw?f&9|5u/7>?pޫ˗/ΝK :n<qE۫{hM4v6ƪ3_>ܧb#_56;.֭[W,X>/ @$ *•\?hl 9۫|(W CbqC:uX|o?|N+DrHg}/ @$ ^z)nֲ./{0#G[ZVFu"60j9!: w,l'qYsҥK瞋6mZYƗ}JG??~|i0aBךyͭdXa^4uĦ-Uikut4 hWR}>6Wb~[:2A@O vژ:uj1x8bhonٲ%KV.M6Gme?bHX0 wKy}|߮?>yK ^n>&Mcǎ A[֎1(X-mt勱aKuD1n#~#GĢmw>8r9uri&_,>HZ<@|_3f׀&SM-[ٗWƊE/æC}]&SX4m|/}&%Kv j}Y{C_KFGow]1rȸTղۯ&4"^;8vlc Zp-~ bnU&ZL;Ĭ/Yܼd@" z׼5QF/Z(nغukv";l}8ȑ1t3Qވ+ib6ĆSN(>ի]+V1>^)aÆ8Sc)D~{?B8)qxjXhtA[WĚA߾.[kuXȐ!CdfhLuuL<9.]?OK0Zw^{m,_mq 1{վ8j=Ѻǃ}}oqJĨ1gYKZTR]]] lq/׹;c̘1*0Ν=X~=@mSOǚ-1bfDUMj1-li[y2^\)>~~-*^iܸqf͚TWĉ*n2Pd̙ep?3}xKX`j{j}q@" z̵v'+??~}g.|ͥu;^mH7ax1n]T/;u>}ƃ6'ĵ?oEkk/@! zڐ+aN~cرqI'żyJ(2^{ЖU1:=bT4,?:V{_{OMNe13;y/@ zڱ;?|:ζY%JpŊmc|0~[W;QCkO7EՒG#ڷv޼&Q:+'c)]>Ћ ^)ȑ#ܞ{s: ʄ{キ'pB~Xh^?41uTS.~0e}{P1oݘ}e+} z!a Ч 4k_|'^ϰ0(ǏYfa n޼yJGkذo00N>7^>x|z!a kM6-֭[ײ8̶wWeUQGq=<Ș:ujw:/~]6x@S:mL j]}z8~w޻l2)IJ8h/ @/$ z??SN9eӁ'MO=T]kNÆ +!eJKqK`'[JKj#GQmOwbp][ m~1V?-֯[}z!a Ы]tEO|"J's9J0M81.REK/ŨQJ БM6^MHULDՒǢuq B¢)Q-/DۨeԨ]BD{7B@2dH_euUV!3|rf͚F暂)s9qI'[\_*[c_785KiR<1FU16>-6/U%ۀZ_<^Hg}v\z饥ooUY98eoo0+~ƌ?Os@T>zPL=lP,}4e޻Bʎcb@Sc|91 K*56B@Oɐ~w\r%oOU) :uV}%b~2@wGĄ {{׆~f x!QѽAckӘi#ۗNgƘQ[K෇[{]S9Ԙ:/@/$ *J?86o;gxꩧ#+V8ꨣk7tS h:fP/=V70;cD4:xmUM5{ :ªmLJcb~y/@o=hO}*nƸKpUUU[gΜY";wn 80FYϛ7s IDAT/}2_~eâe|<ﭪc1d'1cklZcz~[yǎc{;cĈ@0hoxo~1jԨtu'߿(/3 4iR<3v{Y7sXyuD!-c1zX[Nu[ꝶݾrmg郗gMٳnmKxdI #2 /J)JB }K -(m!0 !{qޖ9FF9qH~""S@""":F.8pk֬}9R.Mm6r`6QTT[8JpRFvUE6PR~ $#q<u(!קK%l(Nh>_re"""":1 $"""+,,?/G208}eѣ2X, uXLbDbѰYAixf"Ip'aߊBtgcޔЫ\͚7oA 'da,=N Z| _}{1Y'vpuQ(*-@_ӧOTWIn}.T5RzU&CZfzR'!w"% [qYRrm """xopx#AÿH᠘D`1bCa4Q\\v;(((@~~lVRH81%ݽh@su/R3`ʞEШo@/ߣƴ<+q+!"""@"""0#{`D0 QW ovPTnpQ Td1l!BD L?ق .8ia Q";g9"фbTa1XIee#YYYrޓϞ=[3RSᦦ&hT$f!`:+HW6 vn^5feV>/"""":1 $"""Ҵi?Y0"Fi-W4M*Dp( %HK);Gz|דKb"̚i~DDDDgDDDD#tM7< e8~W'(BE!CAtX\b… CfbbAQCVOar|+rZq57Y2d{+]v iEbᚚt:Y9t:g̘ZY-( R#gYrn$"""3o]~;e_͆566DtD4~7`aA Z5mA\V >ƀh˗/ FZ%<Fm‰r- H+E]$x'PUU5*h\}E|g3V~fYHDDDD +ƘһqM7l6ۂG#&ΘkA E#F"""d٘>}:z)ܹmmmF_# #+ ~a6 &"""1 $""":_ZO 0C&da¢h$L$<D9?W7+_ @""""VD+V?}ah|#!!o @"""L~7o /2_TT4\wu|0 $"""'D~_`֭Y^#/Yo7DDDDwTWW?).rM!"""`HDDDt[NN˖-Sl<|(80I x@^(        Sw`ơrJ\P} ,yݜ/cqʤavpf]mGl[^M'fGDDDDDDDD')6~] {pqGeo⑃*|n]~MW,_+l wJ6.\p}‹uq hsoe(8a$"""""""":N0p(W zѦO/ܺF2".͜od3x[z!/ܺq!ËKokC_Js\ł@l[7Q7mzWd/7N8rM)rT_ATe5_,]1N~눈8ɓߕEɓkU꫃xKS[GDDDDDDDD'iVt1<]?~wOBޮzQJ=+qϮg̢o[GDDDDDDDD'7y}N@?xw}:XRTBͷ0 0 0 0 0 0 0N[=mn^U_+qwvpvhOt<| t׆9w5 ŗG)F=_uE3_':^ $""""""wи^$m5_uE3_':^ 贴yŃ m^=`ҦO/ܺ//DDDDDDDtZʈ>­+}SSئMpW?%Ӳa1}NTk/E囼>|'N!{S㑗n{pӫQƄ;  $""~<u""""R䅖oũ w}7ZpEg Z-'/$>,z >n*aObqᢙЪ d_`hn؍z{Fv$|߀jLDDDDDDDt`X ĕ,@AJ-K;bo:]ǫPo~ |␈N D?f/5W PoceTh:t=_x)nfhJ˖-rIDDDDt"0gv؁W(M-+WMC 0hC1p$ͤ_+?,CA""1&B@DDDDt1'q܃Yk/WxCoW)zV/!NVP[[: GގJ7XS3z|֖VtvA7k> DH4|'E:ؓbOB͊I`,-- r?w?86mr\U=ro30;'}#?Ղ.7b8ÿ<˜hBąsLT|{k=_&m؁Rm3Ԡ޷Qc^9k DNb%CNwڍw6lƮ={q N7`#Ξc9HhsT'$)GGv7ϾM_+'bYpU#?/7z1h%&wDD4~j{ntLPOuxB$%cHh:n_7W֗jL4x#V_8~/aA) 4U"sp%[PW4+*8 y"ADD㝿2MZ'\:[}.K`-Xs f^(5^Gr[j+?<%`R\z2EEǛL&~1hLc͚5@a *<hZd9?d,1 ^p ;egf!7h0]̟5 OhuqQ?.oUbl-8X~,^0x\.T`A}zzzduM.3>t'/DXU0,|эW|qs ߏc dG""SO >X4T8NLRA" 2MzxwA,?a-s|Hqb-8o|Q= PVr9¡ӏE3 e]Rфyt:e%F Ov܅<سڴ$\T]o }6<`%k"++kp^ѡA!@"":^{eHؿPPj  0}hZ5[^7>wv7.}R̚V7h,'NlJrKa8˷Dqo$U꛰c>4&d C )tɋ:##`ݕ +ٌ;nS' PS(3HDD4R{,`6mVVZZWbWcvEl>l:'͏3 $# c@"?+wŞX7d+@NFjF9H|=زs/V Ź~8!T'`P_4t`0P(Mbz{z絷!i0ٟ3f@ee%v%qH5%J<<-ߣOBuu5p5DdɊ׈qEl |8hW);9BQ鶨+G<NqB!RD(nUX~>EU< E} >x/.^dpьK$\' dK.D/['M$CAnݺUb~߉f#IB;jꑗ;0 $<9mXN,7Y)H[[7}}waҥXlCtL8ٰ{ߡ*Ftvao-H~  D'o@10Ozϼ \ϾbwQLHu9 yw!?;S!hX>9#"3GO3y9>DVRR"CZ]eee\3>>>~mEkW2|z"DOl4-FUC٩r dK/5X r3bCWO/dw}ӗᜥqH5^yM=qT`hBPB""X===BLfG?߇P4¶躘_f7Rz.$/BW >o\P~FN/,¶mdP?LNNhq1y`F-D،lL4$CFlذwtj/6yKN}<_yoYCY،!kkk}c|q @cQ'Ef6Y#/R|DF-+N.F{g7v+G)7ߍu}N:z0hr#X[Fx)PSy& 5_:̓(f PH@L4a=zL 9yN1Bssї>uXq&Y83A.Ty)XIKK\fdžL8 #X`7Q唿4Lp,9kbeF IDATNKB~f &Nq*'i:=gؿO4-\ujX, $ j>9p|&dœh!̈́'-D3lDm֠%s1g4w㈪p$"")W@I~8^Y #5U/P?MSP̓7#mv<l_;_?xX$:9ʣOր'DD46~i b[/Ŷ?111fъ" U0JdmϚh 20FDU]AxQM84fdc(۷#mhDk{'2Ғ*ή~ ;'V^xE]]^-C豚p<4`3iiOBFS)(=z1>I4>3)O +F#9ZFeVGZNx^OF Wc?¸8jd_ADD6Q ( MÏƋyyy1]ϑ#G ,ubj@Eyz CL}bD "⯰K]D-8z0,8e&Ml46T$/+M>FlZEb^w4-H9,,4u3d@DD420PT_cjXw Ϳ T?Ծ-jQH U @cƲP+=hnn!"ÿomDc:NK缢*p9pzfMA4ƈ$?jDًcGPW&D;&!;#GQᛔN\*O3p`/+}Wxߝ?$,?D+;F <^CDD#&@q3bݮJ^cwV)| /fJ1uz^x[e<5-֛H|kwPE%@"֭[e5Q!(miiAfff(히 nuq畘y.Jt0 ɻLq{Qv2Κ  hhFo%0!7yUήſqَ*UiuG#j62SX4gF 6Sp""PB"P4 ~gz뭍A`JZye/\04DŽ7{M(9BA1uy7'Fbh~ozzzF\ڶmZ[[uC? LII:D`18O!R4*0؏ӧ :MPOp hi8xıvyN;Aq՟ݏDu1ٽXT^7 G[Vq~̜^{ \=ADDOHAiCG mXiHB3}PA^ |J!H̑XHH+>g剣8YhR Qq"Dդ{DDD'իZ\??OJJ:Ue\jdw#&YHt0d=b2'q qUy@yȾ "1NINj[9> n`>ng/TbaEP0!mriTa""h_vFhtaEnVoMjGE "6e*h+ CPs,X'C aH 0Pd6662 $"JKKqmwĴXeee2 v>Oe/Atp4HH0_2F,ķY96$ v6ϭ|PtST zr?Ȉ9A^hB.75!qqF24PNsb{/t.?ym9w3), l <匇OxPzB|^(R-˯<铊qEHLL -4"h&,OFT8Rq"" @|NFM#yv܉׺rO..=.Z73]U@ c9_M r3OỎ x#^r̸wjw7\F >^wBa~6]NTT#=6D I6 ?P"Ӝh)<1Om롇E!E3x_@'\]8JE Bu <P <6_) # K>?;5} PFވ@P<SzD8hH""<m@o<1j|.]?a˖-2,((DOBU\E(b]+/9 #P4@M@hE>8^]!L =tmվ=ÛߨUggCeM=r2Ӡ򭷭*iN܋>Do"[a*f_~_?}FPA_ PX [c2x9+ Xou%>i[?ŽÂcC(=Tچ&V.c=T(>%"##ӦLYS10_Ktlod0h^nq\P֓ c|22끶 މ}nJ7@(u#,b0) qnljN0Iz7\n7ۑ!Bx=!a`&ZMQ??o?EF]_/nPV~GjQY].tuCGo+[a8< W8ҪhS/j_GBJ(Tz׿ x[2Cs,BcrjlOs'w7 t:gޒ }B )`_.|MITt6샃knhi\"[O&Ii2X[nFcٲerOJ΃0[,HNNU" =Zmd((DUQXXɓ']X͛6[.Dݽ.LsW щ00F+.?\T>l.0$ ?ڈ8F3pvJ30HhX\jIYf d~DD " X$EMÇ[w@!tvvAoF;34q&ĥ̃nV'֠}au# -ܨy/yPC)p  [gU,}ΥxnD2t$Cj| z1pVon}rfwaK~/òsOAD|nZy)Dz{":sǻ;e0 e5-ص +!њ*Cxy|\$S⮇ܾ677`P4o6JJJ0eur(+rKglBם7} c@lB5sxw\v'#a`o(e8}gs=4*v~*RztjE\wC @?R= >@G8]n};a͇N[;|EVdyPy`MD4n?n)XTQZߛ?ڂVFg)H^~ 6 ā& /Ժ7ڦǁ׃+d8Qi]4 7hÑ࿣T"^9{ Y֍x㍯[nҳ P4!":=[q J:M&uVdk#Z,\ݘu&g= ֤Ã' ]d'4n[[o.͓ݻi&9]"M%xVN": gwg/Zw?ڇ^iv|aN5*%v@N0!Zlm[Go]}w╗ƵqşF%&67ڛkN-A´+`+x{1J̓ ^VmzJ^V#4G >?s \GjpJ|Oc05'-k,ko>Ym"NJɫlaHDgCFNc40#M|Nء9vM7,v4fa{r[7 c7tm prў)+U 6Qӑ &k`mgE7$YuRRhDb_WME\s\VD# ,OHa.<=sz":݉A|}0SeF& X;W8! ݾ]Ţ4dыNl/݉Uj-Spԩƴ0ul=\d hX<+}fijap6J@1@ȱc2VW UuĥgcЈNq߂U1М/rm+#ւTې́=*q{C8P0JV [D~ NQ(¿F W0L\Fr?x=R_}Oj/zm0p7CB5.&;@H`Ir4Y* -TV-?{]"r1k , H,h wD'¿Fo}fözDD_ yUg۔*)T*ċ)-?ܟޛP)T #uE6 1{M]2"^޸w᱇=g'"SՖ뿭Fi3աQO/(3mH2dȷSy }H1R1mihrL-n=N g,uдݑYlJPRwy))A :q\̛;I00į.b.KLxjhbu nM鄫d 6ZN0Ճ7o{Ç#DDc@@1n]܇tϾcF )5UMRN⢩ |͡^[#7 U%EH$p١m 0GXqRe_PS`rx?Tk6) ?}Y|p N)h֦krlb`j,nP^@K'_ߎ/]< }Kb|< Yݻ|NatLеiEgGME3b\πƃ"){|?@qa`tvc,榏g"Zǣ?ڞ6'f |^S wc-\n]M 2"~IjAc{7@"1":'JP_u63H6jB06U A`b PaWmUJpޏiU]}3SjD;j4p$^ =f7.]ݲJDn\!?C8СKM&%Ӆ?j=&/>:؇N~8gFΟ];kqǕ qB]ᲳA cD;+=Z󧢼Og=.\4=*AU@3aIҾV=-ƭXj@FowV6A<0 '*s|u;xa{%̖O#'8@ u.TjJ)#^Rk Yitb<>sf…?= )EJLDDMEE{5-mGKFu&ڴiIf'bm50m<^׵zA1 Z5ZƖ#(mhCk- ysX>{"sqǯ^±NKg+P }~8:lFgGSNc+|w@ :4cZa ,雲8\ӈ%'!'`^עo9Uj<os> +QtOON DKDt7 nmm?%J뻑>C; 0)U *U._1,8Sj&4)-+\pMspp[/J_?U9`Ur1Ԁ&Te? {37\gRR<x"*?JuTwtJHк۾$"+ m]=n~&eYMITYn85;X:=Ο$¬d v9o]_TkqМO5܀]pvԢG-[o3XM40 `7mX6o W00;D)SyU0O#&3ڦ"PDD4P(:|g-FY)CBkx[p<p0_>>Lz"TG)0 \צ$\@[(Ux,3pJp͉#Ja`PM8(I`I{!';Εodhxe;k[pōN5u^*a`GuHB0l^|+wa%n?V.旤ާE}K'^0^x+Ϟ)YO omCBmA[`STb}-<xL ոsK40 y20#ŊgM;ʐn%Kfc-drgՁ'br:~iנoMoI@i2%K@D4 O@Q$ )Xw|A[a 5XGuPMwP W U[NQ齈׉FyRnf`gE 8+S\y巐ha#]Xx.`7f#Ν79Dc.Z< (dĕ;Pv͟*+ 9I'Zo_Դ:ЬA;1Hہ5!SݟV8ݔdTVx3&fGVy}[铠qش OU aѠ=9Z%7=?\qa`8.(Egwzg*̙2A8jv,QN߉Ź `3 k&}|Mk א0l@D4 ]C8e (_vӰϻ^Ԕ6T(nHMA/z|JE/R\p`@ 'T \UG0hV9\39 /X/,_ fYAsRia(kr]mC:wՏKp˹ӆk1p)iK`BIF8Fq _Zּۃ}(Hf{.7Ι5$[89KĪxaݮak|$;nk݁n'z{R'&H͂N x,| 8_0 m(uy24t=ptlQ tw Tfר.Mp2N˯ڱ{/~ೲ"0T +j~ò#U+6 7R߁*'h?W,31{m r>f~FځƆ%Zѯvz06Cnkl, W/{ _=/yICü7YQԍ&|R^hl+.%iC91]B Eׂ 0&$sPmEP)>#SӛKz8bYv-0wZ ||t~X3av }<'\>/8gDDg2< e|`/T?vJᏘH#qBT'f3b0\ S|\7GS!.TqfTֻa,ZHz`HDc·{ЬIE&qif<,ll>Ůf|p݊98{zk9VYm;R-q%RkpMP&mq e* ߼&'1wyyQ&%"?=i𾶮^m% G26qhhlڗ k"DmB]}0 ooFĶGTu-o.AF5 LE "5у#mu2  B߈4bn`RI4y(>(GhCpA@WJ~݋j~XIu ӕ G|<1m4$$$pDDcí;aYUԪבi,o5Ī-K8on1l d)lqaLL7#;)~:>L@, Ӫe_ ]O󀏢Lo[vM!!@);v=q;;rg9xꩇX;@B =f &wfg<|泻;NSGdXjm/FK!z/̡xh.;؄87kVr/~:!10HwB-f:/#;,w:G85o/fw+9}0j/7c5fILAٯN87#+a4K! 'Ņ'Ib>VWR|` _hqC%!Q$ ~b$JE@v$wg=[l F ցgq#A!"Xs3G-ܶ*9Cp]]Wq98utI?;a2>DŽ1=' 5[!0`&6+M6+oŷ[0<31.EQUlvG)d!!u[벣_%ĐAv&X{P;=(fM0y /Wo+};X~2M$W6ʚSw0<oo?h&b$֋l ¿aؑ5^to5BVIQ"vȷ 3Пx5+FqԒN8rAN+K]΍RRzZMBȶ%q$>3?^{&1 `QU]=˝,S%JRlBUC a^5u$F]hi;r_{rc}qfz- C-$G[<*{K밷R*$9PVo7d[%, ND'=4p԰7I&Eâ!.YYYxW{~NGasag~ Vm܍`CcD {$Ta_! 0}3K_Vz }~IgX,p2C P 5L AƟ!3aJd:ꪉJفB8$swՄz?d!}6[Kv ^'=uw"at cļy0g<O܁iBnL5H \=Lf=;p}W׆OIƚd<MٿJ|2AO(alam6477c'qnA|V.&w`'I@䂟/$j( %<1HKa}Sk}+h ne`AAMDxĤÁNudNo+g¢U0<9pnUjuf(-N3v! LBu=BoažՆ6G+ՅHNI͐߆=N!3 ǐht߄E/~gł%Sլ Wʘb, 6ؕ\pyI=xJTlnxV|RW^i؄,E)JUcw*-% 6qr\M/ o./9~WgKC>\ r`2]=BhEWQ(ֵb>2?x2KENZ&i+osJ,Z`kh@K}% HKOBhgC3܀$:kѨhz#<{3P }Bxxb[ C#:)6#59oر 6{뼝P KC*j|ZIӏg)(JJ)/f UnB/moxJ-J'Q^LB-ȯH(󤟥 CeJnj}ፙZ|BxF<a!B> ,Lݏe w. OmGkh2p8{ՉMB7#$+X_aāf !2+ɉjQ\4U ZI)e˒Hq0x1tW='$(//ǧ_,Ƿz}ܖ56 `k!%֊0 קz079OjF'\X@r&$/?r%$)gV`L#oS_ iZri6r4BBB9} QtW `d˖Gƒw_G\u5M i#BAUy`GEH9f%,N&Aa/likkk֣nBLNTPQr <7a^]U.օG+bV:yVJ֊ (R ˭A܅W-M1: ?i;^vZeaM76 j\xvy|^wg.$& ifWC݀f셈GzZ_7PY1@(Tp4a֭(+:}ΰHLJEl7!kǢGoÐL:1q@bdY^ְgy~4TBR@IYgIL-s:i:$ Nr5܌&懈yNB.DB82'ax O\ 4"wCf8 5)ҾJ:VqZAɋ+T__Uj|y IDAT%W޶j^,8T_e]<131mtC#☒Gr _/|{k0},:= KPjEeu-#qȋjT u ᧢".8qQDI-y1_wkm(oAA9HD]3ǖf[BFCA ЀZ& ^oT%棵W&کt(VJb;JOj_W*#,#1 cĉ²pmZ`BB($6`/JZ(}φ5`c]x⏗cXPl8I!1gj:N-۵ Y#&!&n%qL2cQ}mxXT$X<D #<ڻII{/E;PI(YJR )۟@ֆ4dk[kD&߇"ZP:Z(wMA/%AwjnbAX;~-Nۼo.f7,藐*0>qaqN"т;q304qCbqp?fͽ9c&w|Xa\@:9 #&LМ۽D` 4ެ$rK B{ K4qb,?^`-â4Rfb$Jڤy.95aΟlj}'J;>XjT x8x{Zb S [xZ܇yǣv\S15qw \Yb%]FWDž3FcKh=D~~>/y,Y q᳭ٚ=q8w..w߈.CPl]56jl~Co` Hе`A<ފōVF&mj $(0A6 :q+ϢIPgEꯌ'L:V[,?Tێ'݇bj?U/ن񫍿|XUȤIQΥ\ Ԓ(%*O&JA: ]dgg㯾eشu'6 ɂFpɄ1= EH90O>Z Ww\&D 46C 髕WCkv'/pM#<&K?[ yo6w܏ O=;i ǴsĀQ(+- C#݂ŜDu]'1P dE \SS a|7rF0!(V)iTPtSsUsUj[I(SVj}=>x"VJ*K۟ $Pڕ_JEܿT%]QTTD7zk A1 ADx Y*l^5fODMG}#'FǟFFF` =F M yĢ KL*X;ھl<=Z*Faq)e˖ /N<߲aŧXb9--8'D}I|lhNI ljjk.)yp!P*B ^ҘR+)i@5@%A5@E"QO5AcgUi,Mhh(n? +76۱a 0f!^aϞ=Xq-UC@g}qy.?_~Fn7`C:e62 B5?#j]Dd lD.JcJ݉Iz;_L@/鄼M%!2XOlRJآ%?JizQfR+;ޘI8\hݒDP,z'Ikͼ62,sM$cɒ%ؽ{7yTTTЀA}m9kpNn*kp>-voقÇ#1=5 ۯ_?!Lc`QTQmp \|hlھ[^ Z aFVVooaܐ $Du t;ufAӧnFi:x̝CLWC%za7YAAm{V\]:i_x'(B‰\$JJKB~%">mPKb D&[2N|Js{1ݟ{PyvmC-mNݢTĹp"%% $V^09 )ڂ}5:[+W v{8`.ñqtS\m¼Gc8|ʣ0F&cosX ]y5QGd!$!- SO={V2oźoe hX5e?&8XcE('yuž(YJZ*'1wM0ĸ`u*OTK]uuu{IuX*J])}/,]\zOng]Q &L@sP|8m|.,=J8A<7(ɳ/Fi7Jˁd iV#O~A1M8Q DPuX-n<_kVK<Z2ˏCf]LK@bjqE󒎨yrJzEqP."bT[DAywE^<@@CPP)ҵMAk 0ӠOk1*=ϝ[_ rPfĽ#G ,/oݺU;p@AZõx9q-61a)<< FgOO mm ).}0,H ]6{vBI.!rԗ3GQnll} O:Up fBq4ă| GfD<}-;i:f]rK/NA1geVUUU(-DB?pó "wIE?!oOVmD2-.Pr%> $Ob0f5VZMĊnw'̟E@'] @2Z3K}=bcդ?+J9!=:j~N=ͿZϼ?I(~7?p,zDK4p&qD!ч`1`D,YPۭ/ 5W|Uh}%߾ʴOD𠧛 1xHf9Ԣ3'igWA~q%͙8< H a1d0wk ,^ +ge 44|.]YrĒ` bE ٭EAZ;&c΋}tJqS&-FAd%6Mg].06Sxo<m.(Ad{j[h01(Xw-& =,ڶk_۳WS 1W\~:|dB,V\|HwWBtD8h(g6>|` eAd֯_/jֳx,~AIX6eFKK^ ֆj:9Aǘn@x`m|D!xB $"hm; OpҖ?qM^x"6jZvj69\[IȓZʓy9-M^ 0ϻDAᰂ憧[CvVm7o<vXǍKqȀVVI.*uZq!"x Aa:MB߹i q8{LlS+iv{٪MM3,QXvaf X__aÆaB@&j\ .Sr09;+Is.H  7eZbˡ\Rx"T˺<ث Ģ_IpPƲS)(?fi&s^ CiۢKԺMގ/5_.c%F]ծ/i6dyq}ITJp"uوtX>)`\7[;g[{ 7^A}EbbAĒv.2(9U =SgrO>Fމ9YhVnDjp|f8.X©q",K*o>aҟysRr`Wl޻qw!*8AꫯcdܐW{%w0x`̗߯%ex(Z( 6%PKٟ?+>zb_&vW+ZICU*J+%ߐg[E8 (ك}O.ctJE?i: :nrA,o_ :2 wתk{no\u3a& "p<>5E|HITFq LȻK>l*T{>i3%k00=Oouܵ`2@H"2aAd8J֤H2C݁> m-trn:~Xg7oDu avl>>m2*s z 6#OV1;(e{UrgW* ~E:z+S(ϦR\xHϰ;Oq{/cmDP~-W **nrA O,M(s{@}M0 jth֬iܜ#1waH?63KC;XQ8 Aϒ%,?ۑ93k؆ CYu9*-H2 ۶mÐ!C_KAd&$ ܆oW{>\ /XK4`{ n7 +6̀[ƹ0wKa֬Y4x=5gJ&iԬ̺cT xP_Dlu%( {<@L/O^,ݷt6nr%mUXv,s-ǩ,c(;Q.b!Aı$a-TU#dlぎ2ۭSzm_,XSOxK^ ˂r۝hy!kv !a}hm;a[pO<-X82m\H ˊw)S`Ϟ=#+g=Զ`ν?y o?Waitr8s=رu#6')ѻ_Yqw|˄72+.)g^D||< 19<X] 'rhXj+/j} js;g/A=J!+uUz s {\"Jp5!!!qqqZ c\3M?p*絣[>{n錡?D~fbƒBH!A[8*/R8{ٌhu)wߎ6.9u$,h-+cB K0aOPfBAiKO?_|.{aXx{6fa-4 / a:6چAucXPJX>_-qLQ>lrڝY[ʺ$fovzȓ+܀s嵭^=Z췴ؾԕX+]/uzrL:Ua2GAį{̂g7""mj&3&gMȆl'B1Xmifuk+QP\. AfEōYXJar5 IDATDo`ر3Q|XѨXMHpbj_hiP{fȖ[Э6zu`bw76%JH >q;O&J"︔bBTw?@(:BK1}t b Y"e40AD^s32vwr<2{>n3Nqt;"M.ddd 4̖@8 sTMg=Wl̤Bǘe˖a(|re(4mb mn"7M wbJf74=I[[(<Ktؤ&4ǎ@ kԆ3OS믒`h;5C% @DB"HKXf6vr"%hr:Y iݒ%Kh` ^ 9 _[ &81b˯[qofcxaȑ#Q[[+ kz\09 Sώ6'_ 'cǎALj 6îkBÊH7}r{0<Ղ0gZ I!6X hL'm, uI"w%h zJBR^ޞZAu֦P˵(~rPm 6j$JcJc*TwaBP$""BdmX\s5>~bǎgKjH1 NNH $''c [jD0IXrC7?#&%Ipƪp8P{n9ÅuªmE{]>/mHJB' ̖-[ hsLлw'\y$9Ť)Qhs ͭ.dGɉ o!3ނw,~\ -NjwopVJ "/ T멉_<LCkIADH-*y \:&̿#J}ض# :^=p,A dl{62t#4~.2-::]vqo~<?~n@ {9,a{/a+u"-)zcj&dDw܎l45U5WdGo~E(JK\ a؄S1kh "td޸ω7Qp `vc2XXPфv -^^nS_)ϲ_gY/ˮܪNK[J45Mj* eY{/ˤJ3˅DXJ0,Pbz P: 7}nۣHHL' D'|VĭoѠF7j=eҹðz<{ 7逽2b5F<+- -xrCM!7&jtfAȳb w6\yO)wgsC/S-B;H]\$JOOfO9sN;ra-P&# `CO1'̽`GvlUTPF̝: ?m,wY0_׿؈L=.g` 0at`,>*>7 ^G1͞px]ZNW_X%\8r%n&9@E:@\r,疬$Rs!2R=ǡd (^*ʏ[@UGov;ŽwI\cbb`2H $TٺukuLT^r%f̘ADAW)o߾²zujPup7ek7`aXq-;s-k_A8zjbI˷Qsu$RDyf_y<T)\ }J.&f-<Ӹ9c:XԾzZ-jnÚ5k0|߳waYr Aq\!1D?1c"#3ߚTH=//(@GA<98cb2`H4zZj+OȀ8v({^'"}hZ,j.ZbU%JZ *\B /S4X10Z83 AiY 0!„O>}ARR ggg㦛n! ;+!>>_|lلʪ*mkrvd`D`ߵ;%;17kx}9BC4(F?!;'ğE\s @h%{,4f`w ԅW1UXZHߥ?CPyC䢤(>J31Gj1v3r?Xkؿ(ZV* XyvM8p\ 8+#++KXK8֬@yY)R30d HA?0vl\L r KS%'[zS.7 N@dVAD[)ܵt8ַf$$ Xu--qjx(YKJb%'V*L#=Y\YA9LO>?,0$ 8ސ+eΜ3; ~-f; z<UC# #Ll5q 9]X 6F"#! U"q'm5[+tȈaho[N竧hi#ЩfU"_>VjynJ<ىwWG.I=\nI(⑅[[ ymIO* fŎ}k̋/(677Fd [HADo_1,5\CAA`!Ül{l2̉xr zfK&kqI=hA[par&:a=dVd$AB߯-Ie&/KDJ*Yy<14\!w-t?1 ],#&lBqA d{& XA]C   N]3݌_ٺuM ,32aG\لXU:&xb /1o;JxWa@fIoV`ycҥ31  z+sAf <.b+{?sTu;VC Npf{=2Q؃CP@w~I۷0!GILnJIeJFľ!Xzv\G%¬DŽ+|qP7;; 5H.򣘬K'{_ LcxS= C%dl u# ZH'rB.\D$i4ϭ8@i_ԓ] vČ1&(M laqElS o6j ClʟPp(yM,ZAFhnFsu*n ]{2w6:Y(sm؈{;/Aٰ>$ 4-rCp {0M OA40d0> }zZ@mmo\OqпqeR9F8PB'vݰ>±mn/6ƛ!&o;[W܆Gqpn;dq@m*,\ W|zCS+ D=܄3і.-/%^Fq0cdRɭH p:qJ iI͔MGt u˳h"`%v?Ke` }˒K<"M=51"U[B1h^zU$dpmm &"8|v ξN| #π96[V{7]_Ecp„ HLLāh"E3 ąf$ⳏaw¨V Á!;+ݛzYs;,to̥8jdm{+7*Z1ĉ3b8ln]^l<ocQM[Dgf3̾v|s1./l,nKؑdxUvw"KZݹղ+-RG6b=y/ (&eɄ~466Jg3 ^l Bhb5]G#exqE).^/{/aل>̝;gu]A'!&MX>?)`\7[;Z[1z϶|o .ł%wN%ZjH'vT5"9{.^np8{#'L.DAm x#gZjkdB i)Ih+,AhL$ɭA8v2^vc%c[/j_yLWt{eofh>,}Cs,=pLi),*_x:k"NuJlk@kbO|S yscA]]]%2IHH NRH 2aݏ{]d!`g̈;6 ۟O>v6oE="ӏ{X:658c$^HՂki%N ^D%:} 㔌V$RP\o<ױ=6k1ju5cDp 9v[w*Sk4- AH $NV;Jx/A ܵuE޻1ʼn)Pԇ!3 @2)}[CIBˋp#tID+s 'I*q`>xqD DP-L|K&Nr`Z^vمEn\rt06<w$&kGru6XLর ,W ל7]5G£aݺu Rۇ3fEBqAb`i~:O?ap.iS;\l7̓7t}g탏*4. k1p-X`=JS`#AFĘ&EXOFXS]U:`F&&G&B { ^ LcA]Ek{bmk;:$̽-߭ .DPYTH5a/ʆΟo{Azjm(S,@5 @LkهZ?y(DlLkN<5 } nS h}hm;a[pO<-X82yjH'B5O8&[C 7cn{[%dw䢡OtTrɫsUeZx*bx4RN6yIBx1?()BTH4_[I'Зb݈4Tch15q狟㙗܋A5 FxTTT lҰvZX NBH }A>[OA|HJV\x8:boRt:#(T*1u+Rj~rb|6X"qRs0 /B'w>8̭:/,\H'9L; :KTRIcRļ^π +3V,}wR(Vo'CU^ζ3%_}iS's{oGD}j z+)w"=!8XvjCG5?;0[p)#=h',l444EDqBb ѫ`rfdd~80QZ`Ge*-^T؊̸\79c2(͚IM!@G| xgMAm*;s޽襗,DD`-gB@,22w0_9 L@+#Y++˝Xsw;0;; hqBq.j"R?VKnH>W*I˥⡴/AK?. po0q*Ӆu1WWK %^Yuv/Q4,ߟ}nw~weg.~K.=i/?G ~UH*=d = bBb 1n`[6Xt TsTl@sR/eNćE@UXIb wX#/24`W2-6?W"-LB32<k>_CSsYPwtڟfx4 ͖-g1K0QH?=bA8•xW_wdx& 2MO?EUUo(|ט )I HJhi=nvK`MDr?| )6"ƖG"1W܌pm2aDZѣ 'j f<.07?xW kjjݟln/=LVڄ<(8 1 B=}( +|{.[l7p #ОA)avqtjp{ÀhJdzVr HII (6s^mEd̠$b9xKw_G8S'r@D_VrUs@+=_rM)0xoD퉸;DW^y%o sj6&d%N44 pDNd ϏHա?,+1sՍrřx?>[x> $ &$A l'ҟ"37N`3pC`iQV xec=Zu9 ŦYC u\)h=8}}'d 1gτqf-ؔZoj@bL kuyPVVbm0m45>aO-}_ .]~G+_r|,bىC|GdA7ۚ>ڏ?7\ub[~Lb A$@ 0&5R+ZXw1FX8Q&hWLl-,'`pENj_AsgDP^Ah檺p~y`؟Qb̒$ ܂YhuO&X e?01QFSݏɄ?&2O3i/;ccz節z'mbAd-bx{'ڹ(Uxl| $Sd"//_|?022/V^֠ h30';%5g(˃3a>vϽ9椤$TA r&P9v)li6 *"׃5Z1'3w/O@g҃0 ~l Ld- s&x<-ZZZK58ڋ_˹_ %  x'ohD<=\㉷z.~ƤlۧŒqYb,0`AARSSqttt!w4l8cjjZPV}Vn2`KSo(Ծ:;IV|_Vh#de AI2P\,<1^/nDeyVng˻y` f?cp^ 6vspQőR^ $F,w4'u  R@K1A`cS.J0?$M%sݵhkkiMtGI uO:e޽o H%rd膶z U) Qp&ƚw{o YAL"H $P9y(^1\=+s3,7o%/21-':0dщvqsZz<{{QvuQlQdŰ)%g" +rnþ%2/!.XxHMI44'Mx6&„<,nXpP ؼy3zܹ{t:Nϊ$vU6"7?} $,cϽF IA*'Bi D _š>> l7-F" d[ Ҍ@f!x߃n7,Z:N !̅f!>>Evf'Wrb):dHLq5:V,K᯾x?dQrD}p2Ozz:]LTT>Ç.\dIFp4Ep,[4s/ {{b_K6Hu.|u2  sN]# <#t؂D~JPȔ;`Q,d̹p;ڝح )BQ-5E28OE !b1%>qxh+K' G *Bݗ|Jƹ)YgA3 PM[QaXd37jƱcxOYW3a6&oڴ ٳc}_PtBX$Za`]17f )PҫǬ󿊚NA!$Aa޼ypQFW{ȕS(i ^|L3Rl` A15@&sN-䅤 d"K8b 8p]@,Px+m- R@TT f?m%W-I0GԓZ>t|u"}[6CGKž766d۷o,`JJ _Зp(MDDW9]Cxg\VM<_uuB  Ta1`N2Pkn*"-f&B6XQ\#hqكz8Du ̚Фf0 a-n7袆ej 堿) *ROA 1Q/F+YpAP~\U_ii鐛~eFx+&=6n&&& }P@V [Das6-e$1ȚIԵ`l4Lq:Bb ADfH АK3 T`IfȕWd ?h܄`U.a0;rE8G`ŝ2oȻ s #@,ůb.~'C3.,b}*$ƒ+n?PqC͹ȾɹL94O>$4NNtt4taCؘY[[;tԩSXl{jj*̙Jlذa8"矑pZ7*xnc$Wwd/@^ƃ: AiAF@mJb+i#7Ϗ./'‚OIFMa:p? nf|+D1lKAXzb&2WiSgޫprE!PITZr&Ab4PM_uBWP rEiع:f?7p5X'PLff&:י5kְ7L[ :jfݫxG*ұk<8dDm17& o܏{8w/3BYo0P#8 !1 "؅ 7?D@HP ց[/FM 6ܢPX,d QdKXA0YFa=8a9ٴ^ԄkE 1s;:K7*Z*}D( $qF(e Jm18#?hh J0k>& q줸؀, ٸ[2˽"~OPQQW R"]>xݮY(DB)Htfc`tAhERtu:  Q?!l@dJ iqHۅ66S0ǖ7nQaB /c=1Uo?&a"0i1|=K_lcL-GΟ!' VrD`_#M1}+=?5Y:qu@؟iw}7|A{>ECqbfҥKqgw?fafΜv||@.#!Sm5woȭYOh \ጜ(zc(_HNMGqBb Aٵ'dM1 ./V8pYq0 w! {(Um*H{| mRYvԉw| NZ+(]ϕ@$& oJB?/ߚ?7giÑDMlOIII|,:K0¬Yw,jXj*]xϞ=qzz:yYn۶mX'kuLDajtemKGf4Xѐy\dh羗,hA!$A"W@=xcwyVu"?&2 Xi;\=nMrɃ3X /L l>著h}?'-dk0!ASunZJ@r?D,>#G:,bJ6 Y&k l֭돁tq(J-GekB>Ihh@tL$z\e [B D NGH $C:n/E0̄<O L劾q͎bna@cuD@&F!$aG_nf3hS ,A bd,( Ն#ǪB஻]eZiFwV.\Ȼ |f%,pkksR#%G[P]nh_5g{9c xƺ𤞁8 4CI>?AqAb AP3x7a6?SelH ?!+ 45z]Ӌ Kgrۋq%5/3B&PL,4:hT&$0!͚1 gřD zb`ـB"AW&r;ov5߃8THsP ܘ\͛g +Yb6~_x|Fgg'1}t=z[n  Kh+ 3⡭7,I " DA9i9H4Bh eѹ|DN]x=:pO"a&-^ߧR1  TnaN2Pkn*=^\UK@i1ifar&ed% K"$>˭?P%y'pWF>2@u^^\\̏>ZZZT_sNb8Àƒ۲atziW8/ UրZgp5aϛODDA), " &+i3(̂pY50赃.dwVmaB+(AÉt vꏵbZMP@f (Pg"~^XB]1$**w6J&z>\MB.HBmw,YwwU#% jhll X￟Xa`__l2떓÷~z*;j ) Ʈ ܮF1z5}0olE:]d82=|$D0AI'^L ZO~Ō5B\ؾy3/ڱ>hK>s –}bK/ 8ZKu]{~*g$Įr"VK&Wabrv &<;wtvPQ .^x8Ai V 欳B[[[Z,}ōUӗď1PrIwph_紫pzWg~pm &!dH+?jCV¶.TN+|ŋc٭p53*x CX0ǥ׆0ڎBfḸ8^|{~CvEPRzIj%RA2Eq\P75dQsAXb&ɉA6Vq$t\ {dc~AAJ'K-eNT[uہe)ȍL2d 4ǑO_~@ I YAZUb͸k}ߡ9_q kpZ>9;NHhr?[vXSuصgb`!`V(|<ܫXzIB` (GِB8k%%p+ZH,J F#;`}L1cM' TLM |-xP:ShA`v혗{& qQ?ON1!1 B^Tu/=/>(#92m&\y%nڄNޭf-Hj|?P0gvhpш.},$+} ݘ?.Y-%?a7D'  VCLc3VZ.!$aցkʬI."-Boo/ > ק~!_1؟H9qf?z 17'Z 7\-00n FA0A*}VWؤ|sWVWGcso>~#׿n6Z6-kVĶje A+r 7[>]1 tLd>&&w}Q}hHK"]h]6b 型kr~, ~^owaV|wfϞ*ϛ@2Xsf _XXܰa߶?8i5=\t6g[a䓂HKL}?@ b#A mJ16au}*CHAG>x~q'iTtpV cu-Yv4p+=QQz*nLYzFЏFO(l<38>TT%(H(\e Nb*[m\v9!0TV~_ALSʕ+gٜ\Ys9cdž,sN} >YbdܹlQ>#Ÿpw~wsfMIĿ1f[0A1r&P;`x쯯`qm7 +lx$ij|E(,+㝟mb!)W;r+GubB!e-0YyT_{- ,>cJ.>xa.*g ., wx˾_|ccw V챽*2C޽ |ጌ ~dۘ0Y2Q%%a A':kznEzB]D B $/ 8-i87J_G}YC࣏? Js~3xäJ'u11xE̙tOL`.]_PZVDDD -% Ѹm8dE@{?— " 鎿D"vzj+T1 \{YxᤱX8a}gż%}Gv?`G۶m]1gΜ!!_n:HA, ްe'~k֬Uf魔HDIlii- ܐ/>~6anql48A,}A#/]x[ TɈ_3A񈰀d }}}D~f*x瑴JCT ?WR*Rb286ਜ/4p9CjeNUVaѢEӟC+˰xYan,fΨ >U~+! fAgJ2&8:PpfVsZ{{dw"8!d@ I,$3, vr}{c su;_$"N,  ,?׎yM." !6 \vh3gbɼ "AA1f:Bo1bSau@mi.+AxV0P9nB{bN E/T WD" J"ojl*/`/+/S˟gvVB_f͚?>Yz\DmEg ;𫻮ŒyS' fL,qGQp{z w_p呒Lٻ830zH; 1A d.,H?xSh.)<ud^h^N k@bO4 *Pm}_ٺ~d8o| z|5Vjp-& F̘XG%\66UsjD|Km=fz"[7p֬^M= b dB +hwaF[T J t!$ H- r[ bb[Ώ ΂T Q"0 "4}cuXu}m0j Q=_R[YvM_cn^"}6qظq#L I?^~C EWx.uzp48 w"D@ֺò.?JqM&l콊 L>7t}AD7dK{}nǰ.{D|KM=*pQ\}[n}ɱ.2 Ո7_z/<7|| 4>\c^N#WAY!&:LH䊓Lr`4,}_1 ~>t1qaI}Q|gxꩧxḸaZ򳬬%#**L "lq it#7RF*D8t5`18d4ۋpzxϏ៦H|!77z+AiRdǎ3 E&d ⠒՟8R;}_-".i˱pB<3xEnkk+oƊ+# FS.fY}m+]HƎHa?,7G&r~f` zPG`!N ُH]|iiik N37VC <"4 ݳ$s' a ~H|¹c{dx:Ŀ{_~9~رc|h~`9sf9hs)AD(8bqSZ_|>.ވ'"oB }aѬDXb=?*P|G7AHF{ vNǏ~ AFBoo/ڰ bx\vhQA$,('B'q"䰘z"]dwSgM4$//oz-W?G bў#|x%TVV}#ܒsI76܁0{^%zJ ޑ :+ s3_Kh4 P`$ :\n$f+srӾ\菞}%FDD7@ Ƃxg:P­Sus uͭ[ "L04 ,m~KȎpY 8aL9~QQQvw䝏6={9xcO_ /ֻqm[/؏ aOrb#xaĻP[JB5 x^ǫ103s/LPŅhA5LV j,RQ_8A b>̬0!@ F{W ־,bڔd Q_قN4fiL|D*NBoxK?U3atVK4skKDŪ˯ ɸ&%^(oq 00  wt)뎖ܵ0}=ho䃵,8 tA &x,nGo^ɖNJE:ď:$ 7vh$& |kJAxnlƔX5S6a Fw>|ߍxLND}k/U43MUiÂ84u^~QsmG,[%a ωmǣ;0cXp2qbwⓃ[o}*+@ʎ'jQ>'RQ bb|3ɉ {'X*/DE"ԈG5} uvպ+Ց__F|1yOuk@|tbwyZ61C1ܾͤ(H⊴f,n8?{X+>k.]8ELj+.ƒṣNp446Hyrpi>-k366z5A@ ݊˰x/AP,< C%Ԅ` Q“TOSC`% FIQfDFFR"btjv;~Z1BG`׆rw4#~ )c^X q{671-y.Zc9Xv73.A1Z Ǹh9 _0V?\;Uu8p5'n3-K`M1A`}}} /M,YɹEB9Ad $zq+# _76釿6U߾JA -U곏SaEY#0vD' IDATdb"`h&Yʚ"7M ÿg1jj-{squD!bRQRr,_EgCWLDPjZmnsfj?.7(R&xl w;l# "?'@şh2*s7Ht( ߐo˟K@)-=(,ȇjR BAo1"*%;@gB6w9Fk@{ HikGKGnt7Nو|+ ] A&L3 ;yqp jO᦯^TdYݮ>l޶ Gv90 gFi(L8?Q} b܃KOzV Zėh'g$nlf?"=XMV{P{yd jޓUk|`'1 k_|}8rы=H(\X%,F=`4yAj,Y.Lv~-; O^݌EK$QdR }܀0;;ZV'xfƵW^H[ɪ@ÉwcϾ}p협x+.ZvdTx&AM⟉Z0(*VMZ?AX!._؃,劒R*jڻZgA~^? 1 ``"வ&p|\)VJ 0zHQK2ޫl5y&̋n }+r'͜M FI-ڸWwg Ytg%w.|.:%L (Y ס3,&G5R@@ d8xq9dL3_8YZ."zWP<'7ϕgc!@ U{>O ]v۸9nAY5-pulXWGyvGoΊA{\ͥӯ2"D1ŋ^o@dTڻqd#16Yp:]xeېK&֎k?Fee%ouh O=I`DA:kAHk` ^O|' jG{PW_C٦$Uӆ!fdE !!:AAR /<CFB$"-8pF=E;qMco 7v/[[i=hmj$! FIAyuZ:p+;߾ I Ú@VzXc.-EVJ.T|eFsz`>M1!^p JN^ Ͽ'JH{{:NP-ަ6Z!Wjڗ'=C_r )t?½A kK~[w@RLRcP܍^3/«Gc]0"qvL}pbףaܙi1jLr1Pǻfm5IOkXLFLM}</č_:Ԕ|mǔ8-:+p`Ib A76q2}Z$ =qbXS $Di[FUca'pMn\=~,aVWJ49:EOVAߓX]nE^'vkì࣎p:N{\ .mG. n3z{{qv@qt bb`[GlfŢՅۻzyh'qe #p%Xj%_oX8}J@EAZpAL\j9˹2*eVJ+p?Q+:O9+PXȽX9*n =_m5'=wd=RBj_\~h?5L&Q<,,T!PNl|p:݈4׉0w<4f]7ka*;ǟŬB;Gv9Yjzì7 =N> Aäy :ĆŢatu##% v]K;(>9ظy+7Q9CA߃% ۮiF bb)I,Fp=H H(e+')zϟ4Ak r.'`_) j\B\{+Tl.Z^DDD/dB8vjO63\F=JO#:. ݎ7hsn3Vü`m-xuHLHugxcbbgN@ĤcbA?o8sTܱ{Jʑau/hBcK'O08ۺ08'~jce LZb<.t⛀TCO*PJ'kM_?a"_wǯ"ˑ3kIy*.`BuXH;@qW#ʉ~JمC\UE鱘V\ qqq܍oAHi9 ^ˣ(9Z( /o[GƊ.1-{05̃e@qna8 F-}v~NOFMw},1JLꙇdc7գq1j(6z(pbl(J uZ;:GAL`̜vÖV4"DΕRD\O }!@T#d*S 3b .,SF̽[DD9g(Ww$ ^B-''}&Gف@_}ޗH]5܃]qj-y@ 1=%xaݦ 3!)ڊ-=K}ۑ9h Z`Yr  фv'\}m0y]:s0{lue&8Պe&c0d&:G~N:l>v ifPX:AeKĚrϊZIP0q2Ċ] C& D )vcӳ`J f7CbfZn e_16 4ޝRG5YmdV\DP*J{u~m[&xfk0Aè({w[1mLtIPq9Ntzu\@F3{Ǎ>XփTt6ն@o_SG 1br ht{0Zow %1`]8~VǪ֣(7 @^&",ta?葐O*EcUQP-h GE$jn7ZxT,&{ e$"a.RDAn&RNzߤbvA{:_ ir?7SN\> ҭ&)+e՞\$!j]X~r¡}ؗd둭8w,̙5Ż "AL,֭[|0-[%^|!=HJGGw/"&DqD9uIIA֍>\ ǴRrBgzW 1ؼZyh_:ιVh)s0A)<e`Jj墡dqs2`w8QMs QpLJl.TL쳻L(Cc0k]#{5| bRG7y)EMXeXX*\E8nƮ8FhL1ܢŒXX]L]y2j܄MzmI~b>4C}JI9|J_5ǖ?'.Jd1:\sx q`B?sۆ/ֿM>E,FM.t:QB|x:jѸEAoEߑY*v>~lסf ugېF'OZĩ`r [ɀCwcYK=yeQY] A$LL-Y^OpHypKn7D :iILáT_((?CAL,}c1l/p% pR_I:nl?^$$Qs+N U*J 6D"1 tuVVb8KBٗh;@mZ?*Ydո*}j+ _2@IWJ0tBi,¼hb~f@ֿH$E _LO{sҎ،BhpvG1&g,ׅ^s* Q_y/byz>yxYZޱ5K0 hl =^ ^YQX2=F '"DzdhF{AYqqޅp ܺ ubήU3+@n^QNRph[`5Cy9Afb Ν E/>IυsX s],J %Q_C%!1" $@qbjO௟NDػ}5H/TݑTr1 j b]E}YWmY}4N{ ~M[=#1Yr &?W_[ Ftbxؿ1".}{WoYdckGUeF9.[͝= }(tnF׉Cs7Q`0"nWv(ǹf~:|6͔< NclA}GvĀČzL0ftuˀΎv F5ya1 b@bF;`b-}¢;CKk;U"1>1',{d✻C{I&x5z Dj)0AĄ &bB K/ް'!*'J݃%uP+&JE+%!W@_ T '61 s-AzB4RP(7`_l (J5m~''֪qU D6y}؂JP.7#lk-Ys{Vo EE ̚5ppŅ砺?$Cݨ;v7.B d%!wXI"yTؔgWrs7}3Kݕk?y{0 $ ݏ%H8=;݀g/Ď qg#3-,kD{{LxǍ^\K n5T#ILi Ǚ8/8tUw ӯneNq]xkgXyLL-7'qs^ ' 5>GסvLF=cEnn`\wgrW&y0{vܾr9hDMmzEQP>g0G,>E9CiB/PZN萞&nDrŰ8Fx=(Ep sV/+ȄtWŸ{:PIe(X,IOe=(ޫXIrm#N 'w'JxTeӓɤHBUQvWbu-k[+(J@ ^&7L Dr>sܹeޛ~9Dh0") dFYsg{(E=dtB b"CGSkk6lO &]QIй 1a6u#P>~ovdf">4c- 0UQ|Qnke7!NQ sKgBYF@a/^?@Vw7 h> s3@Zk r0Ćb؝n$F!=1J<铃 G;.z:?>T)kSCqhO6RemB Ob"PS׀hT $Ⱦc. 0 Ü>ݼ =S9q@۳W  Ebo}6ذ,+N.tw"WaiAB\m[A<ݐqH>.'haosbp'_ӟr0aBgrTDuך`d=E;Q=&$pׁ|dZٹ8k#i4^!qHJJ-w?sXǸ|c_"rP>S`LR >~3KmB<7Lh70uuZWമ0u__oO< N.a]_0 Ü ¾6 Ê50#H#qH. Jesz $̕^;%}WI0Lq Qh߅D4疎 =Ll0"硋)g; st;s,ߤ#<H8P9荒wYǧ= F1vk~Px{z`o̓O4Ü*c(,L޸ҳQl[OKJJjr;Bg]sf*(X zh~>b0PSfj6" 0)0UDyaՇ쟌Hw0IE;PLtflk8+/{ ?Htڼ(i}0nlI+]u3*uؾADϾa83OfJtҳ,vQ.EGj- @]se򳏋`@a3f >zl4l4$Fƣ XPv J[ꐚ1X=| uy~3"P:~ *j[预Z#ڻfR.FLr`9#eD@w,=?7͸i}!B ::- FXBSUPYO U'Gj lW40) #a_WWFO> r!^֧O)`Z=6)'PcRFЩ@7d Ibt IDATosq(ٹ|x߹r;娏,<9 'n9 e6<_m%!X dƞIshl3OV à$؝'Ӂ_Ag; )_`utOlXjQǷǎWWMP#7Gz֫Kjۑ1T9EbB2`AmG?I-s |x+Z8ou>T/xXe삉DAfnݸ@}|=a40)W40).Ef͚?GP}q鯸m B/˝j!Gy~lu[yc6|ݎHz} E(;uuPvx.}=GBl9tUȚ$\n>M{Z_%&0&Ϙ>][&)˔/:w>[K+}eҤI#٪+0443{wuerG{:[e ўmcB(Bn50ww CIe{hqOF9bBT BQE b7U uq{o+iykS7nCրLT(Un[o: _ 0S#m@ōwŘK<!I_^>{1Q{8%_v(9*v~/Ǝ9]X:iPPEswtw=ˏh_f09 |H;ڶQFcN*j?.@t9gx}[M!{yqBY%v x-~=lقHQ0AΝ;@Ꭺ\ĆzMNSt> ޏThAAWU>0[17m ͊A"`uYX  =jMl7Px.cda1u=iYVΘ Oوb&L6X'$?m ƶ&TNS}hADL * W60i9(0661 _feCODAřΑc+淶}̩a3'^ˮֿ Dt6d.Bxd2DaNFZoF|"trq#P]_rg/zHyؤ̙$woϑu[o>b@xehnn4K8F%Ey] 31}z__ǺY,_dVApE5hm@C#Tzo}ťq%Ü~㌑ヂ7p+kP؊ǥb-10<}ki?Ў*(̝)h(7rzE(8 b1KW:0i^$rE@#w&Ç%wL,VHh:j9Q+#-5ef YJb,NĉH8rc'J3Ǟ3w\Ԗ.#Qx|[ wD??bs(afy9صc3ZouD W?;Sga!nԉcmW(jBbb"m{ݠGZ7X#LՎ۬Mqc8$aNWF|0p&U v\JSk`*Pn3:<]C9=&5ACA{r!?a) /՝xaS\y-PDO;&GMLY 8\g Cr J܀ mw} *6VaBzJ)S%xDu*)݂#b`rxs&ه3о|{ruw&H_ƒ0ވ~iAp0̉rCOyB}Bzzlܴ_rcGDB^_rL'x7{\! 6FBD Lݨmi1.):e7`S[\}CARIb$g tDֻu-0̢2vnoل][1aLLw3faN=?~{Uii| wOcL$ͰID~=΄THL?gU(t芵^S7ֿ9S3pշ ' _ya྇¿x%{\V"=! FU0`4$'X~ nB|B$'B-':5Jƴd0~T(Hk~ymM:qCh,yp_`sK+>l۰ ^)փOaNvִඛŽ?IBjD$kξ"r7%Mf*ll?qDC^u oBCFY\_@ADbC˜DWENfMѶE7i!H=Ph#k~`;rwY4 ywcڤ |M2 Kq7 o>x9v7b\53*Rϻd5S2mh&s= ̚@O-*Q܎f^xj=0#ݫpE?aƒRl7_+mPOj)NuCu*T͗_@D*,: D$M`Qa$7DVTTtuxmŇP/ya}aivMޞ9۟(Q=\tZTWW G[gc5<;u w ՕO F7v:^-B^ H`؟Vr+f21qp$h[Zuے@\X d$&>y5|JZok(ʥoRL0 "kV~-tz}@@MPqN~e2 !jT:xx1ʨ3о=G߻=q|I\pm쀹ڋUCjڛY3b50 s*AbP" 8gd|[hG'י;^p\9 w J fpbǎD{G=h)ApP b$:\pߔ䍴?g2 u s)p9nG:yخV)!SЂ-w<=*-:Yu],i-g\y=lG]]໭Ƹ!o;RԢ;Wi_AQ#mŹ0wXNAF&tq0֬Y={6g2 %ݍs9mpG( (ȋzH"\(qNj ϗDu-++oâfmj41 $Ƒ#QNN8n1}α}9ƒ 8{AY.>9wGv} ?m~yᲔܷ 0%TknՀ?X/*</7  64$aA v"ln3PI5\x-<3 b uvNJ72_VS1fS19u TT2l/ڻ QXGa#$9W+BBWRbPճL s/1Px}E8,v6,DQ(߾όQN]^M: a9eWd{Ѐm~āP:QPQ9K(>X 8Ä5[ ϠO!=1 *َI1U.:5v*ZuRFuݻM}@OOO`9E!%qοoc.X1>G!Z/yQؾWwZ}FDGE Q 1 N 7o۵a+c@Gq&?w$$_~eВ."\NIHg!aSooo<> `lW〈)FcK;N}~'$!!2r1.S=T@^ K[m+lb9UD q]w!/+oB~>z6)(MF}B"Dv$9T`˻G-,:T(\}{;g9 +0ZU܍2=Ā*˯I! 0 Ì$pWn;`sFDŽ"5!wd#."cÄX_Zsёi:)+-RqrnaS /x@ނ {ߤK \4'A}6{}(19emgYl9ؔѨGw/B=.SnR?Go0ys$J lSak[u!r6#mtnz{seI 0 ÌdF|OgLKGmc+.Yh–<̞n۲cFh|" 6{BR%8lttv^(MZn1 ÜNP;DΛ%g5+&ԧ!_F\f䂐4_^PBZׁ҂\83vP!i)B7}?i5dO>_7&u_>׼JΆ TmnxGET(<& & ;Uaxgwgෛ230!* * caFYu=LLZMN 4u}R֞ Lf7 d9@///_Ͽ_B= QUPJ"`G^AAA͡ ؕ~r@/&&FT.f\R[{.6N:B uȎ#DNAyAgC;kܹرcJJJ+旖EN"H(=j..t!)PEMA {M:(-!w: /uw>o;ڧ&BP gt3aaΈWk묝K .=k*vg:t.1NvupOv<1Pݧ"M*MaU+OΦRۉ#f1a洃DI q3f@BB^z?m~c N\-+-?i$w^!˃ %x@rꕕnAx&͇fܾ8B#݆r\pt-!)=b Ü*sq]{Lه]g3]h!sC*>nۖhۣ0=(qhO7 sN.TGKPFi۴n`)-OP39C Ü#^z7ȽBDpfOP|e8kBp~g}OnN R"m潹O QV`I\Իs00$J˗WB7=n6'0TQ־j\Աȑ#z-l)HµHhhifNkΙ_GJ¢6@0ֿbjpyֱ mc>4l]q 5O:tm{9XۿRRg~ǃ喛Y0[Wzןgmwgzxm > ;+wno~!.':= }h/pdՐpw]{tu_+m_odD4Z}U7=ɘ;)Bg 6`ɼ hhnG}SgX̶y@]w V-N d) aZ 0oComH $xҴl2<0TlB0)଀`C ..3 =(省Sfn8MTm IDATdMElxl[lڋQЪբTIGE@z։* \cg`]U$^voՄz7 a9koo'֯_ya  Uh|B!g 0B#$$VMՠ{w6׾\]?U`KI6ZKZ8Ho[B"+]+ 0"_|,t ˑ*XpUBܐmޓ ӶhYr!Tp` !Q0ǎ{k(UmzFaNePB_z|9^~{| ̙#ua~3ՍgVEɊ5{2j~^+fzd]l \j[G\s0 3:jUQh"̜9+W{0 AP ȑCy )TPZH!\HMMh1vX.E/ iV>tH,I6_m:p%U}!!Xv,u19i]I | Üʐʹ)",=PX\dg72 3 c>rs1eLwן1gBNΛvW?9˳9v}<1sbMq^KNm-qZ,JƽE0}]|aF@nQX%c"@~~>yYd%am]5ah0 3j$"wkQ8O>M6a93a9B M.}B܀DRR(RQ\\,\[nԩSEDwb#'Q+N\#aVr9+'\eڂ<ޞd/! wca Xu}VIX xtm~H~0"+Miп{h4Li#8hPsab\t%1sN\`ƤS-+;2%sZ&|v8'~V8TQuxڛ둡7Qx`=>,ajPaf!GJ!$`ժU(Ȯ>~:Dzݢ/W&A;Hu؉>m &L.3f`ee%&N(;t"##Dy9C:@ r8@DŽRJ-&eh*ޏRxyz 6&3.Ο$Jyef4k^|j똳{̜n̴}'o?莯XfYcQ՗\3S~x;daa|ﮄ˲`|g939,[믽^[ۯ OmDCxw޼cjBd 4T"t]͸%FsCCZo {sN\:] |aގ\$P8(O4I[|96{ > orag8tpm Bwy+}ݺu"ˆ%Q}!**J4,$N v쐞c UL05A`PҬnџc_3KeaF ?nE !gmKy^m]'6D^q߉GUJ~_|m&um핗mxEp4ʀo0$Lx쑇p931.%o9BZ ,6^vDwy{P[^umQ`u ϜԛݺAtS@sѐY/p8\aF$Q8G" |j wQ:bB}׈햖%${ H QH ޽{(6Bm۶M0c:R.'Qv%Aw[`io T̟97H+0 0 q߬`g;W_ߢ8}cO<-r Vu„^&Lyy;:~JED1 0:LbN_Yf!33~rl/IPzfVJ9 m-u~z$$$ёk <$R("AmI, XSS#>u!׎Bq#±q09 ~!HuC83M/·daaNNX 0̠!ãO5狉ޏ>ѥB_ :7xDhDxX I"B &&"1 Z,7A!*m &UH;bV ,$!RujaaN~X NMe<Ӡ7ĖqcR21ŌWtX^ftb袠^vUJ* aCb ;sERRrpvv66m5Ph] @㊬F||h HU&ABD &"tLfLRshh'HB C 2zaaUߐ>~,KN X21vӭ;a,ra$ #A܃T)ŋLm۷.*:|QqqBpEH)qƉܽ$k\xOJZVtD@t̆\JBH: 0 03ܫ )϶T B#!\Z}eq s>.* Wb[ ҂ws *M 0 sPBb1=(ۅӏ _ň000)H"##!BI6 P@rJȣc*E*Ǜ^/Gǖr%3 0 0,F[~M6W\Zth.NO%1^ׁH>1aQNl,&)Tj[eaaMFb rG޴iӰl2عs'x)Bǎ+u֡A8L/BӾF!m0R] OPVrRt# h[t|I!2 0 0,Etkw9H<yup7D@{W8鍱gc$݌[َ+,݅7*ySɷ T,2 0 mk_c<"m&B kkkEH ) |rIb _/~]y֞>"N 7;`w ]Hqui`ٷRWt|ra*zjxD *L$Q %&0**JZ555B YjK) -OnB)t.-w*@ߟPʍHX:>T⋃ faaNm(CVH8!/7sri(M&6dW"fX:T88DrŻAbXr=ؼ:SH4IU~hlBE]ȋd2AQ$@~}:bpջ"5mؗ؟F (> 0I UEI $󯮮k֬i%$$R1fLRÓ5  H}ݧzJ7aa95x@V]aфhi7 b{e梶Jx n>F̴F| *4NJ~4ιx? ))ITEC%(< hkGmY:0ѵ^Vn1af+\*sqEZL 'a9vr٘5k6o,$b!9xp! SbI#(x2U&$D0 yBaaF,O?W'f'V=E͘%(/>ζ(:0ޥ B h]0hu4.np 0 Ü2P?qqqذaM#aD3j0''&& q%rr$ k >P})J\ロE@aaʅ~j0eT to}Qi*8rPRs ӡ-ha Eu7'ضc2XG ,&rCcAWф&z\xxxb씹ШU(.$ ii61Ps;O>0 sA 1R)pX__[ BݧuFB"G$*[Sp!A(aafb YmgyI>P+FW<4p0TUUWzԹ9uzwxD`GV.&# ]:¨GBꅒb\upiMhBTbΜ9DB_xL"MFS]5j* }|&uqgh<\Qa99I0y'SnARQ]3+'' 1v;2 0 0,e㆟×`Jh XVmGt!krKBBBB'{zM{Ona.:t8t7UgVClbSy !(8":^npf,*L6 ,8FzR2"$< E r=(@a洀ڷ: &Mƍmw}||DN9G%0h.†%HQO:HmTKim ߥ\wy'-[Uaaq;!iTxViDL(jKB9 h0.Q!e@.&^.):-jlܴ &Lbbb-R4JD PAmCYm8ӺST(UԍF$pAXa9K/6o %C>JR]]-DCZB]P](gaN4 @}IT / faahe Cjb4p #;ǣG5RAlS!r ˀ$ 2$tz(QX^"=#.x饗QS[( ᫔aaNќjcǎB|#_dd >|p҃7 &wG-AZ8H} ZB($Q\}O>$j faab4ԵQP\@D`OA r0{\$0:jڭr!A =@ & i@9DGǢqm)W/ V|*ZDD0 0c6KU&AQ***B0B*FS1}n$w mg0KC}/"[,{W1faagxG& V RbBgGf+ swB k?00PNz0c PgK{r!6L|aQco :{ ,2NaaRyP0G7Ւ۶m&g )0&&&6^'QRR"&mH m H<ܵkl///!""B|rv/hٸqꫯ '#0 0 qa~}QQݰ@!ܴ ̛8k'~z[@ H@r@㏒;P{ ¸Q8cB<3<:mK0 0@/^!⑸F6H#W }r@HIuhY\ KaG OaQ܃Ѿ&T٘)`-cѢE}—aa?X tu©z?v; ahEHnj hkAAaE@ &1r|rG?ɕGT摨Gz<$| ?&=RHLnCZ" -KCyH7Zaaa&&eB`@ ~[zԘ@dكV BA:L Y@{zF`m8ea- ' a&(l .Bxh'Am}~~h3ޓ0++K&q?iIXyH!$?/r0 0 s"HbL4N5Zꊑv~L?3 ͭxF/XDEhPq\Ou5[ ˰;k ky_)\ 0 Ü8{DHwĉH¡@4CtO IDATۢ\< 0 0 0C0xH$O`nŌ (nX4!\2 +v}':r P@i0TtaPz`ՏlPb/>kaa"^x9 w۷oNjT!rw@n{ӦM0 0 "p!-1)n>0Z‚p`rJ&'GH*@3@ъP"PALZcg;Ι6|ijE|| a&(.0 HaǏ&RP~`(ԗJaTQ0E HKк?E!2aan0aN>sDDDknU yoǺݹ8cJ2xX(>10ⱱ`aa7T,J sµ6yV\'aa3<k׮!$Q ̛7OT#'/v3 0 04, Nǵ ]P"k[ w +jEp j򐟗#@  *El/'/ks2 0/c=& OR ApԩNB*PB!Ń),0 0 0 E?=v5  Aisr'Z:cqXtTƑ -HUܳc+ K&AV {CAD 0 +V$Qxg#55$:C1aa`1pО_.UhiiE|T0;k &oF.Lb  f½MäoW݉hcn3ba_tY^{(.FÔ˶LOOuD ^0 0 07~d݉?~یXx"TI#qh> 0 +rw܁l"rq7H <"j 0 0 3ܰ :fl߰ޔ7H7؁qxn:tL,0!qtHPpya.n8w{n1kxXLFFh el,>g ta;Sj5wu+"\\\D۾h"asOz vɓ`2 0 0|/Ϣ./>ʢ<x ;c޸h\h*ڱ|^th1jtߏ z.Jd 2. 3&؁6 ,n!aa~C(Uᅬ%\"҃;r >|aa_ Vc_@ue)xY[m9G~w..]0w_:U`f,G(,Xp!\5@{{1i1.0 ÜD̞=[L 0 0 s2bL@p8ظk|U샥8gm~/ua6QT^ x[oG 0 Ü\|/xb|@aa &1}"< q 렴߲_,"4q,.Z4K$$+Äyknb!aaNRH,..aad1^r9}n8t(i}o}^ ҂reWcaaaaO^@x內PSSGyݝ+Ƥ?0 0 0 0 sBpIDBDk~ kXdaaaav\y|aaaaa 0 0 0 0 3B`1aaaaaF,2 0 0 0 0@aaaa!0 0 0 0 0#aaaaf?g ύk̷Tנ`>?:̴sP%&砊(y~S{[To9'ѣ`x%(#‡mZeAg8?m3 0 0 0 0#N ֢eYǃ喛Y0[Wzןgmwgzxm >ff޹Ynm[ۡQ`܇OV w&\tWnJ!9?m3 0 0 0 0#N l9{)\t+LvYךup{3u2&zm9ݕdžoVCȃR)r!!M;v۾_;(fa~y֯_/&ԧ d+CdR8QVj_k_:ZU:.uTQPd( {3MX w'$! \׹Ns߹(". ,ަG2BQ#/88s<}yǽu DhS0(H2PnQ_VL$В}og%z<_HZ^\(:y 9ի6`}#{~UN~D?b̳Ç#h ?vptK}I+#fQEr^q ך8ي8cQMy (/ف9j_}j@20$wΙ] #@PC0) 8 DAD@ B0@ "a !AD@ B"/]v=%@03  @fh"a !j*{GmD0fal֭ۚ5klϞ=W_{:pa0'؄ ,**ƌc;w P߉bbbv[rs@XhM86ol۷o4Q!07nÇݻȑ#>O/φ%KؽKF׷C@3e:t]{ [t~CTd oNF Ba ^m۶YwޱZj-bUT"$%%\'mعsg¶mwA(@ xᄈrYɒ%}p*pT ?Znmz-[f|-[ֶo+\:t./Xn& y(81b <؊+f+V-?~͞=:wlW]u >"ExBg-%#Æ ޽{{ (83gWJRD?}_}M8~s U駶a+Qzb &L`ӧO.,a g}Y섀麛7o_ dw}s!L Allwy^  ^6JgP0p 0{?IlTp͚5,[cbbj*S ZT ػwU^.?60|Gʕ+g:L޽~8zEy0Msnj 8o<=1㙖hnȑ#}~6P0q@>Ybzv kV_|UF\su֍P(`B;vXѢEo7T+855պtAm۶@,B`fn…d5J-nLU o޼GYY@"  ZP eϞ=־}{_f_Z|@ ̙cEOmjW1U*x4KL28jFڵk *Xz ĉmVjUj5B ktB{07oc\CS{nuuJ'zj>WT񬋪Z6l?! 0-ZdC MEݻ{ߔ)S<TsիWߕT}Gtt~ȫ-S%ԨQ/j?tkA@Ӊ}^PC9Tہu݊U *7>#kڴu+)S ahP%@%#;v찊+iV 6 .R Jӧ Y(n|CH 9iu{zA}bb U)0B  PU U%a=)S0 :;t=}_:6h9ځ@2*0Tm۶IY[4kժ`(˪H֭ks0RJ^AtZ/;xҤIƵlkzPZP T|-TU* j(PT- U \@p* EɴB?u-\+Uu))ԒUQe8w䝊BAU17m~III~QPPZjVjU3>1u窊꾠PO踦*/<}+:Pk+W@UdU(Ԓ*!Z ^U-_ܗ(TO㒂o\EǧJPoI} }+҃Dځ@vZpKH}ɼ©SI{z\HU0SjVPIc7?,P_6m8yfԓ1*x"x"XoVzh8qzM6t|RcOV'-ut=thҤs\g0*W|\NJlF6ENε`D#)Q Bnc Te~z_^z:ZU۠A?*XSPjA@]}(r\g"yɸ*k]' f*rT' ,YF9jˏP@R߿QF=za)oڴtL84'pq|j֓(:ǿ@nP:IrBPêQp0+Ta0OPU9 ,*U :ז`:WZRD7_5lgOK.?cm-[㌪ lD:>u}m*@n"ƸqO-AaN*Q'>z]!EN_ o??XO6h1!E:0k,?6kίY'25/-Z3MHBB6!6a@DYn6e2Ojɹ+S]':i׉ZU՗ X_SSAVhܳgO2A:Iƍq1?z: QㄎǏ˦wG쳔$۸q#4!@@X;U̙' )(TlIUa+I=RE* D}MQr |鉂kEˈ5kf3f̰Yb| IDAT3ga;tqGa'e<6XjsqT>WNsذǶBkj=l@UD[!ɹs4GPU|jV^ ' t]^PP5kkXȠ'D ~<6m+DmTbIII~q m>mj{<ʖ6}:l#VadBa eG*sƌ =ԾOU ծjH0OPt]]01s=zd: # ܼysNǖ-ZLA='e'PNlnO Gam[͞PD艷NuQ;NMmjSЧ%# t=vJ:,z[RۇubߡC:TA῎M6UVV`;f긡PP/'MO:踣'#dMzBcZT&f_ݬKs@Ba b]OA`1XΝ'P-ª cS(%X?%v5kZF< *?j]/Rcڃu:^8'FȂ5j?ڜ^wfʞT>6gBa bթSǫvT`00--+eTգ:WL0OP`P%{ >@ѣ8j?=h"Tاc¼yl BAm'ד۷cɨQ|f '$>lk-韸xS^mެU, d.D"IyjռO' tЉ}oرzjݻX'z[}suM"\۷]tEءAْ%KAC4F jAU+Tq6m[?ڿi! pN72{6kBԠAmWWh?} d^'"Zcʸq:Pā2P t\@U ĄZ5U?kQyٯ.uʖ=o\mV<3!@$R^Νz6qv ׼?:1*R- uwA]a9y,-ɺ(lPxp%x`&M߯Ç۰aѮ];?Ţ'!tQ(̙cŗe a\ p:1~w-ဳ @rU\VeKyE2n=l[6ΚjV`>!Pix^|k X4f@U$m֏;j#\RyjC[\6a9 |fŋ`TTz6x*\@ W_\\ I{)O)^x87njM72+TfHv٠EmmJݛf{=)lUJY|֩YK{g;|0F}EzZfϞ +VxXE! ɇ1Kͳk>Q36C<yw EGGKIII> G^_Z.V*UU17A* =~bv{%6ywphg*d+Eo4^F?>~(PBPӦM`]t}\mZ")U9?k{[sUfen)a b)S9UBA]Զ` .r O6 >{pvш6~s<3kҾRiwvh:ģ: @:\xᅾlHzAt,>}/= S ?x%g?jm:XkpVu־ X`S@5O5K̘1gjpN5Iu|=Z^fcCov+xPrviVߴ1d˓Ɨf2{^8=e q@@ĸ}&`@ `oUk@ NuOF UX-êԠPXDqۘ?~2-&&ZZԷo_ر ~;67eCԋcJx{qu-u 霄bf bmy˖- ۷+uYt{~z)bŎMW(('l?QQvU)QVٟo?~ 6U!/_ڴicM6%‹/=kἫ6~uٍjW95k6cOc6yqI]TLUpvP8A[m^)P`j|gE uٴi_r*p!{M-+^$ }u-SQN #]8D?l͚5z!;ƌcQZeVϱw&4{k2U(o b-zc~QT"$]v~=sL6mWथɓm^aU(Nv<3iSt_ v]?f9w6}݆eKX(FShf-[6 wa>y*fC&/Z}{5ycۀP;//3rB>kbVJmorB\4P34K3vѣGې!C<8T(6ߔ\ϫ[dq+YJh]!ڦ]-a,BU#7n||՝SSS3<]X 5=iv~ g>4+34cQ-=;|c3Wek[ݺ<`0*a-uUm8vX)[laÆy˰* 2))scc0l=ߺpict6-6f.w(j ZV]]}b=<#ɢE5ܼyWꉇT!Jx-fכ5Y:f7&kvlw^`vKm#ֲe+Ta-X]5j԰>}ܹs}HP~z@2m@P`0kѢEdoYf<;mZUKXbRVNN;hm{)t s+666Ͽ^+:TI:uϮlrS @NAU_| ?~o ׮]k 6 dFCK?Gقf+ʰ@h f1~suכ8x.\.ϤL+0,TXѮj#"6lj>z\d1[gU{pvw261e?VԫW/W_GKCªfp*شfmڶ*UxxՀ 45[LdNof7oM4鸏eF)\ٖ5v;o؁N{U*>- *XN,>>dʔ)'m,$G #ٻ_vMF~\@*(( >s;ZnT4)i\ۀ _[-uG ={ZLLm۶;K}xv&(:O'UFjڍ7ԩ& B]@L>n:uo>OXfĖI5./DG'kx5N`РA'x`VT;a„L?*}3'l ~zuekcX^" mdrhZ6mdӦMΝ;e'e9r^n] ({̙3=[Emcǎ/kڴi|U$Oіu\}*! DEy@֠A |Χ0LOǔ.&}ϨZFEKrZsC3DSީS'VXᗄ{m .W_}:t`?W:)1J^A}T^^~e3%$Y! DÇ{ 7kB`ߙOXfh[&]Ğַ6 ?ؤ=и=6s_˚Y  #KժUB/]t5n.BkذW)T`~N -[f_~׿~%#5j')@ D 6m%%%+IKNwڕ1wG:ǞHa&آe[lԆ6k}Ž7 KG.E$Y*Xzڅ N8&M!A]~_>g+Vþӵa b'Aͺu%O`ΝՒ7|[{篷>u+ykky0" gi<Uŕ* H-a]bElI^ax}6pܹz-nO\O/OAjX)xǞ={@ DJ*eڒi&o&Ћ.gpʪUo&MXJJJoK\bvA2֪B)W*_ MI6|]W" 0&L`wq>"trwߵɓ'@{ZlVح[7oú~Bm֭VJ~1(^oh|2PU;7o?j׮Ù7tWPoʭ~?Y,I^ 8TO{ hgpY(I_~o~7x[i~ॗ^C P˕+Rژ5By֢E [f P"khD_Ozy6tw79JiiVxQ/edDaOUt礥Y}SoƋGLֽFE{k|i^[iG_~k-jK/?a๥?NV~ϴvܸq8)FZ cB=b:mqƾ=X=ߥ/c DpBoUqm  M۷oG7uk}I=a "d }ե2ex^ /v=RUzT"EItRAXnlX޺49~YO=hwϩMnP֦^x|0 r FGfS$-8KgϞH!_/ I:&VW-BA}Us)HTkZ ifQe]fs`# DaN2G= Tuz4?,Qe: NuR_U $_' 솁AUҥK|t)צYU)|ȶ*d_WT _}geuO?#vjΪ"=1N\:Ҙ1c¡80PzX9:1[z͝;ןh@UzjyٳX*Z.:eXqH!\BB9 s8ٻwo33?sp @@D^wu~0E.QōNЃD^E]!_0K'N/'a.ɽBbv:׌Z[գ]"ְDaK.fՋ}Y2Z)fWT*a7U-a[1oR*l|,m' [„0G2IuXU T6<2 Im XO6۷WXsT)MêW* ur9 mصcQxSgUƩ*ht_ꕉ & @lWTIw(DAJE!j BAiݺO8+ ΧP!愅B۫pB?6gի$٤_|ц !IVAN|;H\Ǐ;G?s 4Q9*@34`Ϟ=- ѱF{c*u\uHg  uTUcfر >!c>WTZ _og(D;V9f c 0P?>3, z] N|;PIj ;ϒ?i$U)*b"Ujƣ+TeB7+Pvc  p(gYJu^h闿 "B0PaB=p\3t{{ZE! Nufd$_60PAB ϤS|"kj>p-A_vQ~ * m/-rтe˖y5\XU&$$xW`($R#X@=~U@ Z' t,Kc@x" DaW'۪JA :_*LX]ve^٣tU(hQrJo6`qCA DڛRk;#}1NM믿X B}ٹN^]Tx{~;!Z$Mˈ40':nU: u f kJOQ1/@4@U'~}׿5ۧ0A]޽]}ޒfvi3uN3~)HQ :9oӦ_t(pvsmΝ^ѦJ@ jQTŏBK`q|6U|jcPajo6z N׮]ٓ e<'4SjMo߾4@sCUºhzymQ @# 'Ç zkBn@{ uQɓd\m~jS04zh T?#>kKTw)ZxW i&ZUCgØ1c/PBժUg Jv*4[Q By.~;gB5XbС?mРAF Frk񈞰мK]|-0a Zs'x`VիE5? .H د_*wС㕂zX)<@U#VV~fB@URVaB1U{{ 3)ψt{%s=~jFB`+W KN:Y=TK^fUq{BAT_CmyAA4PՍjWV6"g| *)y By.BmkҥKNsP 7q<=?رßPşډg-@1UUR%D-G/*N>O'A(jVE-*j E^I*.T)?+pj6[jN`EAaKLKpxң^xCg}h1h hVv`h 9:/.Dh x5?q]ґQFyڇPPstQfm3foU۠Gm:޽;Z6SէGk^ݺu5XDK̓SP0y}>]* V0UL"Z׿z0Pjl.UKF>r*D $8|CPPf, :S3kN@! A`_|/:<@U(3gT}6p@ 3V"Kۃ5'>a]<$3b oUNjŜnt , O=n Te[EUUjVe]AoJTN%%%y@ua9?# O_ {WZhq&''{hɽ{zPp׮]>R!oz WᛪsIUjCZky*k׮\@ @2=mm(>>/ Ÿ!Cxw!? XuNz[*:7o8 m8gua. a PKC=dK,zAmH9v %x˖-5X3Y{9TWA]-Q˰7Uۭ^֯_=gKPyja*U\@7@N#!!^xoEUf99iȑܹsgo aA(; RP|rU)DO Ծ\fM-ZF!@@6\z~y7mVl,+J}g>o￟;4i}uIMM^U ꢷՖ Na*T18o-\ƌcZU,gB7`j V(VzT @mڴW=v*Uz9ZߑMz"88C>SĉgiժUֽ{w۷o o(SN*T%a=n+LNN*AuZ"#O/*><]_PH-˗@]va yYn@ 6 o޼?Um|Z0'Q*tT觋*U} @cݺuX򟽑y;W[VlMֲWZe*58s{S}I^e}/[kt%ƃ@! a-0P(S)ܰa+  T"S@cIII֮];o9i_9[gq~? o^]𙽺tX!_vws&dn ]{G6x3 a-11:m V' TݧOjA(QՃj VȧpP**@2_s5"9o݋Nz- _%^M^gz>'w=t A~@XSo-Yf^է_)T| PP*׭[g[lVT)}`͚5=\kaÆ8cS{>ooHa k)W,V٘gz>r{fvYVWa/N\\oȍ%24z(#ruS}̤>h?cOnӝ 0D’:w&LEjղ:xHq fWSu*uYzW jHݺumժUV~}`E\H4L#17x0C lk׮UZUA -[!`@~Yo=Y\ ޙUmK̓@" amPPՂcǎJ?Q6k6  FQۆSR-A[0A [ 쵥,f*6+a=KC&lYdVjă@" aM[5oʔ)>[nw^5jmxl`DUA 66 '~{;GZԀk_+F^B_N}wvė'#s>;/a EGG 6 @mV(8w\onҤ/_͛7{H 0ӑ_ >6mٽ^v׮Bͻ< 9 4W{߼NU4-?muN}rs=zABry(8c VoRI&ypllPH @e Yش/zس? G/.^]::U:yfWvws׋$|"=XK?4#PAڵk-))7 }:j-Z e5rpz}ֽ߲_ՙ~~vws׋$߂J>Vd_Xس1N}zJs*Vf? &x[>KBA]TAxbKHHڵkɓӗ6aPDLߟz(9"7nlɶbŊJҥK-11?9˖-6ڢE UaبQ#۹spa_Ҷm[ h7|U6mԯyCA lo]W|E b+59dz8= k98}=bccȑ#ǵ@OyvB<`3fm޼ٗ߿?} ,AU .\|y۵k=^EةS' XDI˩ޟk_veVlY{%p|)6aTXB_&fT6g[p5k̯6a ڄ@D+RթSڴic+WNx69s&wa QZ ҠAkݺ+W.a @ ܸqc+YdC5 D ?ٳg͞=ۊ/UqqqKFBf mdPLf>/ ٟe߾}<8a @QQQVhQׯ_B]СC<8a @۶mMmV; 42*& dDZkweAi'@ ;+Xf wa @&` իW6(_,KQ \(\b@0..j֬yF6K"Ec6x;n]:tȒlʔ)qF;rHNJJmٲ;a0ׯ_z핁[xM:նnݚ3bĈTpz haC}ժU0e˖~Qϟooe˖k+W&L Dt ,Vر;!0T{7]v֦MkժUz(8m4oVuYP' 7nU׬YOb@VFecǎ=zx ضm[`0TЧPbŊ *U*khiHm߾}0 *?ܾ;ٳUCAU kuԱŋ0[TTU^ *d|7κuU۷4ܼyoZ/)Qw&a K+VJ?{&Md^x]v=}X3 *Lܰajb a w{*Eڵk^zVn]۳g[6qDܹXa3 j* *0 m;OZ2{lX||/ٶmkv_^y'O>֬Yceʔϗ… sG dfLNNpOۃU)`III?ZBn>Uo{7z9eʔ RլYӃs9srիmʕ(0ݻ{ץKBRPKB cccm'{!w?'" aEޑ#G޳cE]tܢۇ`DBuFVP!c'ذaÐʩ^%)y@XQ pѢE}y0ac N(D֭*ڵk>|W *U*$~]vYZ엿 _x~)0w/ZuA arKA&-"j ([Nƙ,N 9kmY:A@h^P0hB{p8v.y}o<d׿J@X^T=cɕ~o}[sHV [6 i>t8D(X#`OMS;G#nKzV ^裏NA?oC͕ Fco~<|xΜ9'.m޼9 80{y2v|''|r:ujZjU:_"]@׈F!=\ڹsg1bDQI`tP0*/>{wW^y|;vjraeT?p iРA.:$ z/HIDAToΡ^4 ῥۯ~($:GU]t[~r5k֤'mܹsO=Tݻٳgg}6hPΑ[ڶm[~Cfcna'OMoUd駟N/b0oΕuQ 6ѕ8-wqsG0c]qq[[Ll/tg3C.t ;a p{Gs`T\2wP0BТpÆ KCnpT ?MH֮]~r]F?8.j1c8T& CJo Á4nܸAF!E-._ǜѥ7*JcƋa!ܳgO 9L8 #Ƴ:+mٲ%zi9Z3u".t'HAGuߑGG%`~qs(w0#4pyq^0p99sfޗW^y%]s5餓NrBa +cǎv1HIo|0Rh$r ' R(a|> 3u^a` ?'Q M6nܘ6}4z.ty/}K/~Çs m۶m9W_}5mذ!566ٳgu cTZgyfnCr /իWevؑ<ӱzT>;pt ~СCbyЙTwK.M~{|ChB2z<[n]A]t/%01#'Е@{iԩ+_JZfMn6<0\dIXwN/pXO\rI8  ':_qi7ʹbŊŷ:+iL[bhʕ+s /0w}iĉyCN@>_ҦM;dȐ]8FUa3oٲ%]wuyAn@n){[oM[nsVgiÀ qT6N;-ߢ{I/r۷oy#D3f~8M<9r)(=0OcXꪫի꫹ qIK/iӦ1_jUUKddc7o^ڸqczgp'yceɢE @' hGt^xqZvmSccc̙ƌ@pXaQ8bĈԿÊ0Q)78qP@(a 0 B! @A P^zө{z8M/>zQںtoIC|˵>Hdᗶ}]1Gى&@v}!];yݕ>y™ӯ; jWrmٿ.}?3tL]wmZW,jb0PxcLh5=.~iq icSnA_wz [(j&  ?xUmZ}=ϧ#e01G JOzV[vۓe07b1mWzk5-޶ڲ{җNDP3a @;=ִ\6tz j& h7ڷ7|q5-Wh6r<_BЎCӍ4?ӻ4ִ\V?pd7է^X*C==-ygi+gzòiU-ז]kҝH{ws$jhhw* P@(a 0 B! @A P@(a 0 B! @A P@(a 0 B! @A P@(a 0 B! @A P@(a 0 B! @A P@(a 0 B! @A P@(a 0 B! @A P@(a 0 B! @A P@(a 0 B! @A P@(a 0 B! @A P@(a Dz jhh ޽{t]w]v &ŋÇ@f̘L\裏@p͚57oN۷oOƍK 8x}֭&  ,X O81VXM6-1#G}@ "[v!?3iȐ!MϿ/7ַҜ9sދKA~4iҤN>NTOO?ʕ+^sI3glz-5kA/~# 0  4(Z*}NOGuTn|t'6-ÄرcXv߾}q4L@Q ްaC}琰R<lz۷o0‰{^"s=70`@'P(#HzG|餓NJ=XkYg-ZٲeK5jTpl~lٲ!!6b"|e5ۍW^8* 4xCdɒtmDZL%9,tOtyvly<[;Z[ι֭K'OΕ/N]tQ߿{Ɂ\t-uܻwoך/X&#,y|Ϗ7nܘ&Nx6,FEbGA`a`?; :w:T#BhC=ƌs2L_~y|{{PWKٳg &2 \W]uUSEaT#qt)ʱr!a`|RXUmUWE^5O`ϔ[5Tnx~NTJgǺcSIR9oJ*N9ǤJA稒E{\{{=,lkQuRuVz7xcڹsgя~j;P|?|UWRG󀕪:@+z:ڗrPo> j'F%Ǧ]JSa<܊i]J^ T::mʽVnTxVa\O4 a^ziEԩSsᒨ,J&MʍCb.\ b?JCWvjٙ.gb3Ն1-߯$h`C5|j{ߵ󻖻L52ݝMga=u\)ċ1bDwFx^"\ncNFW4w4K:{?zA?}P$7oޜ?7uTXIXPIrUȣPpJ4*ZNug5դ>\j5QлDE`gQ]wW ּp4 9_p5HEa`[aL6(wmR-$dWXQm+r_*ӰcܕUi՜v}jYWa߽뽣?'\tRg|;.:vs}@0{7 2!¡amM_gZqU&U2^Gۨ{k9sۮWs=jU%繜sTuSke-uVkK.Ut&LHwnw٘cpڴi=fKC׭[o N84o] =u{]to|iܹiذaKG>d 638#ر-[QF[?>/~1-Xi:={v~jժC߰wҥMΒ'I"0pe˖UsC?%Qy~(_%}m nSO#l[|y2eJ*\2uԊ%Pl$tJ_μy<|ӕW^̙yQxinEwGR* N5{8w/7n\~oڴ)W ><7i;o7rȴ}Շ|$B]crT/VJ@X"x9 \n۶b.%lMڵ̙3 P1`t 꺎4oS=;"TP-ʍC"[n]nҖb0`*tmI&9! ԧ>nᆦ3f(s ؝b^ӧOz=@hEg҂ }_*4l9 WK@wק;.-\0?_lYCSotv8n?>-]4א!C^0B CǍ.LR(Yf#GvE@D7ޢjxv%^r|ѿ IENDB`xl2tpd-1.3.16/doc/l2tp.svg000066400000000000000000013056351374460464600152210ustar00rootroot00000000000000 INTERNET 192.168.100.1 192.168.100.2 192.168.100.2 192.168.100.1 Openswan with Xl2tpd10.0.1.1 192.168.100.1 10.0.1.4 10.0.1.2 10.0.1.310.0.1.1010.0.1.1110.0.1.1210.0.1.1310.0.1.14 xl2tpd-1.3.16/doc/l2tpd-RPM.README000066400000000000000000000045411374460464600161460ustar00rootroot00000000000000 l2tpd RPM """"""""" This l2tpd RPM was originally created by Lenny Cartier and Per Øyvind Karlsen . Some details have been changed by me (see specfile changelog). Originally it only built on recent versions of Mandrake but it should now work on Red Hat, SuSE and older Mandrake versions as well. You may need to edit the specfile for non-Red Hat systems and set a flag for your distribution of choice. I don't know for what purpose Mandrakesoft included the l2tpd RPM in Mandrake Cooker (Oct 21 2002), but my objective was to use it in combination with FreeS/WAN so that Windows IPsec clients can connect to it. The original RPM by Mandrakesoft starts l2tpd at install and runs it at startup. This has been changed for this RPM to be on the safe side. The l2tpd sample config file is copied to the default l2tpd.conf but all contents are commented out. L2tpd will still start on all interfaces, though. This could be a security risk, so I decided to not start l2tpd at install. It is also not added to the startup configuration. You will have to edit the config file and start l2tpd explicitly. This RPM does not contain firewall rules. There is simply too much variation (iptables, ipchains, Lokkit, homegrown rules etc.) to make any assumptions about the particular firewall in place. The example configuration files included in this RPM reflect the following setup: ========= Internet --------- LAN +-------------------+ +------------------+ +---------------+ | Win9x + MSL2TP or | ipsec0 | Linux FreeS/WAN | | some internal | | SSH, SoftRemote |=========| l2tpd, pppd |----------| server | | or Win2000/XP | eth0 | | eth1 | | +-------------------+ +------------------+ +---------------+ 234.234.234.234 eth0=ipsec0= eth1=192.168.1.98 192.168.1.2 123.123.123.123 ppp0=192.168.1.99 internal network: 192.168.1.x (from which 192.168.1.128-192.168.1.254 are reserved for Road Warriors) More information about this RPM package can be found at: http://www.jacco2.dds.nl/networking/freeswan-l2tp.html This page contains the latest versions, source RPMs, etc. Thank you to everybody who has provided feedback! Jacco de Leeuw xl2tpd-1.3.16/doc/l2tpd.conf.sample000066400000000000000000000100771374460464600167630ustar00rootroot00000000000000; ; Sample l2tpd configuration file ; ; This example file should give you some idea of how the options for l2tpd ; should work. The best place to look for a list of all options is in ; the source code itself, until I have the time to write better documentation :) ; Specifically, the file "file.c" contains a list of commands at the end. ; ; You most definitely don't have to spell out everything as it is done here ; ; [global] ; Global parameters: ; port = 1701 ; * Bind to port 1701 ; auth file = /etc/l2tpd/l2tp-secrets ; * Where our challenge secrets are ; access control = yes ; * Refuse connections without IP match ; rand source = dev ; Source for entropy for random ; ; numbers, options are: ; ; dev - reads of /dev/urandom ; ; sys - uses rand() ; ; egd - reads from egd socket ; ; egd is not yet implemented ; ; [lns default] ; Our fallthrough LNS definition ; exclusive = no ; * Only permit one tunnel per host ; ip range = 192.168.0.1-192.168.0.20 ; * Allocate from this IP range ; no ip range = 192.168.0.3-192.168.0.9 ; * Except these hosts ; ip range = 192.168.0.5 ; * But this one is okay ; ip range = lac1-lac2 ; * And anything from lac1 to lac2's IP ; lac = 192.168.1.4 - 192.168.1.8 ; * These can connect as LAC's ; no lac = untrusted.marko.net ; * This guy can't connect ; hidden bit = no ; * Use hidden AVP's? ; local ip = 192.168.1.2 ; * Our local IP to use ; local ip range = 192.168.200.0-192.168.200.20 ; Alternatively, use a range for local addressing ; length bit = yes ; * Use length bit in payload? ; require chap = yes ; * Require CHAP auth. by peer ; refuse pap = yes ; * Refuse PAP authentication ; refuse chap = no ; * Refuse CHAP authentication ; refuse authentication = no ; * Refuse authentication altogether ; require authentication = yes ; * Require peer to authenticate ; unix authentication = no ; * Use /etc/passwd for auth. ; name = myhostname ; * Report this as our hostname ; ppp debug = no ; * Turn on PPP debugging ; pppoptfile = /etc/ppp/options.l2tpd.lns ; * ppp options file ; call rws = 10 ; * RWS for call (-1 is valid) ; tunnel rws = 4 ; * RWS for tunnel (must be > 0) ; flow bit = yes ; * Include sequence numbers ; challenge = yes ; * Challenge authenticate peer ; ; rx bps = 10000000 ; Receive tunnel speed ; tx bps = 10000000 ; Transmit tunnel speed ; bps = 100000 ; Define both receive and transmit speed in one option ; [lac marko] ; Example VPN LAC definition ; lns = lns.marko.net ; * Who is our LNS? ; lns = lns2.marko.net ; * A backup LNS (not yet used) ; redial = yes ; * Redial if disconnected? ; redial timeout = 15 ; * Wait n seconds between redials ; max redials = 5 ; * Give up after n consecutive failures ; hidden bit = yes ; * User hidden AVP's? ; local ip = 192.168.1.1 ; * Force peer to use this IP for us ; remote ip = 192.168.1.2 ; * Force peer to use this as their IP ; length bit = no ; * Use length bit in payload? ; require pap = no ; * Require PAP auth. by peer ; require chap = yes ; * Require CHAP auth. by peer ; refuse pap = yes ; * Refuse PAP authentication ; refuse chap = no ; * Refuse CHAP authentication ; refuse authentication = no ; * Refuse authentication altogether ; require authentication = yes ; * Require peer to authenticate ; name = marko ; * Report this as our hostname ; ppp debug = no ; * Turn on PPP debugging ; pppoptfile = /etc/ppp/options.l2tpd.marko ; * ppp options file for this lac ; call rws = 10 ; * RWS for call (-1 is valid) ; tunnel rws = 4 ; * RWS for tunnel (must be > 0) ; flow bit = yes ; * Include sequence numbers ; challenge = yes ; * Challenge authenticate peer ; ; [lac cisco] ; Another quick LAC ; lns = cisco.marko.net ; * Required, but can take from default ; require authentication = yes xl2tpd-1.3.16/doc/origREADME000066400000000000000000000116501374460464600153460ustar00rootroot00000000000000l2tpd version 0.60 ================== Copyright (C)1998 Adtran, Inc. Mark Spencer Introduction: ------------- l2tpd is an implementation of the layer two tunneling protocol. It works in userspace completely (although kernel work is planned after the userspace version is stablized). l2tpd works by opening a pseudo-tty for communicating with pppd. Although l2tpd was written for Linux, the current version should be highly portable to other UNIX's supported by pppd. Legal: ------ l2tpd is free software, distributed under the GNU General Public License (GPL) and you should read the LICENSE File if you are not already familiar with the GPL before using the product. If you distribute l2tpd, a modified version, or a derivative product, you MUST not remove Adtran's name from the product nor modify the terms of the copyright. Adtran may license l2tpd under other terms in addition to the GPL. This way, companies who wish to use l2tpd for embedded systems or commercial applications and find the GPL too restrictive can license the technology from Adtran under more favorable terms. Bugs, Patches, and Code Contribution: ------------------------------------- Please send bug reports and patches to either the l2tp mailng list (l2tpd@marko.net) or myself (markster@marko.net). In order to contribute code, either with patches, or by direct access to the CVS tree for l2tpd, send me e-mail (markster@marko.net). The word "FIXME" is a place holder for code that needs to be in place, or checks that need to be done, but haven't been coded yet. Feel free to fix the fixme's and submit patches! Adtran requires that you not restrict the licensing of any patches or code contributions to the main l2tpd project (beyond the terms that are already there). This is to maintain our ability to distribute l2tpd as described above. It does not in any way affect your ability to use code that you have written. Of course, the above patch rules apply only to the "official" l2tpd product as distributed by Adtran. If you are unwilling to give Adtran the right to re-license your patches under other terms than GPL, you may create your own third party product which is distributed only under GPL. Release Notes ------------- Version 0.60 should be considered ALPHA. It does NOT completely implement the l2tp draft specification. Work on the high-speed kernel implementation has already begun, but a relase date is not available. The primary use of this ALPHA level code is to test the ability of l2tpd to talk with other LAC and LNS implementations. I hope that everyone who tests the software will send me results on how it worked or failed to work for them. (theoretically) implemented features ------------------------------------ * Proper payload and control packet handling * Reliable control packet delivery * Ability to recover from payload errors * Ability to handle packets with/without length set * Ability to handle flow control or no flow control * Most critical AVP's for normal operation * Challenge authentication * Hidden AVP's * Hello's to detect outages * Handles sync and async packets * Can act as LNS * Can be a source of a virtual LAC call * Reads configuration file * Automated LAC dialup via config file, including redial * Can be configured while running via a file system pipe * Access Control * Statistics report when sent a SIGUSR1 * ACCM Major unimplemented specification features ------------------------------------------ * Rate Adaptive Timeouts * Out of order packet handling * Initial/Final LCP states * Q.931 Result Codes * Tie Breakers * Minimum/Maximum BPS * Call Errors Important non-specification related features to be added -------------------------------------------------------- * More configuration options if needed * Kernel support for *much* improved performance Usage notes on /var/run/l2tp-control ------------------------------------ There aren't any command line options to l2tpd yet. Upon running l2tpd, a pipe is created in /var/run/l2tp-control. Simple commands can then be echoed to this pipe to control l2tp on the fly. The commands are: t - create a tunnel to c or - originate an l2tp call on the tunnel identified locally by , or dial the entry h - hang up a call with the local identifier d or - disconnect the tunnel locally identified by or a lac entry For example, to establish a tunnel to marko.net, one might do: echo "t marko.net" >/var/run/l2tp-control l2tpd must be running for this to work. Various other notes ------------------- The PPP options are hard coded in l2tp.h until a file format is decided upon. Sending a SIGUSR1 to l2tpd will cause it to dump its status. Mailing List ------------ If you would like to contribute to discussions of the architecture of l2tpd, file formats, etc, I encourage you to join the l2tpd mailing list by sending the word "subscribe" in the body of a message to "l2tpd-request@marko.net" xl2tpd-1.3.16/doc/xl2tpd-control.8000066400000000000000000000065201374460464600165710ustar00rootroot00000000000000.TH xl2tpd-control 8 "Sep 2020" .SH NAME xl2tpd\-control \- xl2tpd control utility. .SH DESCRIPTION xl2tpd is an implementation of the Layer 2 Tunneling Protocol (RFC 2661). L2TP allows to tunnel PPP over UDP. Some ISPs use L2TP to tunnel user sessions from dial-in servers (modem banks, ADSL DSLAMs) to back-end PPP servers. Another important application is Virtual Private Networks where the IPsec protocol is used to secure the L2TP connection (L2TP/IPsec, RFC 3193). xl2tpd works by opening a pseudo-tty for communicating with pppd. It runs completely in userspace but supports kernel mode L2TP. xl2tpd supports IPsec SA Reference tracking to enable overlapping internak NAT'ed IP's by different clients (eg all clients connecting from their linksys internal IP 192.168.1.101) as well as multiple clients behind the same NAT router. .SH SYNOPSIS .HP \fBxl2tpd-control\fR [\fI-c\fR PATH] \fI\fR \fI\fR [\fIOPTIONS\fR] .SH OPTIONS .TP .B -c This option specifies xl2tpd control file. .TP .B -d This option enables debugging mode. .SH COMMANDS .TP .B add-lac Adds new or modify existing LAC (L2TP Access Concentrator) configuration. Configuration should be specified as a command options in = pairs format. See available options in xl2tpd.conf(5). .TP .B connect-lac Establish new connection to LAC. Username and secret for tunnel can be passed as a command options. .TP .B disconnect-lac Disconnects tunnel. .TP .B remove-lac Removes existing LAC configuration. xl2tpd disconnects the tunnel before removing. .TP .B add-lns Adds new or modify existing LNS (L2TP Network Server) configuration. .TP .B remove-lns Removes existing LNS configuration. .TP .B status-lns Check the status of LNS. .TP .B available Check availability. .SH BUGS Please use the github project page https://github.com/xelerance/xl2tpd to send bugreports, issues and any other feedback. .SH SEE ALSO xl2tpd.conf(5), xl2tpd(8), pppd(8) .SH COPYLEFT This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 (see the file LICENSE); if not, see https://www.gnu.org/licenses/, or contact Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. .SH CONTRIBUTORS Alexander Dorokhov .br Alexander Naumov .SH AUTHORS Forked from l2tpd by Xelerance: https://github.com/xelerance/xl2tpd Michael Richardson .br Paul Wouters .br Samir Hussain Previous development was hosted at sourceforge (http://www.sourceforge.net/projects/l2tpd) by: .P Scott Balmos .br David Stipp .br Jeff McAdams Based off of l2tpd version 0.61. Many thanks to Jacco de Leeuw for maintaining l2tpd. .br Copyright (C)1998 Adtran, Inc. .br Mark Spencer xl2tpd-1.3.16/doc/xl2tpd.8000066400000000000000000000065071374460464600151200ustar00rootroot00000000000000.TH xl2tpd 8 "Sep 2020" .SH NAME xl2tpd \- Layer 2 Tunnelling Protocol Daemon. .SH DESCRIPTION xl2tpd is an implementation of the Layer 2 Tunneling Protocol (RFC 2661). L2TP allows to tunnel PPP over UDP. Some ISPs use L2TP to tunnel user sessions from dial-in servers (modem banks, ADSL DSLAMs) to back-end PPP servers. Another important application is Virtual Private Networks (VPN) where the IPsec protocol is used to secure the L2TP connection (L2TP/IPsec, RFC 3193). xl2tpd works by opening a pseudo-tty for communicating with pppd. It runs completely in userspace but supports kernel mode L2TP. xl2tpd supports IPsec SA Reference tracking to enable overlapping internak NAT'ed IP's by different clients (eg all clients connecting from their linksys internal IP 192.168.1.101) as well as multiple clients behind the same NAT router. This implementation is based on L2TPd 0.61 from http://www.marko.net/l2tp and patches collected by Jacco de Leeuw at http://www.jacco2.dds.nl/networking/openswan-l2tp.html. .SH OPTIONS .TP .B -D This option prevents xl2tpd from detaching from the terminal and daemonizing. .TP .B -l This option tells xl2tpd to use syslog for logging even when \fB\-D\fR was specified. .TP .B -c Set an alternate config file. Fallback configuration file is /etc/l2tpd/l2tpd.conf. .TP .B -s Tells xl2tpd to use an alternate "secrets" file. .TP .B -p Set an alternate pid file. Default is /var/run/xl2tpd/xl2tpd.pid. .TP .B -C Set an alternate control file. .SH FILES .IP /etc/xl2tpd/xl2tpd.conf Configuration file of xl2tpd, used by default. .IP /etc/xl2tpd/l2tp-secrets Secrets file, used by default. .IP /var/run/xl2tpd/l2tp\-control Control file, used by default. .SH BUGS Please use the github project page https://github.com/xelerance/xl2tpd to send bugreports, issues and any other feedback. .SH SEE ALSO xl2tpd.conf(5), xl2tpd-control(8), pppd(8) .SH COPYLEFT This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 (see the file LICENSE); if not, see https://www.gnu.org/licenses/, or contact Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. .SH CONTRIBUTORS Alexander Dorokhov .br Alexander Naumov .SH AUTHORS Forked from l2tpd by Xelerance: https://github.com/xelerance/xl2tpd Michael Richardson .br Paul Wouters .br Samir Hussain Previous development was hosted at sourceforge (http://www.sourceforge.net/projects/l2tpd) by: .P Scott Balmos .br David Stipp .br Jeff McAdams Based off of l2tpd version 0.61. Many thanks to Jacco de Leeuw for maintaining l2tpd. .br Copyright (C)1998 Adtran, Inc. .br Mark Spencer xl2tpd-1.3.16/doc/xl2tpd.conf.5000066400000000000000000000211131374460464600160270ustar00rootroot00000000000000.TH xl2tpd.conf 5 "Sep 2020" .SH NAME xl2tpd.conf \- L2TPD configuration file .SH DESCRIPTION The xl2tpd.conf file contains configuration information for xl2tpd, the free implementation of l2tp protocol. The configuration file is composed of sections and parameters. Each section has a given name which will be used when using the configuration FIFO (normally /var/run/xl2tpd/l2tp\-control). See xl2tpd.8 for more details. The specific given name .B default will specify parameters applicable for all the following sections. .SH GLOBAL SECTION .TP .B auth file Specify where to find the authentication file used to authenticate l2tp tunnels. The default is /etc/xl2tpd/l2tp\-secrets. .TP .B ipsec saref Use IPsec Security Association tracking. When this is enabled, packets received by xl2tpd should have to extra fields (refme and refhim) which allows tracking of multiple clients using the same internal NATed IP address, and allows tracking of multiple clients behind the same NAT router. This needs to be supported by the kernel. Currently, this only works with Openswan KLIPS in "mast" mode. (see http://www.openswan.org/) Set this to yes and the system will provide proper SAref values in the recvmsg() calls. Values can be 'yes' or 'no'. The default is 'no'. .TP .B saref refinfo When using IPsec Security Association trackinng, a new setsockopt is used. Since this is not (yet?) an official Linux kernel option, we got bumped. Openswan upto 2.6.35 for linux kernels up to 2.6.35 used a saref num of 22. Linux 3.6.36+ uses 22 for IP_NODEFRAG. We moved our IP_IPSEC_REFINFO to 30. If not set, the default is to use 30. For older SAref patched kernels, use 22. .TP .B listen-addr The IP address of the interface on which the daemon listens. By default, it listens on INADDR_ANY (0.0.0.0), meaning it listens on all interfaces. .TP .B port Specify which UDP port xl2tpd should use. The default is 1701. .TP .B access control If set to 'yes', the xl2tpd process will only accept connections from peers addresses specified in the following sections. The default is 'no'. .TP .B debug avp Set this to 'yes' to enable syslog output of L2TP AVP debugging information. .TP .B debug network Set this to 'yes' to enable syslog output of network debugging information. .TP .B debug packet Set this to 'yes' to enable printing of L2TP packet debugging information. Note: Output goes to STDOUT, so use this only in conjunction with the .B -D command line option. .TP .B debug state Set this to 'yes' to enable syslog output of FSM debugging information. .TP .B debug tunnel Set this to 'yes' to enable syslog output of tunnel debugging information. .TP .B max retries Specify how many retries before a tunnel is closed. If there is no tunnel, then stop re-transmitting. The default is 5. .SH LNS SECTION .TP .B exclusive If set to 'yes', only one control tunnel will be allowed to be built between 2 peers. .TP .B (no) ip range Specify the range of IP addresses the LNS will assign to the connecting LAC PPP tunnels. Multiple ranges can be defined. Using the 'no' statement disallows the use of that particular range. Ranges are defined using the format IP \- IP (example: 1.1.1.1 \- 1.1.1.10). Note that either at least one .B ip range option must be given, or you must set .B assign ip to no. .TP .B assign ip Set this to 'no' if xl2tpd should not assign IP addresses out of the pool defined with the .B ip range option. This can be useful if you have some other means to assign IP addresses, e. g. a pppd that supports RADIUS AAA. .TP .B (no) lac Specify the IP addresses of LAC's which are allowed to connect to xl2tpd acting as a LNS. The format is the same as the .B ip range option. .TP .B hidden bit If set to 'yes', xl2tpd will use the AVP hiding feature of L2TP. To get more information about hidden AVP's and AVP in general, refer to rfc2661 (add URL?) .TP .B local ip Use the following IP as xl2tpd's own IP address. .TP .B local ip range Specify the range of addresses the LNS will assign as the local address to connecting LAC PPP tunnels. This option is mutually exclusive with the .B local ip option and is useful in cases where it is desirable to have a unique IP address for each tunnel. Specify the range value exactly like the .B ip range option. Note that the .B assign ip option has no effect on this option. .TP .B length bit If set to 'yes', the length bit present in the l2tp packet payload will be used. .TP .B (refuse | require) chap Will require or refuse the remote peer to get authenticated via CHAP for the ppp authentication. .TP .B (refuse | require) pap Will require or refuse the remote peer to get authenticated via PAP for the ppp authentication. .TP .B (refuse | require) authentication Will require or refuse the remote peer to authenticate itself. .TP .B unix authentication If set to 'yes', /etc/passwd will be used for remote peer ppp authentication. .TP .B hostname Will report this as the xl2tpd hostname in negotiation. .TP .B ppp debug This will enable the debug for pppd. .TP .B pass peer Pass the peer's IP address to pppd as ipparam. Enabled by default. .TP .B pppoptfile Specify the path for a file which contains pppd configuration parameters to be used. .TP .B call rws This option is deprecated and no longer functions. It used to be used to define the flow control window size for individual L2TP calls or sessions. The L2TP standard (RFC2661) no longer defines flow control or window sizes on calls or sessions. .TP .B tunnel rws This defines the window size of the control channel. The window size is defined as the number of outstanding unacknowledged packets, not as a number of bytes. .TP .B flow bits If set to 'yes', sequence numbers will be included in the communication. The feature to use sequence numbers in sessions is currently broken and does not function. .TP .B challenge If set to 'yes', use challenge authentication to authenticate peer. .TP .B rx bps If set, the receive bandwidth maximum will be set to this value .TP .B tx bps If set, the transmit bandwidth maximum will be set to this value .SH "LAC SECTION" The following are LAC specific configuration flags. Most of those described in the LNS section may be used in a LAC context, where it makes common sense (essentially l2tp protocols tuning flags and authentication / ppp related ones). .TP .B lns Set the dns name or ip address of the LNS to connect to. .TP .B autodial If set to 'yes', xl2tpd will automatically dial the LAC during startup. .TP .B redial If set to 'yes', xl2tpd will attempt to redial if the call get disconnected. Note that, if enabled, xl2tpd will keep passwords in memory: a potential security risk. .TP .B redial timeout Wait X seconds before redial. The redial option must be set to yes to use this option. Defaults to 30 seconds. .TP .B max redials Will give up redial tries after X attempts. .SH FILES .IP /etc/xl2tpd/xl2tpd.conf Configuration file of xl2tpd, used by default. .IP /etc/xl2tpd/l2tp-secrets Secrets file, used by default. .IP /var/run/xl2tpd/l2tp\-control Control file, used by default. .SH BUGS Please use the github project page https://github.com/xelerance/xl2tpd to send bugreports, issues and any other feedback .SH SEE ALSO xl2tpd(8), xl2tpd-control(8), pppd(8) .SH COPYLEFT This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 (see the file LICENSE); if not, see https://www.gnu.org/licenses/, or contact Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. .SH CONTRIBUTORS Alexander Dorokhov .br Alexander Naumov .SH AUTHORS Forked from l2tpd by Xelerance: https://github.com/xelerance/xl2tpd Michael Richardson .br Paul Wouters .br Samir Hussain Previous development was hosted at sourceforge (http://www.sourceforge.net/projects/l2tpd) by: .P Scott Balmos .br David Stipp .br Jeff McAdams Based off of l2tpd version 0.61. Many thanks to Jacco de Leeuw for maintaining l2tpd. .br Copyright (C)1998 Adtran, Inc. .br Mark Spencer xl2tpd-1.3.16/examples/000077500000000000000000000000001374460464600146535ustar00rootroot00000000000000xl2tpd-1.3.16/examples/README000066400000000000000000000002121374460464600155260ustar00rootroot00000000000000These are example files for use with xl2tpd. Openswan carries config examples for use with l2tp-over-ipsec. See http://www.openswan.org/ xl2tpd-1.3.16/examples/chapsecrets.sample000066400000000000000000000005041374460464600203610ustar00rootroot00000000000000# Secrets for authentication on server using CHAP # client server secret IP addresses jacco * "mysecret" 192.168.1.128/25 # Dynamic IP sam * "rumpelstiltskin" 192.168.1.5 # Static IP # # Secrets for authentication on client using CHAP # client server secret IP addresses * jacco "mysecret" * sam "rumpelstiltskin" xl2tpd-1.3.16/examples/ppp-options.xl2tpd000066400000000000000000000003321374460464600203000ustar00rootroot00000000000000ipcp-accept-local ipcp-accept-remote ms-dns 192.168.1.1 ms-dns 192.168.1.3 ms-wins 192.168.1.2 ms-wins 192.168.1.4 noccp auth crtscts idle 1800 mtu 1410 mru 1410 nodefaultroute debug lock proxyarp connect-delay 5000 xl2tpd-1.3.16/examples/xl2tpd-L2TP-CERT-orgWIN2KXP.conf000066400000000000000000000011141374460464600220160ustar00rootroot00000000000000conn L2TP-CERT-orgWIN2KXP # # Configuration for one user with the non-updated Windows 2000/XP. # # # Use a certificate. Disable Perfect Forward Secrecy. # authby=rsasig pfs=no # left=123.123.123.123 leftrsasigkey=%cert leftcert=/etc/ipsec.d/ssl/localCERT.pem # # Required for original (non-updated) Windows 2000/XP clients. leftprotoport=17/0 # # The remote user. # right=%any rightrsasigkey=%cert rightcert=/etc/ipsec.d/ssl/userCERT.pem rightprotoport=17/1701 # # Change 'ignore' to 'add' to enable the configuration for this user. # auto=ignore keyingtries=3 xl2tpd-1.3.16/examples/xl2tpd-L2TP-CERT.conf000066400000000000000000000020721374460464600202120ustar00rootroot00000000000000# /etc/ipsec.conf version 2 config setup nat_traversal=yes # example assumes we using 192.168.1.0/24 ourselves virtual_private=%v4:10.0.0.0/8,%v4:192.168.0.0/16,%v4:172.16.0.0/12,%v4:!192.168.1.0/24. # Only the mast stack of Openswan supports SAref tracking protostack=mast #protostack=netkey conn L2TP-CERT # # Configuration for one user with any type of IPsec/L2TP client # including the updated Windows 2000/XP (MS KB Q818043), but # excluding the non-updated Windows 2000/XP. # # # Use a certificate. Disable Perfect Forward Secrecy. # authby=rsasig pfs=no # left=123.123.123.123 leftrsasigkey=%cert leftcert=/etc/ipsec.d/ssl/localCERT.pem # leftprotoport=17/1701 # # The remote user. # right=%any rightrsasigkey=%cert rightcert=/etc/ipsec.d/ssl/userCERT.pem rightsubnet=vhost:%priv,%no rightprotoport=17/%any # # Change 'ignore' to 'add' to enable the configuration for this user. # auto=ignore keyingtries=3 # Only the mast stack with Openswan supports SAref tracking with # overlapping IP address support overlapip=yes sareftrack=yes xl2tpd-1.3.16/examples/xl2tpd-L2TP-PSK-orgWIN2KXP.conf000066400000000000000000000007331374460464600217240ustar00rootroot00000000000000conn L2TP-PSK-orgWIN2KXP # # Configuration for one user with the non-updated Windows 2000/XP. # # # Use a Preshared Key. Disable Perfect Forward Secrecy. # authby=secret pfs=no # left=123.123.123.123 # # Required for original (non-updated) Windows 2000/XP clients. leftprotoport=17/0 # # The remote user. # right=234.234.234.234 rightprotoport=17/1701 # # Change 'ignore' to 'add' to enable the configuration for this user. # auto=ignore keyingtries=3 xl2tpd-1.3.16/examples/xl2tpd-L2TP-PSK.conf000066400000000000000000000016601374460464600201140ustar00rootroot00000000000000# /etc/ipsec.conf version 2 nat_traversal=yes # example assumes we using 192.168.1.0/24 ourselves virtual_private=%v4:10.0.0.0/8,%v4:192.168.0.0/16,%v4:172.16.0.0/12,%v4:!192.168.1.0/24. # Only the mast stack of Openswan supports SAref tracking protostack=mast #protostack=netkey conn L2TP-PSK # # Configuration for one user with any type of IPsec/L2TP client # including the updated Windows 2000/XP (MS KB Q818043), but # excluding the non-updated Windows 2000/XP. # # # Use a Preshared Key. Disable Perfect Forward Secrecy. # authby=secret pfs=no # left=123.123.123.123 # leftprotoport=17/1701 # # The remote user. # right=%any rightprotoport=17/%any rightsubnet=vhost:%priv,%no # # Change 'ignore' to 'add' to enable the configuration for this user. # auto=ignore keyingtries=3 # Only the mast stack with Openswan supports SAref tracking with # overlapping IP address support overlapip=yes sareftrack=yes xl2tpd-1.3.16/examples/xl2tpd.conf000066400000000000000000000025701374460464600167430ustar00rootroot00000000000000; ; This is a minimal sample xl2tpd configuration file for use ; with L2TP over IPsec. ; ; The idea is to provide an L2TP daemon to which remote Windows L2TP/IPsec ; clients connect. In this example, the internal (protected) network ; is 192.168.1.0/24. A special IP range within this network is reserved ; for the remote clients: 192.168.1.128/25 ; (i.e. 192.168.1.128 ... 192.168.1.254) ; ; The listen-addr parameter can be used if you want to bind the L2TP daemon ; to a specific IP address instead of to all interfaces. For instance, ; you could bind it to the interface of the internal LAN (e.g. 192.168.1.98 ; in the example below). Yet another IP address (local ip, e.g. 192.168.1.99) ; will be used by xl2tpd as its address on pppX interfaces. [global] ; listen-addr = 192.168.1.98 ; ; requires openswan-2.5.18 or higher - Also does not yet work in combination ; with kernel mode l2tp as present in linux 2.6.23+ ; ipsec saref = yes ; Use refinfo of 22 if using an SAref kernel patch based on openswan 2.6.35 or ; when using any of the SAref kernel patches for kernels up to 2.6.35. ; saref refinfo = 30 ; ; force userspace = yes ; ; debug tunnel = yes [lns default] ip range = 192.168.1.128-192.168.1.254 local ip = 192.168.1.99 require chap = yes refuse pap = yes require authentication = yes name = LinuxVPNserver ppp debug = yes pppoptfile = /etc/ppp/options.xl2tpd length bit = yes xl2tpd-1.3.16/file.c000066400000000000000000001254711374460464600141320ustar00rootroot00000000000000/* * Layer Two Tunnelling Protocol Daemon * Copyright (C) 1998 Adtran, Inc. * Copyright (C) 2002 Jeff McAdams * * Mark Spencer * * This software is distributed under the terms * of the GPL, which you should have received * along with this source. * * File format handling * */ #include #include #include #include #include #include #include #include #include #include "l2tp.h" struct lns *lnslist; struct lac *laclist; struct lns *deflns; struct lac *deflac; struct global gconfig; char filerr[STRLEN]; int parse_config (FILE *); struct keyword words[]; int init_config () { FILE *f; int returnedValue; gconfig.port = UDP_LISTEN_PORT; gconfig.sarefnum = IP_IPSEC_REFINFO; /* default use the latest we know */ gconfig.ipsecsaref = 0; /* default off - requires patched KLIPS kernel module */ gconfig.forceuserspace = 0; /* default off - allow kernel decap of data packets */ gconfig.listenaddr = htonl(INADDR_ANY); /* Default is to bind (listen) to all interfaces */ gconfig.debug_avp = 0; gconfig.debug_network = 0; gconfig.packet_dump = 0; gconfig.debug_tunnel = 0; gconfig.debug_state = 0; gconfig.max_retries = DEFAULT_MAX_RETRIES; gconfig.cap_backoff = 0; lnslist = NULL; laclist = NULL; deflac = (struct lac *) calloc (1, sizeof (struct lac)); f = fopen (gconfig.configfile, "r"); if (!f) { f = fopen (gconfig.altconfigfile, "r"); if (f) { l2tp_log (LOG_WARNING, "%s: Using old style config files %s and %s\n", __FUNCTION__, gconfig.altconfigfile, gconfig.altauthfile); strncpy (gconfig.authfile, gconfig.altauthfile, sizeof (gconfig.authfile)); } else { l2tp_log (LOG_CRIT, "%s: Unable to open config file %s or %s\n", __FUNCTION__, gconfig.configfile, gconfig.altconfigfile); return -1; } } returnedValue = parse_config (f); fclose (f); return (returnedValue); } struct lns *new_lns () { struct lns *tmp; tmp = (struct lns *) calloc (1, sizeof (struct lns)); if (!tmp) { l2tp_log (LOG_CRIT, "%s: Unable to allocate memory for new LNS\n", __FUNCTION__); return NULL; } tmp->next = NULL; tmp->exclusive = 0; tmp->localaddr = 0; tmp->tun_rws = DEFAULT_RWS_SIZE; tmp->call_rws = DEFAULT_RWS_SIZE; tmp->rxspeed = DEFAULT_RX_BPS; tmp->txspeed = DEFAULT_TX_BPS; tmp->hbit = 0; tmp->lbit = 0; tmp->authpeer = 0; tmp->authself = -1; tmp->authname[0] = 0; tmp->peername[0] = 0; tmp->hostname[0] = 0; tmp->entname[0] = 0; tmp->range = NULL; tmp->localrange = NULL; tmp->assign_ip = 1; /* default to 'yes' */ tmp->lacs = NULL; tmp->passwdauth = 0; tmp->pap_require = 0; tmp->pap_refuse = 0; tmp->chap_require = 0; tmp->chap_refuse = 0; tmp->idle = 0; tmp->pridns = 0; tmp->secdns = 0; tmp->priwins = 0; tmp->secwins = 0; tmp->proxyarp = 0; tmp->proxyauth = 0; tmp->challenge = 0; tmp->debug = 0; tmp->pass_peer = 0; tmp->pppoptfile[0] = 0; tmp->t = NULL; return tmp; } struct lac *new_lac () { struct lac *tmp; tmp = (struct lac *) calloc (1, sizeof (struct lac)); if (!tmp) { l2tp_log (LOG_CRIT, "%s: Unable to allocate memory for lac entry!\n", __FUNCTION__); return NULL; } tmp->next = NULL; tmp->rsched = NULL; tmp->localaddr = 0; tmp->remoteaddr = 0; tmp->lns = 0; tmp->tun_rws = DEFAULT_RWS_SIZE; tmp->call_rws = DEFAULT_RWS_SIZE; tmp->hbit = 0; tmp->lbit = 0; tmp->authpeer = 0; tmp->authself = -1; tmp->authname[0] = 0; tmp->peername[0] = 0; tmp->hostname[0] = 0; tmp->entname[0] = 0; tmp->pap_require = 0; tmp->pap_refuse = 0; tmp->chap_require = 0; tmp->chap_refuse = 0; tmp->t = NULL; tmp->redial = 0; tmp->rtries = 0; tmp->rmax = 0; tmp->challenge = 0; tmp->autodial = 0; tmp->rtimeout = 30; tmp->active = 0; tmp->debug = 0; tmp->pass_peer = 0; tmp->pppoptfile[0] = 0; tmp->defaultroute = 0; return tmp; } int yesno (char *value) { if (!strcasecmp (value, "yes") || !strcasecmp (value, "y") || !strcasecmp (value, "true")) return 1; else if (!strcasecmp (value, "no") || !strcasecmp (value, "n") || !strcasecmp (value, "false")) return 0; else return -1; } int set_boolean (char *word, char *value, int *ptr) { int val; #ifdef DEBUG_FILE l2tp_log (LOG_DEBUG, "set_%s: %s flag to '%s'\n", word, word, value); #endif /* ; */ if ((val = yesno (value)) < 0) { snprintf (filerr, sizeof (filerr), "%s must be 'yes' or 'no'\n", word); return -1; } *ptr = val; return 0; } int set_int (char *word, char *value, int *ptr) { int val; #ifdef DEBUG_FILE l2tp_log (LOG_DEBUG, "set_%s: %s flag to '%s'\n", word, word, value); #endif /* ; */ if ((val = atoi (value)) < 0) { snprintf (filerr, sizeof (filerr), "%s must be a number\n", word); return -1; } *ptr = val; return 0; } int set_string (char *word, char *value, char *ptr, int len) { UNUSED(word); #ifdef DEBUG_FILE l2tp_log (LOG_DEBUG, "set_%s: %s flag to '%s'\n", word, word, value); #endif /* ; */ strncpy (ptr, value, len); return 0; } int set_port (char *word, char *value, int context, void *item) { switch (context & ~CONTEXT_DEFAULT) { case CONTEXT_GLOBAL: #ifdef DEBUG_FILE l2tp_log (LOG_DEBUG, "set_maxretries: Setting global max retries to %s\n", value); #endif set_int (word, value, &(((struct global *) item)->port)); break; default: snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n", word); return -1; } return 0; } int set_rtimeout (char *word, char *value, int context, void *item) { if (atoi (value) < 1) { snprintf (filerr, sizeof (filerr), "rtimeout value must be at least 1\n"); return -1; } switch (context & ~CONTEXT_DEFAULT) { case CONTEXT_LAC: #ifdef DEBUG_FILE l2tp_log (LOG_DEBUG, "set_rtimeout: Setting redial timeout to %s\n", value); #endif set_int (word, value, &(((struct lac *) item)->rtimeout)); break; default: snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n", word); return -1; } return 0; } int set_rws (char *word, char *value, int context, void *item) { if (atoi (value) < -1) { snprintf (filerr, sizeof (filerr), "receive window size must be at least -1\n"); return -1; } switch (context & ~CONTEXT_DEFAULT) { case CONTEXT_LAC: if (word[0] == 'c') set_int (word, value, &(((struct lac *) item)->call_rws)); if (word[0] == 't') { set_int (word, value, &(((struct lac *) item)->tun_rws)); if (((struct lac *) item)->tun_rws < 1) { snprintf (filerr, sizeof (filerr), "receive window size for tunnels must be at least 1\n"); return -1; } } break; case CONTEXT_LNS: if (word[0] == 'c') set_int (word, value, &(((struct lns *) item)->call_rws)); if (word[0] == 't') { set_int (word, value, &(((struct lns *) item)->tun_rws)); if (((struct lns *) item)->tun_rws < 1) { snprintf (filerr, sizeof (filerr), "receive window size for tunnels must be at least 1\n"); return -1; } } break; default: snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n", word); return -1; } return 0; } int set_speed (char *word, char *value, int context, void *item) { if (atoi (value) < 1 ) { snprintf (filerr, sizeof (filerr), "bps must be greater than zero\n"); return -1; } switch (context & ~CONTEXT_DEFAULT) { case CONTEXT_LAC: if (word[0] == 't') set_int (word, value, &(((struct lac *) item)->txspeed)); else if (word[0] == 'r') set_int (word, value, &(((struct lac *) item)->rxspeed)); else { set_int (word, value, &(((struct lac *) item)->rxspeed)); set_int (word, value, &(((struct lac *) item)->txspeed)); } break; case CONTEXT_LNS: if (word[0] == 't') set_int (word, value, &(((struct lns *) item)->txspeed)); else if (word[0] == 'r') set_int (word, value, &(((struct lns *) item)->rxspeed)); else { set_int (word, value, &(((struct lns *) item)->rxspeed)); set_int (word, value, &(((struct lns *) item)->txspeed)); } break; default: snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n", word); return -1; } return 0; } int set_maxretries (char *word, char *value, int context, void *item) { switch (context & ~CONTEXT_DEFAULT) { case CONTEXT_GLOBAL: #ifdef DEBUG_FILE l2tp_log (LOG_DEBUG, "set_port: Setting global max retries to %s\n", value); #endif set_int (word, value, &(((struct global *) item)->max_retries)); break; default: snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n", word); return -1; } return 0; } int set_capbackoff (char *word, char *value, int context, void *item) { switch (context & ~CONTEXT_DEFAULT) { case CONTEXT_GLOBAL: #ifdef DEBUG_FILE l2tp_log (LOG_DEBUG, "set_capbackoff: Setting global cap backoff to %s\n", value); #endif set_int (word, value, &(((struct global *) item)->cap_backoff)); break; default: snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n", word); return -1; } return 0; } int set_rmax (char *word, char *value, int context, void *item) { if (atoi (value) < 1) { snprintf (filerr, sizeof (filerr), "rmax value must be at least 1\n"); return -1; } switch (context & ~CONTEXT_DEFAULT) { case CONTEXT_LAC: #ifdef DEBUG_FILE l2tp_log (LOG_DEBUG, "set_rmax: Setting max redials to %s\n", value); #endif set_int (word, value, &(((struct lac *) item)->rmax)); break; default: snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n", word); return -1; } return 0; } int set_authfile (char *word, char *value, int context, void *item) { if (!strlen (value)) { snprintf (filerr, sizeof (filerr), "no filename specified for authentication\n"); return -1; } switch (context & ~CONTEXT_DEFAULT) { case CONTEXT_GLOBAL: #ifdef DEBUG_FILE l2tp_log (LOG_DEBUG, "set_authfile: Setting global auth file to '%s'\n", value); #endif /* ; */ strncpy (((struct global *) item)->authfile, value, sizeof (((struct global *)item)->authfile)); break; default: snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n", word); return -1; } return 0; } int set_autodial (char *word, char *value, int context, void *item) { switch (context & ~CONTEXT_DEFAULT) { case CONTEXT_LAC: if (set_boolean (word, value, &(((struct lac *) item)->autodial))) return -1; break; default: snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n", word); return -1; } return 0; } int set_flow (char *word, char *value, int context, void *item) { int v = -1; set_boolean (word, value, &v); if (v < 0) return -1; switch (context & ~CONTEXT_DEFAULT) { case CONTEXT_LAC: if (v) { if (((struct lac *) item)->call_rws < 0) ((struct lac *) item)->call_rws = 0; } else { ((struct lac *) item)->call_rws = -1; } break; case CONTEXT_LNS: if (v) { if (((struct lns *) item)->call_rws < 0) ((struct lns *) item)->call_rws = 0; } else { ((struct lns *) item)->call_rws = -1; } break; default: snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n", word); return -1; } return 0; } int set_defaultroute (char *word, char *value, int context, void *item) { switch (context & ~CONTEXT_DEFAULT) { case CONTEXT_LAC: if (set_boolean (word, value, &(((struct lac *) item)->defaultroute))) return -1; break; default: snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n", word); return -1; } return 0; } int set_authname (char *word, char *value, int context, void *item) { struct lac *l = (struct lac *) item; struct lns *n = (struct lns *) item; switch (context & ~CONTEXT_DEFAULT) { case CONTEXT_LNS: if (set_string (word, value, n->authname, sizeof (n->authname))) return -1; break; case CONTEXT_LAC: if (set_string (word, value, l->authname, sizeof (l->authname))) return -1; break; default: snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n", word); return -1; } return 0; } int set_hostname (char *word, char *value, int context, void *item) { struct lac *l = (struct lac *) item; struct lns *n = (struct lns *) item; switch (context & ~CONTEXT_DEFAULT) { case CONTEXT_LNS: if (set_string (word, value, n->hostname, sizeof (n->hostname))) return -1; break; case CONTEXT_LAC: if (set_string (word, value, l->hostname, sizeof (l->hostname))) return -1; break; default: snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n", word); return -1; } return 0; } int set_passwdauth (char *word, char *value, int context, void *item) { switch (context & ~CONTEXT_DEFAULT) { case CONTEXT_LNS: if (set_boolean (word, value, &(((struct lns *) item)->passwdauth))) return -1; break; default: snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n", word); return -1; } return 0; } int set_hbit (char *word, char *value, int context, void *item) { switch (context & ~CONTEXT_DEFAULT) { case CONTEXT_LAC: if (set_boolean (word, value, &(((struct lac *) item)->hbit))) return -1; break; case CONTEXT_LNS: if (set_boolean (word, value, &(((struct lns *) item)->hbit))) return -1; break; default: snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n", word); return -1; } return 0; } int set_challenge (char *word, char *value, int context, void *item) { switch (context & ~CONTEXT_DEFAULT) { case CONTEXT_LAC: if (set_boolean (word, value, &(((struct lac *) item)->challenge))) return -1; break; case CONTEXT_LNS: if (set_boolean (word, value, &(((struct lns *) item)->challenge))) return -1; break; default: snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n", word); return -1; } return 0; } int set_lbit (char *word, char *value, int context, void *item) { switch (context & ~CONTEXT_DEFAULT) { case CONTEXT_LAC: if (set_boolean (word, value, &(((struct lac *) item)->lbit))) return -1; break; case CONTEXT_LNS: if (set_boolean (word, value, &(((struct lns *) item)->lbit))) return -1; break; default: snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n", word); return -1; } return 0; } int set_debug (char *word, char *value, int context, void *item) { switch (context & ~CONTEXT_DEFAULT) { case CONTEXT_LAC: if (set_boolean (word, value, &(((struct lac *) item)->debug))) return -1; break; case CONTEXT_LNS: if (set_boolean (word, value, &(((struct lns *) item)->debug))) return -1; break; default: snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n", word); return -1; } return 0; } int set_pass_peer (char *word, char *value, int context, void *item) { switch (context & ~CONTEXT_DEFAULT) { case CONTEXT_LAC: if (set_boolean (word, value, &(((struct lac *) item)->pass_peer))) return -1; break; case CONTEXT_LNS: if (set_boolean (word, value, &(((struct lns *) item)->pass_peer))) return -1; break; default: snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n", word); return -1; } return 0; } int set_pppoptfile (char *word, char *value, int context, void *item) { struct lac *l = (struct lac *) item; struct lns *n = (struct lns *) item; switch (context & ~CONTEXT_DEFAULT) { case CONTEXT_LNS: if (set_string (word, value, n->pppoptfile, sizeof (n->pppoptfile))) return -1; break; case CONTEXT_LAC: if (set_string (word, value, l->pppoptfile, sizeof (l->pppoptfile))) return -1; break; default: snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n", word); return -1; } return 0; } int set_papchap (char *word, char *value, int context, void *item) { int result; char *c; struct lac *l = (struct lac *) item; struct lns *n = (struct lns *) item; if (set_boolean (word, value, &result)) return -1; c = strchr (word, ' '); c++; switch (context & ~CONTEXT_DEFAULT) { case CONTEXT_LAC: if (c[0] == 'p') /* PAP */ if (word[2] == 'f') l->pap_refuse = result; else l->pap_require = result; else if (c[0] == 'a') /* Authentication */ if (word[2] == 'f') l->authself = !result; else l->authpeer = result; else /* CHAP */ if (word[2] == 'f') l->chap_refuse = result; else l->chap_require = result; break; case CONTEXT_LNS: if (c[0] == 'p') /* PAP */ if (word[2] == 'f') n->pap_refuse = result; else n->pap_require = result; else if (c[0] == 'a') /* Authentication */ if (word[2] == 'f') n->authself = !result; else n->authpeer = result; else /* CHAP */ if (word[2] == 'f') n->chap_refuse = result; else n->chap_require = result; break; default: snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n", word); return -1; } return 0; } int set_redial (char *word, char *value, int context, void *item) { switch (context & ~CONTEXT_DEFAULT) { case CONTEXT_LAC: if (set_boolean (word, value, &(((struct lac *) item)->redial))) return -1; break; default: snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n", word); return -1; } return 0; } int set_accesscontrol (char *word, char *value, int context, void *item) { switch (context & ~CONTEXT_DEFAULT) { case CONTEXT_GLOBAL: if (set_boolean (word, value, &(((struct global *) item)->accesscontrol))) return -1; break; default: snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n", word); return -1; } return 0; } int set_userspace (char *word, char *value, int context, void *item) { switch (context & ~CONTEXT_DEFAULT) { case CONTEXT_GLOBAL: if (set_boolean (word, value, &(((struct global *) item)->forceuserspace))) return -1; break; default: snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n", word); return -1; } return 0; } int set_debugavp (char *word, char *value, int context, void *item) { switch (context & ~CONTEXT_DEFAULT) { case CONTEXT_GLOBAL: if (set_boolean (word, value, &(((struct global *) item)->debug_avp))) return -1; break; default: snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n", word); return -1; } return 0; } int set_debugnetwork (char *word, char *value, int context, void *item) { switch (context & ~CONTEXT_DEFAULT) { case CONTEXT_GLOBAL: if (set_boolean (word, value, &(((struct global *) item)->debug_network))) return -1; break; default: snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n", word); return -1; } return 0; } int set_debugpacket (char *word, char *value, int context, void *item) { switch (context & ~CONTEXT_DEFAULT) { case CONTEXT_GLOBAL: if (set_boolean (word, value, &(((struct global *) item)->packet_dump))) return -1; break; default: snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n", word); return -1; } return 0; } int set_debugtunnel (char *word, char *value, int context, void *item) { switch (context & ~CONTEXT_DEFAULT) { case CONTEXT_GLOBAL: if (set_boolean (word, value, &(((struct global *) item)->debug_tunnel))) return -1; break; default: snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n", word); return -1; } return 0; } int set_debugstate (char *word, char *value, int context, void *item) { switch (context & ~CONTEXT_DEFAULT) { case CONTEXT_GLOBAL: if (set_boolean (word, value, &(((struct global *) item)->debug_state))) return -1; break; default: snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n", word); return -1; } return 0; } int set_assignip (char *word, char *value, int context, void *item) { switch (context & ~CONTEXT_DEFAULT) { case CONTEXT_LNS: if (set_boolean (word, value, &(((struct lns *) item)->assign_ip))) return -1; break; default: snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n", word); return -1; } return 0; } struct iprange *set_range (char *word, char *value, struct iprange *in) { char *c, *d = NULL, *e = NULL; struct iprange *ipr, *p; struct hostent *hp; int count = 0; c = strchr (value, '-'); if (c) { d = c + 1; *c = 0; while ((c >= value) && (*c < 33)) *(c--) = 0; while (*d && (*d < 33)) d++; } if (!strlen (value) || (c && !strlen (d))) { snprintf (filerr, sizeof (filerr), "format is '%s - '\n", word); return NULL; } ipr = malloc (sizeof (struct iprange)); ipr->next = NULL; hp = gethostbyname (value); if (!hp) { snprintf (filerr, sizeof (filerr), "Unknown host %s\n", value); free (ipr); return NULL; } bcopy (hp->h_addr, &ipr->start, sizeof (unsigned int)); if (c) { char ip_hi[16]; e = d; while(*e != '\0') { if (*e++ == '.') count++; } if (count < 3) { strcpy(ip_hi, value); for (e = ip_hi + sizeof(ip_hi); e >= ip_hi; e--) { if (*e == '.') count--; if (count < 0) { e++; break; } } /* Copy the last field + null terminator */ if ((size_t)(ip_hi + sizeof(ip_hi)-e) > strlen(d)) { strcpy(e, d); d = ip_hi; } } hp = gethostbyname (d); if (!hp) { snprintf (filerr, sizeof (filerr), "Unknown host %s\n", d); free (ipr); return NULL; } bcopy (hp->h_addr, &ipr->end, sizeof (unsigned int)); } else ipr->end = ipr->start; if (ntohl (ipr->start) > ntohl (ipr->end)) { snprintf (filerr, sizeof (filerr), "start is greater than end!\n"); free (ipr); return NULL; } if (word[0] == 'n') ipr->sense = SENSE_DENY; else ipr->sense = SENSE_ALLOW; p = in; if (p) { while (p->next) p = p->next; p->next = ipr; return in; } else return ipr; } int set_iprange (char *word, char *value, int context, void *item) { struct lns *lns = (struct lns *) item; switch (context & ~CONTEXT_DEFAULT) { case CONTEXT_LNS: break; default: snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n", word); return -1; } lns->range = set_range (word, value, lns->range); if (!lns->range) return -1; #ifdef DEBUG_FILE l2tp_log (LOG_DEBUG, "range start = %x, end = %x, sense=%ud\n", ntohl (lns->range->start), ntohl (lns->range->end), lns->range->sense); #endif return 0; } int set_localiprange (char *word, char *value, int context, void *item) { struct lns *lns = (struct lns *) item; switch (context & ~CONTEXT_DEFAULT) { case CONTEXT_LNS: break; default: snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n", word); return -1; } if (lns->localaddr) { snprintf (filerr, sizeof (filerr), "'local ip range' and 'local ip' are mutually exclusive\n"); return -1; } lns->localrange = set_range (word, value, lns->localrange); if (!lns->localrange) return -1; #ifdef DEBUG_FILE l2tp_log (LOG_DEBUG, "range start = %x, end = %x, sense=%ud\n", ntohl (lns->range->start), ntohl (lns->range->end), lns->range->sense); #endif return 0; } int set_lac (char *word, char *value, int context, void *item) { struct lns *lns = (struct lns *) item; switch (context & ~CONTEXT_DEFAULT) { case CONTEXT_LNS: break; default: snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n", word); return -1; } lns->lacs = set_range (word, value, lns->lacs); if (!lns->lacs) return -1; #ifdef DEBUG_FILE l2tp_log (LOG_DEBUG, "lac start = %x, end = %x, sense=%ud\n", ntohl (lns->lacs->start), ntohl (lns->lacs->end), lns->lacs->sense); #endif return 0; } int set_exclusive (char *word, char *value, int context, void *item) { switch (context & ~CONTEXT_DEFAULT) { case CONTEXT_LNS: if (set_boolean (word, value, &(((struct lns *) item)->exclusive))) return -1; break; default: snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n", word); return -1; } return 0; } int set_ip (char *word, char *value, unsigned int *addr) { UNUSED(word); struct hostent *hp; hp = gethostbyname (value); if (!hp) { snprintf (filerr, sizeof (filerr), "%s: host '%s' not found\n", __FUNCTION__, value); return -1; } bcopy (hp->h_addr, addr, sizeof (unsigned int)); return 0; } int set_listenaddr (char *word, char *value, int context, void *item) { switch (context & ~CONTEXT_DEFAULT) { case CONTEXT_GLOBAL: #ifdef DEBUG_FILE l2tp_log (LOG_DEBUG, "set_listenaddr: Setting listen address to %s\n", value); #endif if (set_ip (word, value, &(((struct global *) item)->listenaddr))) return -1; break; default: snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n", word); return -1; } return 0; } int set_localaddr (char *word, char *value, int context, void *item) { struct lac *l; struct lns *n; switch (context & ~CONTEXT_DEFAULT) { case CONTEXT_LAC: l = (struct lac *) item; return set_ip (word, value, &(l->localaddr)); case CONTEXT_LNS: n = (struct lns *) item; if (n->localrange) { snprintf (filerr, sizeof (filerr), "'local ip range' and 'local ip' are mutually exclusive\n"); return -1; } return set_ip (word, value, &(n->localaddr)); default: snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n", word); return -1; } return 0; } int set_remoteaddr (char *word, char *value, int context, void *item) { struct lac *l; switch (context & ~CONTEXT_DEFAULT) { case CONTEXT_LAC: l = (struct lac *) item; return set_ip (word, value, &(l->remoteaddr)); default: snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n", word); return -1; } return 0; } int set_lns (char *word, char *value, int context, void *item) { #if 0 struct hostent *hp; #endif struct lac *l; struct host *ipr, *pos; char *d; switch (context & ~CONTEXT_DEFAULT) { case CONTEXT_LAC: #ifdef DEBUG_FILE l2tp_log (LOG_DEBUG, "set_lns: setting LNS to '%s'\n", value); #endif l = (struct lac *) item; d = strchr (value, ':'); if (d) { d[0] = 0; d++; } #if 0 // why would you want to lookup hostnames at this time? hp = gethostbyname (value); if (!hp) { snprintf (filerr, sizeof (filerr), "no such host '%s'\n", value); return -1; } #endif ipr = malloc (sizeof (struct host)); ipr->next = NULL; pos = l->lns; if (!pos) { l->lns = ipr; } else { while (pos->next) pos = pos->next; pos->next = ipr; } strncpy (ipr->hostname, value, sizeof (ipr->hostname)); if (d) ipr->port = atoi (d); else ipr->port = UDP_LISTEN_PORT; break; default: snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n", word); return -1; } return 0; } int set_rand_sys () { l2tp_log(LOG_WARNING, "The \"rand()\" function call is not a very good source" "of randomness\n"); rand_source = RAND_SYS; return 0; } int set_ipsec_saref (char *word, char *value, int context, void *item) { struct global *g = ((struct global *) item); switch (context & ~CONTEXT_DEFAULT) { case CONTEXT_GLOBAL: if (set_boolean (word, value, &(g->ipsecsaref))) return -1; if(g->ipsecsaref) { l2tp_log(LOG_INFO, "Enabling IPsec SAref processing for L2TP transport mode SAs\n"); } if(g->forceuserspace != 1) { l2tp_log(LOG_WARNING, "IPsec SAref does not work with L2TP kernel mode yet, enabling force userspace=yes\n"); g->forceuserspace = 1; } break; default: snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n", word); return -1; } return 0; } int set_saref_num (char *word, char *value, int context, void *item) { switch (context & ~CONTEXT_DEFAULT) { case CONTEXT_GLOBAL: l2tp_log (LOG_INFO, "Setting SAref IP_IPSEC_REFINFO number to %s\n", value); set_int (word, value, &(((struct global *) item)->sarefnum)); break; default: snprintf (filerr, sizeof (filerr), "'%s' not valid in this context\n", word); return -1; } return 0; } int set_rand_dev () { rand_source = RAND_DEV; return 0; } int set_rand_egd (char *value) { UNUSED(value); l2tp_log(LOG_WARNING, "%s: not yet implemented!\n", __FUNCTION__); rand_source = RAND_EGD; return -1; } int set_rand_source (char *word, char *value, int context, void *item) { UNUSED(item); time_t seconds; /* * We're going to go ahead and seed the rand() function with srand() * because even if we set the randomness source to dev or egd, they * can fall back to sys if they fail, so we want to make sure we at * least have *some* semblance of randomness available from the * rand() function */ /* * This is a sucky random number seed...just the result from the * time() call...but...the user requested to use the rand() * function, which is a pretty sucky source of randomness * regardless...at least we can get a almost sorta decent seed. If * you have any better suggestions for creating a seed...lemme know * :/ */ seconds = time(NULL); srand(seconds); if (context != CONTEXT_GLOBAL) { l2tp_log(LOG_WARNING, "%s: %s not valid in context %d\n", __FUNCTION__, word, context); return -1; } /* WORKING HERE */ if (strlen(value) == 0) { snprintf(filerr, sizeof (filerr), "no randomness source specified\n"); return -1; } if (strncmp(value, "egd", 3) == 0) { return set_rand_egd(value); } else if (strncmp(value, "dev", 3) == 0) { return set_rand_dev(); } else if (strncmp(value, "sys", 3) == 0) { return set_rand_sys(); } else { l2tp_log(LOG_WARNING, "%s: %s is not a valid randomness source\n", __FUNCTION__, value); return -1; } } int parse_config (FILE * f) { /* Read in the configuration file handed to us */ /* FIXME: I should check for incompatible options */ int context = 0; char buf[1024]; char *s, *d, *t; int linenum = 0; int def = 0; int in_comment = 0; int has_lf; void *data = NULL; struct lns *tl; struct lac *tc; while (!feof (f)) { if (NULL == fgets (buf, sizeof (buf), f)) { /* Error or EOL */ break; } /* Watch for continuation comments. */ has_lf = buf[strlen(buf) - 1] == '\n'; if (in_comment) { in_comment = !has_lf; continue; } linenum++; s = buf; /* Strip comments */ while (*s && *s != ';') s++; if (*s == ';' && !has_lf) in_comment = 1; *s = 0; s = buf; if (!strlen (buf)) continue; while ((*s < 33) && *s) s++; /* Skip over beginning white space */ t = s + strlen (s); while ((t >= s) && (*t < 33)) *(t--) = 0; /* Ditch trailing white space */ if (!strlen (s)) continue; if (s[0] == '[') { /* We've got a context description */ if (!(t = strchr (s, ']'))) { l2tp_log (LOG_CRIT, "parse_config: line %d: No closing bracket\n", linenum); return -1; } t[0] = 0; s++; if ((d = strchr (s, ' '))) { /* There's a parameter */ d[0] = 0; d++; } if (d && !strcasecmp (d, "default")) def = CONTEXT_DEFAULT; else def = 0; if (!strcasecmp (s, "global")) { context = CONTEXT_GLOBAL; #ifdef DEBUG_FILE l2tp_log (LOG_DEBUG, "parse_config: global context descriptor %s\n", d ? d : ""); #endif data = &gconfig; } else if (!strcasecmp (s, "lns")) { context = CONTEXT_LNS; if (def) { if (!deflns) { deflns = new_lns (); strncpy (deflns->entname, "default", sizeof (deflns->entname)); } data = deflns; continue; } data = NULL; tl = lnslist; if (d) { while (tl) { if (!strcasecmp (d, tl->entname)) break; tl = tl->next; } if (tl) data = tl; } if (!data) { data = new_lns (); if (!data) return -1; ((struct lns *) data)->next = lnslist; lnslist = (struct lns *) data; } if (d) strncpy (((struct lns *) data)->entname, d, sizeof (((struct lns *) data)->entname)); #ifdef DEBUG_FILE l2tp_log (LOG_DEBUG, "parse_config: lns context descriptor %s\n", d ? d : ""); #endif } else if (!strcasecmp (s, "lac")) { context = CONTEXT_LAC; if (def) { if (!deflac) { deflac = new_lac (); strncpy (deflac->entname, "default", sizeof (deflac->entname)); } data = deflac; continue; } data = NULL; tc = laclist; if (d) { while (tc) { if (!strcasecmp (d, tc->entname)) break; tc = tc->next; } if (tc) data = tc; } if (!data) { data = new_lac (); if (!data) return -1; ((struct lac *) data)->next = laclist; laclist = (struct lac *) data; } if (d) strncpy (((struct lac *) data)->entname, d, sizeof (((struct lac *) data)->entname)); #ifdef DEBUG_FILE l2tp_log (LOG_DEBUG, "parse_config: lac context descriptor %s\n", d ? d : ""); #endif } else { l2tp_log (LOG_WARNING, "parse_config: line %d: unknown context '%s'\n", linenum, s); return -1; } } else { if (!context) { l2tp_log (LOG_WARNING, "parse_config: line %d: data '%s' occurs with no context\n", linenum, s); return -1; } if (!(t = strchr (s, '='))) { l2tp_log (LOG_WARNING, "parse_config: line %d: line too long or no '=' in data\n", linenum); return -1; } d = t; d--; t++; while ((d >= s) && (*d < 33)) d--; d++; *d = 0; while (*t && (*t < 33)) t++; #ifdef DEBUG_FILE l2tp_log (LOG_DEBUG, "parse_config: field is %s, value is %s\n", s, t); #endif /* Okay, bit twiddling is done. Let's handle this */ switch (parse_one_option (s, t, context | def, data)) { case -1: l2tp_log (LOG_WARNING, "parse_config: line %d: %s", linenum, filerr); return -1; case -2: l2tp_log (LOG_CRIT, "parse_config: line %d: Unknown field '%s'\n", linenum, s); return -1; } } } return 0; } int parse_one_option(char *word, char *value, int context, void *item) { struct keyword *kw; for (kw = words; kw->keyword; kw++) { if (!strcasecmp (word, kw->keyword)) { if (kw->handler (word, value, context, item)) { return -1; } break; } } if (!kw->keyword) { return -2; } return 0; } struct keyword words[] = { {"listen-addr", &set_listenaddr}, {"port", &set_port}, {"saref refinfo", &set_saref_num}, {"rand source", &set_rand_source}, {"auth file", &set_authfile}, {"exclusive", &set_exclusive}, {"autodial", &set_autodial}, {"redial", &set_redial}, {"redial timeout", &set_rtimeout}, {"lns", &set_lns}, {"max redials", &set_rmax}, {"access control", &set_accesscontrol}, {"force userspace", &set_userspace}, {"ip range", &set_iprange}, {"no ip range", &set_iprange}, {"debug avp", &set_debugavp}, {"debug network", &set_debugnetwork}, {"debug packet", &set_debugpacket}, {"debug tunnel", &set_debugtunnel}, {"debug state", &set_debugstate}, {"ipsec saref", &set_ipsec_saref}, {"lac", &set_lac}, {"no lac", &set_lac}, {"assign ip", &set_assignip}, {"local ip", &set_localaddr}, {"local ip range", &set_localiprange}, {"remote ip", &set_remoteaddr}, {"defaultroute", &set_defaultroute}, {"length bit", &set_lbit}, {"hidden bit", &set_hbit}, {"require pap", &set_papchap}, {"require chap", &set_papchap}, {"require authentication", &set_papchap}, {"require auth", &set_papchap}, {"refuse pap", &set_papchap}, {"refuse chap", &set_papchap}, {"refuse authentication", &set_papchap}, {"refuse auth", &set_papchap}, {"unix authentication", &set_passwdauth}, {"unix auth", &set_passwdauth}, {"name", &set_authname}, {"hostname", &set_hostname}, {"ppp debug", &set_debug}, {"pass peer", &set_pass_peer}, {"pppoptfile", &set_pppoptfile}, {"call rws", &set_rws}, {"tunnel rws", &set_rws}, {"flow bit", &set_flow}, {"challenge", &set_challenge}, {"tx bps", &set_speed}, {"rx bps", &set_speed}, {"bps", &set_speed}, {"max retries" , &set_maxretries}, {"cap backoff" , &set_capbackoff}, {NULL, NULL} }; xl2tpd-1.3.16/file.h000066400000000000000000000171511374460464600141320ustar00rootroot00000000000000/* * Layer Two Tunnelling Protocol Daemon * Copyright (C) 1998 Adtran, Inc. * Copyright (C) 2002 Jeff McAdams * * Mark Spencer * * This software is distributed under the terms * of the GPL, which you should have received * along with this source. * * File format handling header file * */ #ifndef _FILE_H #define _FILE_H #define STRLEN 100 /* Length of a string */ /* Definition of a keyword */ struct keyword { char *keyword; int (*handler) (char *word, char *value, int context, void *item); }; struct iprange { unsigned int start; unsigned int end; int sense; struct iprange *next; }; struct host { char hostname[STRLEN]; int port; struct host *next; }; #define CONTEXT_GLOBAL 1 #define CONTEXT_LNS 2 #define CONTEXT_LAC 3 #define CONTEXT_DEFAULT 256 #define SENSE_ALLOW -1 #define SENSE_DENY 0 #ifndef DEFAULT_AUTH_FILE #define DEFAULT_AUTH_FILE "/etc/xl2tpd/l2tp-secrets" #endif #ifndef DEFAULT_CONFIG_FILE #define DEFAULT_CONFIG_FILE "/etc/xl2tpd/xl2tpd.conf" #endif #define ALT_DEFAULT_AUTH_FILE "/etc/l2tpd/l2tp-secrets" #define ALT_DEFAULT_CONFIG_FILE "/etc/l2tp/l2tpd.conf" #define DEFAULT_PID_FILE "/var/run/xl2tpd.pid" /* Definition of an LNS */ struct lns { struct lns *next; int exclusive; /* Only one tunnel per host? */ int active; /* Is this actively in use? */ unsigned int localaddr; /* Local IP for PPP connections */ int tun_rws; /* Receive window size (tunnel) */ int call_rws; /* Call rws */ int rxspeed; /* Tunnel rx speed */ int txspeed; /* Tunnel tx speed */ int hbit; /* Permit hidden AVP's? */ int lbit; /* Use the length field? */ int challenge; /* Challenge authenticate the peer? */ int authpeer; /* Authenticate our peer? */ int authself; /* Authenticate ourselves? */ char authname[STRLEN]; /* Who we authenticate as */ char peername[STRLEN]; /* Force peer name to this */ char hostname[STRLEN]; /* Hostname to report */ char entname[STRLEN]; /* Name of this entry */ struct iprange *lacs; /* Hosts permitted to connect */ struct iprange *range; /* Range of IP's we provide */ struct iprange *localrange; /* Range of local IP's we provide */ int assign_ip; /* Do we actually provide IP addresses? */ int passwdauth; /* Authenticate by passwd file? (or PAM) */ int pap_require; /* Require PAP auth for PPP */ int chap_require; /* Require CHAP auth for PPP */ int pap_refuse; /* Refuse PAP authentication for us */ int chap_refuse; /* Refuse CHAP authentication for us */ int idle; /* Idle timeout in seconds */ unsigned int pridns; /* Primary DNS server */ unsigned int secdns; /* Secondary DNS server */ unsigned int priwins; /* Primary WINS server */ unsigned int secwins; /* Secondary WINS server */ int proxyarp; /* Use proxy-arp? */ int proxyauth; /* Allow proxy authentication? */ int debug; /* Debug PPP? */ int pass_peer; /* Pass peer IP to pppd as ipparam? */ char pppoptfile[STRLEN]; /* File containing PPP options */ struct tunnel *t; /* Tunnel of this, if it's ready */ }; struct lac { struct lac *next; struct host *lns; /* LNS's we can connect to */ struct schedule_entry *rsched; int tun_rws; /* Receive window size (tunnel) */ int call_rws; /* Call rws */ int rxspeed; /* Tunnel rx speed */ int txspeed; /* Tunnel tx speed */ int active; /* Is this connection in active use? */ int hbit; /* Permit hidden AVP's? */ int lbit; /* Use the length field? */ int challenge; /* Challenge authenticate the peer? */ unsigned int localaddr; /* Local IP address */ unsigned int remoteaddr; /* Force remote address to this */ char authname[STRLEN]; /* Who we authenticate as */ char password[STRLEN]; /* Password to authenticate with */ char peername[STRLEN]; /* Force peer name to this */ char hostname[STRLEN]; /* Hostname to report */ char entname[STRLEN]; /* Name of this entry */ int authpeer; /* Authenticate our peer? */ int authself; /* Authenticate ourselves? */ int pap_require; /* Require PAP auth for PPP */ int chap_require; /* Require CHAP auth for PPP */ int pap_refuse; /* Refuse PAP authentication for us */ int chap_refuse; /* Refuse CHAP authentication for us */ int idle; /* Idle timeout in seconds */ int autodial; /* Try to dial immediately? */ int defaultroute; /* Use as default route? */ int redial; /* Redial if disconnected */ int rmax; /* Maximum # of consecutive redials */ int rtries; /* # of tries so far */ int rtimeout; /* Redial every this many # of seconds */ int pass_peer; /* Pass peer IP to pppd as ipparam? */ char pppoptfile[STRLEN]; /* File containing PPP options */ int debug; struct tunnel *t; /* Our tunnel */ struct call *c; /* Our call */ }; struct global { unsigned int listenaddr; /* IP address to bind to */ int port; /* Port number to listen to */ char authfile[STRLEN]; /* File containing authentication info */ char altauthfile[STRLEN]; /* File containing authentication info */ char configfile[STRLEN]; /* File containing configuration info */ char altconfigfile[STRLEN]; /* File containing configuration info */ char pidfile[STRLEN]; /* File containing the pid number*/ char controlfile[STRLEN]; /* Control file name (named pipe) */ char controltos[STRLEN]; /* Control TOS value */ int daemon; /* Use daemon mode? */ int syslog; /* Use syslog for logging? */ int accesscontrol; /* Use access control? */ int forceuserspace; /* Force userspace? */ int packet_dump; /* Dump (print) all packets? */ int debug_avp; /* Print AVP debugging info? */ int debug_network; /* Print network debugging info? */ int debug_tunnel; /* Print tunnel debugging info? */ int debug_state; /* Print FSM debugging info? */ int ipsecsaref; int sarefnum; /* Value of IPSEC_REFINFO used by kernel * (we used to pick 22, but 2.6.36+ took that, so now we pick 30) * Changed in SAref patch in openswan 2.6.36 for linux 2.6.36+ */ int max_retries; /* Max retries before closing tunnel or stop re-transmitting */ int cap_backoff; /* Limit seconds between exponential backoff */ }; extern struct global gconfig; /* Global configuration options */ extern struct lns *lnslist; /* All LNS entries */ extern struct lac *laclist; /* All LAC entries */ extern struct lns *deflns; /* Default LNS config */ extern struct lac *deflac; /* Default LAC config */ extern int init_config (); /* Read in the config file */ /* Tries to apply _word_ option with _value_ to _item_ in _context_ */ extern int parse_one_option (char *word, char *value, int context, void *item); /* Allocate memory and filled up new lac */ extern struct lac *new_lac (); extern struct lns *new_lns (); #endif xl2tpd-1.3.16/ipsecmast.h000066400000000000000000000005021374460464600151730ustar00rootroot00000000000000#ifndef _IPSECMAST_H #define _IPSECMAST_H #ifndef IP_IPSEC_REFINFO /* 22 has been assigned to IP_NODEFRAG in 2.6.36+ so we moved to 30 * #define IP_IPSEC_REFINFO 22 */ #define IP_IPSEC_REFINFO 30 #endif #ifndef IPSEC_SAREF_NULL typedef uint32_t IPsecSAref_t; #define IPSEC_SAREF_NULL ((IPsecSAref_t)0) #endif #endif xl2tpd-1.3.16/l2tp.h000066400000000000000000000217031374460464600140720ustar00rootroot00000000000000/* * Layer Two Tunnelling Protocol Daemon * Copyright (C) 1998 Adtran, Inc. * Copyright (C) 2002 Jeff McAdams * * Mark Spencer * * This software is distributed under the terms * of the GPL, which you should have received * along with this source. * * Protocol and implementation information, * structures and constants. */ /* typedef unsigned short _u16; typedef unsigned long long _u64; */ #ifndef _L2TP_H #define _L2TP_H #define MAXSTRLEN 120 /* Maximum length of common strings */ /* FIXME: MAX_RECV_SIZE, what is it? */ #define MAX_RECV_SIZE 4096 /* Biggest packet we'll accept */ #include #include #ifdef OPENBSD # include #endif #include "osport.h" #include "scheduler.h" #include "misc.h" #include "file.h" #include "call.h" #include "avp.h" #include "control.h" #include "aaa.h" #include "common.h" #include "ipsecmast.h" #define CONTROL_PIPE "/var/run/xl2tpd/l2tp-control" #define CONTROL_PIPE_MESSAGE_SIZE 1024 #define UNUSED(x) (void)(x) /* Control pip request types */ #define CONTROL_PIPE_REQ_LAC_REMOVE 'r' #define CONTROL_PIPE_REQ_LAC_ADD_MODIFY 'a' #define CONTROL_PIPE_REQ_LAC_STATUS 's' #define CONTROL_PIPE_REQ_LAC_DISCONNECT 'd' #define CONTROL_PIPE_REQ_LAC_HANGUP 'h' #define CONTROL_PIPE_REQ_LAC_OUTGOING_CALL 'o' #define CONTROL_PIPE_REQ_LAC_CONNECT 'c' #define CONTROL_PIPE_REQ_TUNNEL 't' #define CONTROL_PIPE_REQ_LNS_ADD_MODIFY 'z' /* Create or modify an existing LNS */ #define CONTROL_PIPE_REQ_LNS_STATUS 'y' /* Get status of LNS */ #define CONTROL_PIPE_REQ_AVAILABLE 'x' /* Get status of LNS */ #define CONTROL_PIPE_REQ_LNS_REMOVE 'w' /* Get status of LNS */ #define BINARY "xl2tpd" #define SERVER_VERSION "xl2tpd-1.3.16" #define VENDOR_NAME "xelerance.com" #ifndef PPPD #define PPPD "/usr/sbin/pppd" #endif #define CALL_PPP_OPTS "defaultroute" #define FIRMWARE_REV 0x0690 /* Revision of our firmware (software, in this case) */ #define HELLO_DELAY 60 /* How often to send a Hello message */ struct control_hdr { _u16 ver; /* Version and more */ _u16 length; /* Length field */ _u16 tid; /* Tunnel ID */ _u16 cid; /* Call ID */ _u16 Ns; /* Next sent */ _u16 Nr; /* Next received */ } __attribute__((packed)); #define CTBIT(ver) (ver & 0x8000) /* Determins if control or not */ #define CLBIT(ver) (ver & 0x4000) /* Length bit present. Must be 1 for control messages */ #define CZBITS(ver) (ver &0x37F8) /* Reserved bits: We must drop anything with these there */ #define CFBIT(ver) (ver & 0x0800) /* Presence of Ns and Nr fields flow bit? */ #define CVER(ver) (ver & 0x0007) /* Version of encapsulation */ struct payload_hdr { _u16 ver; /* Version and friends */ _u16 length; /* Optional Length */ _u16 tid; /* Tunnel ID */ _u16 cid; /* Caller ID */ _u16 Ns; /* Optional next sent */ _u16 Nr; /* Optional next received */ _u16 o_size; /* Optional offset size */ // _u16 o_pad; /* Optional offset padding */ } __attribute__((packed)); #define NZL_TIMEOUT_DIVISOR 4 /* Divide TIMEOUT by this and you know how often to send a zero byte packet */ #define PAYLOAD_BUF 10 /* Provide 10 expansion bytes so we can "decompress" the payloads and simplify coding */ #if 1 #define DEFAULT_MAX_RETRIES 5 /* Recommended value from spec */ #else #define DEFAULT_MAX_RETRIES 95 /* give us more time to debug */ #endif #define DEFAULT_RWS_SIZE 4 /* Default max outstanding control packets in queue */ #define DEFAULT_TX_BPS 10000000 /* For outgoing calls, report this speed */ #define DEFAULT_RX_BPS 10000000 #define DEFAULT_MAX_BPS 10000000 /* jz: outgoing calls max bps */ #define DEFAULT_MIN_BPS 10000 /* jz: outgoing calls min bps */ #define PAYLOAD_FUDGE 2 /* How many packets we're willing to drop */ #define MIN_PAYLOAD_HDR_LEN 6 #define UDP_LISTEN_PORT 1701 #define OUR_L2TP_VERSION 0x100 /* We support version 1, revision 0 */ #define PTBIT(ver) CTBIT(ver) /* Type bit: Must be zero for us */ #define PLBIT(ver) CLBIT(ver) /* Length specified? */ #define PFBIT(ver) CFBIT(ver) /* Flow control specified? */ #define PVER(ver) CVER(ver) /* Version */ #define PZBITS(ver) (ver & 0x14F8) /* Reserved bits */ #define PRBIT(ver) (ver & 0x2000) /* Reset Sr bit */ #define PSBIT(ver) (ver & 0x0200) /* Offset size bit */ #define PPBIT(ver) (ver & 0x0100) /* Preference bit */ struct tunnel { struct call *call_head; /* Member calls */ struct tunnel *next; /* Allows us to be linked easily */ int fc; /* Framing capabilities of peer */ struct schedule_entry *hello; int ourfc; /* Our framing capabilities */ int bc; /* Peer's bearer channels */ int hbit; /* Allow hidden AVP's? */ int ourbc; /* Our bearer channels */ _u64 tb; /* Their tie breaker */ _u64 ourtb; /* Our tie breaker */ int tid; /* Peer's tunnel identifier */ IPsecSAref_t refme; /* IPsec SA particulars */ IPsecSAref_t refhim; int ourtid; /* Our tunnel identifier */ int qtid; /* TID for disconnection */ int firmware; /* Peer's firmware revision */ #if 0 unsigned int addr; /* Remote address */ unsigned short port; /* Port on remote end */ #else struct sockaddr_in peer; /* Peer's Address */ #endif int debug; /* Are we debugging or not? */ int nego; /* Show Negotiation? */ int count; /* How many membmer calls? */ int state; /* State of tunnel */ _u16 control_seq_num; /* Sequence for next packet */ _u16 control_rec_seq_num; /* Next expected to receive */ int cLr; /* Last packet received by peer */ #ifdef SANITY int sanity; /* check for sanity? */ #endif int rws; /* Peer's Receive Window Size */ int ourrws; /* Receive Window Size */ int rxspeed; /* Receive bps */ int txspeed; /* Transmit bps */ int udp_fd; /* UDP fd */ int pppox_fd; /* PPPOX tunnel fd */ struct call *self; struct lns *lns; /* LNS that owns us */ struct lac *lac; /* LAC that owns us */ struct in_pktinfo my_addr; /* Address of my endpoint */ char hostname[MAXSTRLEN]; /* Remote hostname */ char vendor[MAXSTRLEN]; /* Vendor of remote product */ struct challenge chal_us; /* Their Challenge to us */ struct challenge chal_them; /* Our challenge to them */ char secret[MAXSTRLEN]; /* Secret to use */ }; struct tunnel_list { struct tunnel *head; int count; int calls; }; /* Values for version */ #define VER_L2TP 2 #define VER_PPTP 3 /* Some PPP sync<->async stuff */ #define fcstab ppp_crc16_table #define PPP_FLAG 0x7e #define PPP_ESCAPE 0x7d #define PPP_TRANS 0x20 #define PPP_INITFCS 0xffff #define PPP_GOODFCS 0xf0b8 #define PPP_FCS(fcs,c) (((fcs) >> 8) ^ fcstab[((fcs) ^ (c)) & 0xff]) /* Values for Randomness sources */ #define RAND_DEV 0x0 #define RAND_SYS 0x1 #define RAND_EGD 0x2 /* Error Values */ extern struct tunnel_list tunnels; extern void tunnel_close (struct tunnel *t); extern void network_thread (); extern int init_network (); extern int server_socket; extern struct tunnel *new_tunnel (); extern struct packet_queue xmit_udp; extern void destroy_tunnel (struct tunnel *); extern struct buffer *new_payload (struct sockaddr_in); extern void recycle_payload (struct buffer *, struct sockaddr_in); extern void add_payload_hdr (struct tunnel *, struct call *, struct buffer *); extern int read_packet (struct call *); extern void udp_xmit (struct buffer *buf, struct tunnel *t); extern void control_xmit (void *); extern int ppd; extern int switch_io; /* jz */ extern int control_fd; #ifdef USE_KERNEL extern int kernel_support; extern int connect_pppol2tp (struct tunnel *t); #endif extern int start_pppd (struct call *c, struct ppp_opts *); extern void magic_lac_dial (void *); extern int get_entropy (unsigned char *, int); #ifndef MIN #define MIN(a,b) (((a)<(b)) ? (a) : (b)) #endif #endif /* * This is just some stuff to take * care of kernel definitions */ #ifdef USE_KERNEL #include #include #include #include #endif xl2tpd-1.3.16/md5.c000066400000000000000000000210241374460464600136650ustar00rootroot00000000000000#ifdef FREEBSD # include #elif defined(OPENBSD) || defined(NETBSD) # define __BSD_VISIBLE 0 # include #elif defined(LINUX) # include #elif defined(SOLARIS) # include #endif #if __BYTE_ORDER == __BIG_ENDIAN #define HIGHFIRST 1 #endif /* * This code implements the MD5 message-digest algorithm. * The algorithm is due to Ron Rivest. This code was * written by Colin Plumb in 1993, no copyright is claimed. * This code is in the public domain; do with it what you wish. * * Equivalent code is available from RSA Data Security, Inc. * This code has been tested against that, and is equivalent, * except that you don't need to include two pages of legalese * with every copy. * * To compute the message digest of a chunk of bytes, declare an * MD5Context structure, pass it to MD5Init, call MD5Update as * needed on buffers full of bytes, and then call MD5Final, which * will fill a supplied 16-byte array with the digest. */ #include /* for memcpy() */ #include "md5.h" #ifndef HIGHFIRST #define byteReverse(buf, len) /* Nothing */ #else void byteReverse (unsigned char *buf, unsigned longs); #ifndef ASM_MD5 /* * Note: this code is harmless on little-endian machines. */ void byteReverse (unsigned char *buf, unsigned longs) { uint32 t; do { t = (uint32) ((unsigned) buf[3] << 8 | buf[2]) << 16 | ((unsigned) buf[1] << 8 | buf[0]); *(uint32 *) buf = t; buf += 4; } while (--longs); } #endif #endif /* * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious * initialization constants. */ void MD5Init (struct MD5Context *ctx) { ctx->buf[0] = 0x67452301; ctx->buf[1] = 0xefcdab89; ctx->buf[2] = 0x98badcfe; ctx->buf[3] = 0x10325476; ctx->bits[0] = 0; ctx->bits[1] = 0; } /* * Update context to reflect the concatenation of another buffer full * of bytes. */ void MD5Update (struct MD5Context *ctx, unsigned char const *buf, unsigned len) { uint32 t; /* Update bitcount */ t = ctx->bits[0]; if ((ctx->bits[0] = t + ((uint32) len << 3)) < t) ctx->bits[1]++; /* Carry from low to high */ ctx->bits[1] += len >> 29; t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */ /* Handle any leading odd-sized chunks */ if (t) { unsigned char *p = (unsigned char *) ctx->in + t; t = 64 - t; if (len < t) { memcpy (p, buf, len); return; } memcpy (p, buf, t); byteReverse (ctx->in, 16); MD5Transform (ctx->buf, (uint32 *) ctx->in); buf += t; len -= t; } /* Process data in 64-byte chunks */ while (len >= 64) { memcpy (ctx->in, buf, 64); byteReverse (ctx->in, 16); MD5Transform (ctx->buf, (uint32 *) ctx->in); buf += 64; len -= 64; } /* Handle any remaining bytes of data. */ memcpy (ctx->in, buf, len); } /* * Final wrapup - pad to 64-byte boundary with the bit pattern * 1 0* (64-bit count of bits processed, MSB-first) */ void MD5Final (unsigned char digest[16], struct MD5Context *ctx) { unsigned count; unsigned char *p; /* Compute number of bytes mod 64 */ count = (ctx->bits[0] >> 3) & 0x3F; /* Set the first char of padding to 0x80. This is safe since there is always at least one byte free */ p = ctx->in + count; *p++ = 0x80; /* Bytes of padding needed to make 64 bytes */ count = 64 - 1 - count; /* Pad out to 56 mod 64 */ if (count < 8) { /* Two lots of padding: Pad the first block to 64 bytes */ memset (p, 0, count); byteReverse (ctx->in, 16); MD5Transform (ctx->buf, (uint32 *) ctx->in); /* Now fill the next block with 56 bytes */ memset (ctx->in, 0, 56); } else { /* Pad block to 56 bytes */ memset (p, 0, count - 8); } byteReverse (ctx->in, 14); /* Append length in bits and transform */ memcpy(ctx->in + 14 * sizeof(uint32), ctx->bits, sizeof(ctx->bits)); MD5Transform (ctx->buf, (uint32 *) ctx->in); byteReverse ((unsigned char *) ctx->buf, 4); memcpy (digest, ctx->buf, 16); memset (ctx, 0, sizeof (*ctx)); /* In case it's sensitive */ } #ifndef ASM_MD5 /* The four core functions - F1 is optimized somewhat */ /* #define F1(x, y, z) (x & y | ~x & z) */ #define F1(x, y, z) (z ^ (x & (y ^ z))) #define F2(x, y, z) F1(z, x, y) #define F3(x, y, z) (x ^ y ^ z) #define F4(x, y, z) (y ^ (x | ~z)) /* This is the central step in the MD5 algorithm. */ #define MD5STEP(f, w, x, y, z, data, s) \ ( w += f(x, y, z) + data, w = w<>(32-s), w += x ) /* * The core of the MD5 algorithm, this alters an existing MD5 hash to * reflect the addition of 16 longwords of new data. MD5Update blocks * the data and converts bytes into longwords for this routine. */ void MD5Transform (uint32 buf[4], uint32 const in[16]) { register uint32 a, b, c, d; a = buf[0]; b = buf[1]; c = buf[2]; d = buf[3]; MD5STEP (F1, a, b, c, d, in[0] + 0xd76aa478, 7); MD5STEP (F1, d, a, b, c, in[1] + 0xe8c7b756, 12); MD5STEP (F1, c, d, a, b, in[2] + 0x242070db, 17); MD5STEP (F1, b, c, d, a, in[3] + 0xc1bdceee, 22); MD5STEP (F1, a, b, c, d, in[4] + 0xf57c0faf, 7); MD5STEP (F1, d, a, b, c, in[5] + 0x4787c62a, 12); MD5STEP (F1, c, d, a, b, in[6] + 0xa8304613, 17); MD5STEP (F1, b, c, d, a, in[7] + 0xfd469501, 22); MD5STEP (F1, a, b, c, d, in[8] + 0x698098d8, 7); MD5STEP (F1, d, a, b, c, in[9] + 0x8b44f7af, 12); MD5STEP (F1, c, d, a, b, in[10] + 0xffff5bb1, 17); MD5STEP (F1, b, c, d, a, in[11] + 0x895cd7be, 22); MD5STEP (F1, a, b, c, d, in[12] + 0x6b901122, 7); MD5STEP (F1, d, a, b, c, in[13] + 0xfd987193, 12); MD5STEP (F1, c, d, a, b, in[14] + 0xa679438e, 17); MD5STEP (F1, b, c, d, a, in[15] + 0x49b40821, 22); MD5STEP (F2, a, b, c, d, in[1] + 0xf61e2562, 5); MD5STEP (F2, d, a, b, c, in[6] + 0xc040b340, 9); MD5STEP (F2, c, d, a, b, in[11] + 0x265e5a51, 14); MD5STEP (F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); MD5STEP (F2, a, b, c, d, in[5] + 0xd62f105d, 5); MD5STEP (F2, d, a, b, c, in[10] + 0x02441453, 9); MD5STEP (F2, c, d, a, b, in[15] + 0xd8a1e681, 14); MD5STEP (F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); MD5STEP (F2, a, b, c, d, in[9] + 0x21e1cde6, 5); MD5STEP (F2, d, a, b, c, in[14] + 0xc33707d6, 9); MD5STEP (F2, c, d, a, b, in[3] + 0xf4d50d87, 14); MD5STEP (F2, b, c, d, a, in[8] + 0x455a14ed, 20); MD5STEP (F2, a, b, c, d, in[13] + 0xa9e3e905, 5); MD5STEP (F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); MD5STEP (F2, c, d, a, b, in[7] + 0x676f02d9, 14); MD5STEP (F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); MD5STEP (F3, a, b, c, d, in[5] + 0xfffa3942, 4); MD5STEP (F3, d, a, b, c, in[8] + 0x8771f681, 11); MD5STEP (F3, c, d, a, b, in[11] + 0x6d9d6122, 16); MD5STEP (F3, b, c, d, a, in[14] + 0xfde5380c, 23); MD5STEP (F3, a, b, c, d, in[1] + 0xa4beea44, 4); MD5STEP (F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); MD5STEP (F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); MD5STEP (F3, b, c, d, a, in[10] + 0xbebfbc70, 23); MD5STEP (F3, a, b, c, d, in[13] + 0x289b7ec6, 4); MD5STEP (F3, d, a, b, c, in[0] + 0xeaa127fa, 11); MD5STEP (F3, c, d, a, b, in[3] + 0xd4ef3085, 16); MD5STEP (F3, b, c, d, a, in[6] + 0x04881d05, 23); MD5STEP (F3, a, b, c, d, in[9] + 0xd9d4d039, 4); MD5STEP (F3, d, a, b, c, in[12] + 0xe6db99e5, 11); MD5STEP (F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); MD5STEP (F3, b, c, d, a, in[2] + 0xc4ac5665, 23); MD5STEP (F4, a, b, c, d, in[0] + 0xf4292244, 6); MD5STEP (F4, d, a, b, c, in[7] + 0x432aff97, 10); MD5STEP (F4, c, d, a, b, in[14] + 0xab9423a7, 15); MD5STEP (F4, b, c, d, a, in[5] + 0xfc93a039, 21); MD5STEP (F4, a, b, c, d, in[12] + 0x655b59c3, 6); MD5STEP (F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); MD5STEP (F4, c, d, a, b, in[10] + 0xffeff47d, 15); MD5STEP (F4, b, c, d, a, in[1] + 0x85845dd1, 21); MD5STEP (F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); MD5STEP (F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); MD5STEP (F4, c, d, a, b, in[6] + 0xa3014314, 15); MD5STEP (F4, b, c, d, a, in[13] + 0x4e0811a1, 21); MD5STEP (F4, a, b, c, d, in[4] + 0xf7537e82, 6); MD5STEP (F4, d, a, b, c, in[11] + 0xbd3af235, 10); MD5STEP (F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); MD5STEP (F4, b, c, d, a, in[9] + 0xeb86d391, 21); buf[0] += a; buf[1] += b; buf[2] += c; buf[3] += d; } #endif xl2tpd-1.3.16/md5.h000066400000000000000000000011541374460464600136740ustar00rootroot00000000000000#ifndef MD5_H #define MD5_H #ifdef __alpha typedef unsigned int uint32; #else #include typedef uint32_t uint32; #endif struct MD5Context { uint32 buf[4]; uint32 bits[2]; unsigned char in[64]; }; void MD5Init (struct MD5Context *context); void MD5Update (struct MD5Context *context, unsigned char const *buf, unsigned len); void MD5Final (unsigned char digest[16], struct MD5Context *context); void MD5Transform (uint32 buf[4], uint32 const in[16]); /* * This is needed to make RSAREF happy on some MS-DOS compilers. */ typedef struct MD5Context MD5_CTX; #endif /* !MD5_H */ xl2tpd-1.3.16/misc.c000066400000000000000000000165611374460464600141450ustar00rootroot00000000000000/* * Layer Two Tunnelling Protocol Daemon * Copyright (C) 1998 Adtran, Inc. * Copyright (C) 2002 Jeff McAdams * * Mark Spencer * * This software is distributed under the terms * of the GPL, which you should have received * along with this source. * * Miscellaneous but important functions * */ #include #include #include #include #include #include #include #include #include #include #if defined(SOLARIS) # include #endif #include #include "l2tp.h" /* prevent deadlock that occurs when a signal handler, which interrupted a * call to syslog(), attempts to call syslog(). */ static int syslog_nesting = 0; #define SYSLOG_CALL(code) do { \ if (++syslog_nesting < 2) { \ code; \ } \ --syslog_nesting; \ } while(0) #define UNUSED(x) (void)(x) void init_log() { static int logopen=0; if(!logopen) { SYSLOG_CALL( openlog (BINARY, LOG_PID, LOG_DAEMON) ); logopen=1; } } void l2tp_log (int level, const char *fmt, ...) { char buf[2048]; va_list args; va_start (args, fmt); vsnprintf (buf, sizeof (buf), fmt, args); va_end (args); if(gconfig.syslog) { init_log(); SYSLOG_CALL( syslog (level, "%s", buf) ); } else { fprintf(stderr, "xl2tpd[%d]: %s", getpid(), buf); } } void set_error (struct call *c, int error, const char *fmt, ...) { va_list args; va_start (args, fmt); c->error = error; c->result = RESULT_ERROR; c->needclose = -1; vsnprintf (c->errormsg, sizeof (c->errormsg), fmt, args); if (c->errormsg[strlen (c->errormsg) - 1] == '\n') c->errormsg[strlen (c->errormsg) - 1] = 0; va_end (args); } struct buffer *new_buf (int size) { struct buffer *b = NULL; if (!size || size < 0) return NULL; b = malloc (sizeof (struct buffer)); if (!b) return NULL; b->rstart = malloc (size); if (!b->rstart) { free (b); return NULL; } b->start = b->rstart; b->rend = b->rstart + size - 1; b->len = size; b->maxlen = size; return b; } inline void recycle_buf (struct buffer *b) { b->start = b->rstart; b->len = b->maxlen; } #define bufferDumpWIDTH 16 void bufferDump (unsigned char *buf, int buflen) { int i = 0, j = 0; /* we need TWO characters to DISPLAY ONE byte */ char line[2 * bufferDumpWIDTH + 1], *c; for (i = 0; i < buflen / bufferDumpWIDTH; i++) { c = line; for (j = 0; j < bufferDumpWIDTH; j++) { sprintf (c, "%02x", (buf[i * bufferDumpWIDTH + j]) & 0xff); c++; c++; /* again two characters to display ONE byte */ } *c = '\0'; l2tp_log (LOG_WARNING, "%s: buflen=%d, buffer[%d]: *%s*\n", __FUNCTION__, buflen, i, line); } c = line; for (j = 0; j < buflen % bufferDumpWIDTH; j++) { sprintf (c, "%02x", buf[(buflen / bufferDumpWIDTH) * bufferDumpWIDTH + j] & 0xff); c++; c++; } if (c != line) { *c = '\0'; l2tp_log (LOG_WARNING, "%s: buffer[%d]: *%s*\n", __FUNCTION__, i, line); } } void do_packet_dump (struct buffer *buf) { size_t x; unsigned char *c = buf->start; printf ("packet dump: \nHEX: { "); for (x = 0; x < buf->len; x++) { printf ("%.2X ", *c); c++; }; printf ("}\nASCII: { "); c = buf->start; for (x = 0; x < buf->len; x++) { if (*c > 31 && *c < 127) { putchar (*c); } else { putchar (' '); } c++; } printf ("}\n"); } void swaps (void *buf_v, int len) { #ifdef __alpha /* Reverse byte order alpha is little endian so lest save a step. to make things work out easier */ int x; unsigned char t1; unsigned char *tmp = (_u16 *) buf_v; for (x = 0; x < len; x += 2) { t1 = tmp[x]; tmp[x] = tmp[x + 1]; tmp[x + 1] = t1; } #else /* Reverse byte order (if proper to do so) to make things work out easier */ int x; struct hw { _u16 s; } __attribute__ ((packed)) *p = (struct hw *) buf_v; for (x = 0; x < len / 2; x++, p++) p->s = ntohs(p->s); #endif } inline void toss (struct buffer *buf) { /* * Toss a frame and free up the buffer that contained it */ free (buf->rstart); free (buf); } inline void safe_copy (char *a, char *b, int size) { /* Copies B into A (assuming A holds MAXSTRLEN bytes) safely */ strncpy (a, b, MIN (size, MAXSTRLEN - 1)); a[MIN (size, MAXSTRLEN - 1)] = '\000'; } struct ppp_opts *add_opt (struct ppp_opts *option, char *fmt, ...) { va_list args; struct ppp_opts *new, *last; new = malloc (sizeof (struct ppp_opts)); if (!new) { l2tp_log (LOG_WARNING, "%s : Unable to allocate ppp option memory. Expect a crash\n", __FUNCTION__); return option; } new->next = NULL; va_start (args, fmt); vsnprintf (new->option, sizeof (new->option), fmt, args); va_end (args); if (option) { last = option; while (last->next) last = last->next; last->next = new; return option; } else return new; } void opt_destroy (struct ppp_opts *option) { struct ppp_opts *tmp; while (option) { tmp = option->next; free (option); option = tmp; }; } int get_egd_entropy(char *buf, int count) { UNUSED(buf); UNUSED(count); return -1; } int get_sys_entropy(unsigned char *buf, int count) { /* * This way of filling buf with rand() generated data is really * fairly inefficient from a function call point of view...rand() * returns four bytes of data (on most systems, sizeof(int)) * and we end up only using 1 byte of it (sizeof(char))...ah * well...it was a *whole* lot easier to code this way...suggestions * for improvements are, of course, welcome */ int counter; for (counter = 0; counter < count; counter++) { buf[counter] = (char)rand(); } #ifdef DEBUG_ENTROPY bufferDump (buf, count); #endif return count; } int get_dev_entropy(unsigned char *buf, int count) { int devrandom; ssize_t entropy_amount; devrandom = open ("/dev/urandom", O_RDONLY | O_NONBLOCK); if (devrandom == -1) { #ifdef DEBUG_ENTROPY l2tp_log(LOG_WARNING, "%s: couldn't open /dev/urandom," "falling back to rand()\n", __FUNCTION__); #endif return get_sys_entropy(buf, count); } entropy_amount = read(devrandom, buf, count); close(devrandom); return entropy_amount; } int get_entropy (unsigned char *buf, int count) { if (rand_source == RAND_SYS) { return get_sys_entropy(buf, count); } else if (rand_source == RAND_DEV) { return get_dev_entropy(buf, count); } else if (rand_source == RAND_EGD) { l2tp_log(LOG_WARNING, "%s: EGD Randomness source not yet implemented\n", __FUNCTION__); return -1; } else { l2tp_log(LOG_WARNING, "%s: Invalid Randomness source specified (%d)\n", __FUNCTION__, rand_source); return -1; } } xl2tpd-1.3.16/misc.h000066400000000000000000000033701374460464600141440ustar00rootroot00000000000000/* * Layer Two Tunnelling Protocol Daemon * Copyright (C) 1998 Adtran, Inc. * Copyright (C) 2002 Jeff McAdams * * Mark Spencer * * This software is distributed under the terms * of the GPL, which you should have received * along with this source. * * Misc stuff... */ #ifndef _MISC_H #define _MISC_H #include struct tunnel; struct buffer { int type; void *rstart; void *rend; void *start; size_t len; size_t maxlen; #if 0 unsigned int addr; int port; #else struct sockaddr_in peer; #endif struct tunnel *tunnel; /* Who owns this packet, if it's a control */ int retries; /* Again, if a control packet, how many retries? */ }; struct ppp_opts { char option[MAXSTRLEN]; struct ppp_opts *next; }; #define IPADDY(a) inet_ntoa(*((struct in_addr *)&(a))) #define DEBUG c ? c->debug || t->debug : t->debug #ifdef USE_SWAPS_INSTEAD #define SWAPS(a) ((((a) & 0xFF) << 8 ) | (((a) >> 8) & 0xFF)) #ifdef htons #undef htons #endif #ifdef ntohs #undef htons #endif #define htons(a) SWAPS(a) #define ntohs(a) SWAPS(a) #endif #define halt() printf("Halted.\n") ; for(;;) extern char hostname[]; extern void l2tp_log (int level, const char *fmt, ...); extern struct buffer *new_buf (int); extern void udppush_handler (int); extern int addfcs (struct buffer *buf); extern void swaps (void *, int); extern void do_packet_dump (struct buffer *); extern void status (const char *fmt, ...); extern int getPtyMaster(char *, int); extern void do_control (void); extern void recycle_buf (struct buffer *); extern void safe_copy (char *, char *, int); extern void opt_destroy (struct ppp_opts *); extern struct ppp_opts *add_opt (struct ppp_opts *, char *, ...); extern void process_signal (void); #endif xl2tpd-1.3.16/network.c000066400000000000000000000555071374460464600147060ustar00rootroot00000000000000/* * Layer Two Tunnelling Protocol Daemon * Copyright (C) 1998 Adtran, Inc. * Copyright (C) 2002 Jeff McAdams * * Mark Spencer * * This software is distributed under the terms * of the GPL, which you should have received * along with this source. * * Network routines for UDP handling */ #include #include #include #include #include #include #include #include #include #include #include #include #ifndef LINUX # include #endif #include "l2tp.h" #include "ipsecmast.h" #include "misc.h" /* for IPADDY macro */ char hostname[256]; struct sockaddr_in server, from; /* Server and transmitter structs */ int server_socket; /* Server socket */ #ifdef USE_KERNEL int kernel_support; /* Kernel Support there or not? */ #endif int init_network (void) { long arg; unsigned int length = sizeof (server); gethostname (hostname, sizeof (hostname)); server.sin_family = AF_INET; server.sin_addr.s_addr = gconfig.listenaddr; server.sin_port = htons (gconfig.port); int flags; if ((server_socket = socket (PF_INET, SOCK_DGRAM, 0)) < 0) { l2tp_log (LOG_CRIT, "%s: Unable to allocate socket. Terminating.\n", __FUNCTION__); return -EINVAL; }; flags = 1; setsockopt(server_socket, SOL_SOCKET, SO_REUSEADDR, &flags, sizeof(flags)); #ifdef SO_NO_CHECK setsockopt(server_socket, SOL_SOCKET, SO_NO_CHECK, &flags, sizeof(flags)); #endif if (bind (server_socket, (struct sockaddr *) &server, sizeof (server))) { close (server_socket); l2tp_log (LOG_CRIT, "%s: Unable to bind socket: %s. Terminating.\n", __FUNCTION__, strerror(errno), errno); return -EINVAL; }; if (getsockname (server_socket, (struct sockaddr *) &server, &length)) { close (server_socket); l2tp_log (LOG_CRIT, "%s: Unable to read socket name.Terminating.\n", __FUNCTION__); return -EINVAL; } #ifdef LINUX /* * For L2TP/IPsec with KLIPSng, set the socket to receive IPsec REFINFO * values. */ if (!gconfig.ipsecsaref) { l2tp_log (LOG_INFO, "Not looking for kernel SAref support.\n"); } else { arg=1; if(setsockopt(server_socket, IPPROTO_IP, gconfig.sarefnum, &arg, sizeof(arg)) != 0 && !gconfig.forceuserspace) { l2tp_log(LOG_CRIT, "setsockopt recvref[%d]: %s\n", gconfig.sarefnum, strerror(errno)); gconfig.ipsecsaref=0; } arg=1; if(setsockopt(server_socket, IPPROTO_IP, IP_PKTINFO, (char*)&arg, sizeof(arg)) != 0) { l2tp_log(LOG_CRIT, "setsockopt IP_PKTINFO: %s\n", strerror(errno)); } } #else l2tp_log(LOG_INFO, "No attempt being made to use IPsec SAref's since we're not on a Linux machine.\n"); #endif #ifdef USE_KERNEL if (gconfig.forceuserspace) { l2tp_log (LOG_INFO, "Not looking for kernel support.\n"); kernel_support = 0; } else { int kernel_fd = socket(AF_PPPOX, SOCK_DGRAM, PX_PROTO_OL2TP); if (kernel_fd < 0) { close(kernel_fd); l2tp_log (LOG_INFO, "L2TP kernel support not detected (try modprobing l2tp_ppp and pppol2tp)\n"); kernel_support = 0; } else { close(kernel_fd); l2tp_log (LOG_INFO, "Using l2tp kernel support.\n"); kernel_support = -1; } } #else l2tp_log (LOG_INFO, "This binary does not support kernel L2TP.\n"); #endif arg = fcntl (server_socket, F_GETFL); arg |= O_NONBLOCK; fcntl (server_socket, F_SETFL, arg); gconfig.port = ntohs (server.sin_port); return 0; } static inline void extract (void *buf, int *tunnel, int *call) { /* * Extract the tunnel and call #'s, and fix the order of the * version */ struct payload_hdr *p = (struct payload_hdr *) buf; if (PLBIT (p->ver)) { *tunnel = p->tid; *call = p->cid; } else { *tunnel = p->length; *call = p->tid; } } static inline void fix_hdr (void *buf) { /* * Fix the byte order of the header */ struct payload_hdr *p = (struct payload_hdr *) buf; _u16 ver = ntohs (p->ver); if (CTBIT (p->ver)) { /* * Control headers are always * exactly 12 bytes big. */ swaps (buf, 12); } else { int len = 6; if (PSBIT (ver)) len += 2; if (PLBIT (ver)) len += 2; if (PFBIT (ver)) len += 4; swaps (buf, len); } } void dethrottle (void *call) { UNUSED(call); /* struct call *c = (struct call *)call; */ /* if (c->throttle) { #ifdef DEBUG_FLOW log(LOG_DEBUG, "%s: dethrottling call %d, and setting R-bit\n",__FUNCTION__,c->ourcid); #endif c->rbit = RBIT; c->throttle = 0; } else { log(LOG_DEBUG, "%s: call %d already dethrottled?\n",__FUNCTION__,c->ourcid); } */ } void control_xmit (void *b) { struct buffer *buf = (struct buffer *) b; struct tunnel *t; struct timeval tv; int ns; if (!buf) { l2tp_log (LOG_WARNING, "%s: called on NULL buffer!\n", __FUNCTION__); return; } t = buf->tunnel; #ifdef DEBUG_CONTROL_XMIT if(t) { l2tp_log (LOG_DEBUG, "trying to send control packet to %d\n", t->ourtid); } #endif buf->retries++; ns = ntohs (((struct control_hdr *) (buf->start))->Ns); if (t) { if (ns < t->cLr) { #ifdef DEBUG_CONTROL_XMIT l2tp_log (LOG_DEBUG, "%s: Tossing packet %d\n", __FUNCTION__, ns); #endif /* Okay, it's been received. Let's toss it now */ toss (buf); return; } } if (buf->retries > gconfig.max_retries) { /* * Too many retries. Either kill the tunnel, or * if there is no tunnel, just stop retransmitting. */ if (t) { if (t->self->needclose) { l2tp_log (LOG_DEBUG, "Unable to deliver closing message for tunnel %d. Destroying anyway.\n", t->ourtid); t->self->needclose = 0; t->self->closing = -1; } else { l2tp_log (LOG_NOTICE, "Maximum retries exceeded for tunnel %d. Closing.\n", t->ourtid); strcpy (t->self->errormsg, "Timeout"); t->self->needclose = -1; } call_close(t->self); } toss (buf); } else { /* * Adaptive timeout with exponential backoff. The delay grows * exponentialy, unless it's capped by configuration. */ unsigned shift_by = (buf->retries-1); if (shift_by > 31) shift_by = 31; tv.tv_sec = 1LL << shift_by; tv.tv_usec = 0; schedule (tv, control_xmit, buf); #ifdef DEBUG_CONTROL_XMIT l2tp_log (LOG_DEBUG, "%s: Scheduling and transmitting packet %d\n", __FUNCTION__, ns); #endif udp_xmit (buf, t); } } unsigned char* get_inner_tos_byte (struct buffer *buf) { int tos_offset = 10; unsigned char *tos_byte = buf->start+tos_offset; return tos_byte; } unsigned char* get_inner_ppp_type (struct buffer *buf) { int ppp_type_offset = 8; unsigned char *ppp_type_byte = buf->start+ppp_type_offset; return ppp_type_byte; } void udp_xmit (struct buffer *buf, struct tunnel *t) { struct cmsghdr *cmsg = NULL; char cbuf[CMSG_SPACE(sizeof (unsigned int) + sizeof (struct in_pktinfo))]; unsigned int *refp; struct msghdr msgh; int err; struct iovec iov; int finallen = 0; /* * OKAY, now send a packet with the right SAref values. */ memset(&msgh, 0, sizeof(struct msghdr)); msgh.msg_control = cbuf; msgh.msg_controllen = sizeof(cbuf); if (gconfig.ipsecsaref && t->refhim != IPSEC_SAREF_NULL) { cmsg = CMSG_FIRSTHDR(&msgh); cmsg->cmsg_level = IPPROTO_IP; cmsg->cmsg_type = gconfig.sarefnum; cmsg->cmsg_len = CMSG_LEN(sizeof(unsigned int)); if(gconfig.debug_network) { l2tp_log(LOG_DEBUG,"sending with saref=%d using sarefnum=%d\n", t->refhim, gconfig.sarefnum); } refp = (unsigned int *)CMSG_DATA(cmsg); *refp = t->refhim; finallen = cmsg->cmsg_len; } #ifdef LINUX if (t->my_addr.ipi_addr.s_addr){ struct in_pktinfo *pktinfo; if ( ! cmsg) { cmsg = CMSG_FIRSTHDR(&msgh); } else { cmsg = CMSG_NXTHDR(&msgh, cmsg); } cmsg->cmsg_level = IPPROTO_IP; cmsg->cmsg_type = IP_PKTINFO; cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo)); pktinfo = (struct in_pktinfo*) CMSG_DATA(cmsg); *pktinfo = t->my_addr; finallen += cmsg->cmsg_len; } #endif /* * Some OS don't like assigned buffer with zero length (e.g. OpenBSD), * some OS don't like empty buffer with non-zero length (e.g. Linux). * So make them all happy by assigning control buffer only if we really * have something there and zero both fields otherwise. */ msgh.msg_controllen = finallen; if (!finallen) msgh.msg_control = NULL; iov.iov_base = buf->start; iov.iov_len = buf->len; /* return packet from whence it came */ msgh.msg_name = &buf->peer; msgh.msg_namelen = sizeof(buf->peer); msgh.msg_iov = &iov; msgh.msg_iovlen = 1; msgh.msg_flags = 0; /* Receive one packet. */ if ((err = sendmsg(server_socket, &msgh, 0)) < 0) { l2tp_log(LOG_ERR, "udp_xmit failed to %s:%d with err=%d:%s\n", IPADDY(t->peer.sin_addr), ntohs(t->peer.sin_port), err,strerror(errno)); } } int build_fdset (fd_set *readfds) { struct tunnel *tun; struct call *call; int max = 0; tun = tunnels.head; FD_ZERO (readfds); while (tun) { if (tun->udp_fd > -1) { if (tun->udp_fd > max) max = tun->udp_fd; FD_SET (tun->udp_fd, readfds); } call = tun->call_head; while (call) { if (call->needclose ^ call->closing) { call_close (call); call = tun->call_head; if (!call) break; continue; } if (call->fd > -1) { if (!call->needclose && !call->closing) { if (call->fd > max) max = call->fd; FD_SET (call->fd, readfds); } } call = call->next; } /* Now that call fds have been collected, and checked for * closing, check if the tunnel needs to be closed too */ if (tun->self->needclose ^ tun->self->closing) { if (gconfig.debug_tunnel) l2tp_log (LOG_DEBUG, "%s: closing down tunnel %d\n", __FUNCTION__, tun->ourtid); call_close (tun->self); /* Reset the while loop * and check for NULL */ tun = tunnels.head; if (!tun) break; continue; } tun = tun->next; } FD_SET (server_socket, readfds); if (server_socket > max) max = server_socket; FD_SET (control_fd, readfds); if (control_fd > max) max = control_fd; return max; } void network_thread () { /* * We loop forever waiting on either data from the ppp drivers or from * our network socket. Control handling is no longer done here. */ struct sockaddr_in from; struct in_pktinfo to; unsigned int fromlen; int tunnel, call; /* Tunnel and call */ int recvsize; /* Length of data received */ struct buffer *buf; /* Payload buffer */ struct call *c, *sc; /* Call to send this off to */ struct tunnel *st; /* Tunnel */ fd_set readfds; /* Descriptors to watch for reading */ int max; /* Highest fd */ struct timeval tv, *ptv; /* Timeout for select */ struct msghdr msgh; struct iovec iov; char cbuf[256]; unsigned int refme, refhim; int * currentfd; int server_socket_processed; /* This one buffer can be recycled for everything except control packets */ buf = new_buf (MAX_RECV_SIZE); tunnel = 0; call = 0; for (;;) { int ret; process_signal(); max = build_fdset (&readfds); ptv = process_schedule(&tv); ret = select (max + 1, &readfds, NULL, NULL, ptv); if (ret <= 0) { if (ret == 0) { if (gconfig.debug_network) { l2tp_log (LOG_DEBUG, "%s: select timeout with max retries: %d for tunnel: %d\n", __FUNCTION__, gconfig.max_retries, tunnels.head->ourtid); } } else { if (gconfig.debug_network) { l2tp_log (LOG_DEBUG, "%s: select returned error %d (%s)\n", __FUNCTION__, errno, strerror (errno)); } } continue; } if (FD_ISSET (control_fd, &readfds)) { do_control (); } server_socket_processed = 0; currentfd = NULL; st = tunnels.head; while (st || !server_socket_processed) { if (st && (st->udp_fd == -1)) { st=st->next; continue; } if (st) { currentfd = &st->udp_fd; } else { currentfd = &server_socket; server_socket_processed = 1; } if (FD_ISSET (*currentfd, &readfds)) { /* * Okay, now we're ready for reading and processing new data. */ recycle_buf (buf); /* Reserve space for expanding payload packet headers */ buf->start += PAYLOAD_BUF; buf->len -= PAYLOAD_BUF; memset(&from, 0, sizeof(from)); memset(&to, 0, sizeof(to)); fromlen = sizeof(from); memset(&msgh, 0, sizeof(struct msghdr)); iov.iov_base = buf->start; iov.iov_len = buf->len; msgh.msg_control = cbuf; msgh.msg_controllen = sizeof(cbuf); msgh.msg_name = &from; msgh.msg_namelen = fromlen; msgh.msg_iov = &iov; msgh.msg_iovlen = 1; msgh.msg_flags = 0; /* Receive one packet. */ recvsize = recvmsg(*currentfd, &msgh, 0); if (recvsize < MIN_PAYLOAD_HDR_LEN) { if (recvsize < 0) { if (errno == ECONNREFUSED) { close(*currentfd); } if ((errno == ECONNREFUSED) || (errno == EBADF)) { *currentfd = -1; } if (errno != EAGAIN) l2tp_log (LOG_WARNING, "%s: recvfrom returned error %d (%s)\n", __FUNCTION__, errno, strerror (errno)); } else { l2tp_log (LOG_WARNING, "%s: received too small a packet\n", __FUNCTION__); } if (st) st=st->next; continue; } refme=refhim=0; struct cmsghdr *cmsg; /* Process auxiliary received data in msgh */ for (cmsg = CMSG_FIRSTHDR(&msgh); cmsg != NULL; cmsg = CMSG_NXTHDR(&msgh,cmsg)) { #ifdef LINUX /* extract destination(our) addr */ if (cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_PKTINFO) { struct in_pktinfo* pktInfo = ((struct in_pktinfo*)CMSG_DATA(cmsg)); to = *pktInfo; } else #endif /* extract IPsec info out */ if (gconfig.ipsecsaref && cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == gconfig.sarefnum) { unsigned int *refp; refp = (unsigned int *)CMSG_DATA(cmsg); refme =refp[0]; refhim=refp[1]; } } /* * some logic could be added here to verify that we only * get L2TP packets inside of IPsec, or to provide different * classes of service to packets not inside of IPsec. */ buf->len = recvsize; fix_hdr (buf->start); extract (buf->start, &tunnel, &call); if (gconfig.debug_network) { l2tp_log(LOG_DEBUG, "%s: recv packet from %s, size = %d, " "tunnel = %d, call = %d ref=%u refhim=%u\n", __FUNCTION__, inet_ntoa (from.sin_addr), recvsize, tunnel, call, refme, refhim); } if (gconfig.packet_dump) { do_packet_dump (buf); } if (!(c = get_call (tunnel, call, from.sin_addr, from.sin_port, refme, refhim))) { if ((c = get_tunnel (tunnel, from.sin_addr.s_addr, from.sin_port))) { /* * It is theoretically possible that we could be sent * a control message (say a StopCCN) on a call that we * have already closed or some such nonsense. To * prevent this from closing the tunnel, if we get a * call on a valid tunnel, but not with a valid CID, * we'll just send a ZLB to ACK receiving the packet. */ if (gconfig.debug_tunnel) l2tp_log (LOG_DEBUG, "%s: no such call %d on tunnel %d. Sending special ZLB\n", __FUNCTION__, call, tunnel); if(1==handle_special (buf, c, call)) { buf = new_buf (MAX_RECV_SIZE); } } else l2tp_log (LOG_DEBUG, "%s: unable to find call or tunnel to handle packet. call = %d, tunnel = %d Dumping.\n", __FUNCTION__, call, tunnel); } else { if (c->container) { c->container->my_addr = to; } buf->peer = from; /* Handle the packet */ c->container->chal_us.vector = NULL; if (handle_packet (buf, c->container, c)) { if (gconfig.debug_tunnel) l2tp_log (LOG_DEBUG, "%s: bad packet\n", __FUNCTION__); } if (c->cnu) { /* Send Zero Byte Packet */ control_zlb (buf, c->container, c); c->cnu = 0; } } } if (st) st=st->next; } /* * finished obvious sources, look for data from PPP connections. */ for (st = tunnels.head; st; st = st->next) { for (sc = st->call_head; sc; sc = sc->next) { if ((sc->fd < 0) || !FD_ISSET (sc->fd, &readfds)) continue; /* Got some payload to send */ int result; while ((result = read_packet (sc)) > 0) { add_payload_hdr (sc->container, sc, sc->ppp_buf); if (gconfig.packet_dump) { do_packet_dump (sc->ppp_buf); } sc->prx = sc->data_rec_seq_num; if (sc->zlb_xmit) { deschedule (sc->zlb_xmit); sc->zlb_xmit = NULL; } sc->tx_bytes += sc->ppp_buf->len; sc->tx_pkts++; unsigned char* tosval = get_inner_tos_byte(sc->ppp_buf); unsigned char* typeval = get_inner_ppp_type(sc->ppp_buf); int tosval_dec = (int)*tosval; int typeval_dec = (int)*typeval; if (typeval_dec != 33 ) tosval_dec=atoi(gconfig.controltos); setsockopt(server_socket, IPPROTO_IP, IP_TOS, &tosval_dec, sizeof(tosval_dec)); udp_xmit (sc->ppp_buf, st); recycle_payload (sc->ppp_buf, sc->container->peer); } if (result != 0) { l2tp_log (LOG_WARNING, "%s: tossing read packet, error = %s (%d). Closing call.\n", __FUNCTION__, strerror (-result), -result); strcpy (sc->errormsg, strerror (-result)); sc->needclose = -1; } } // for (sc.. } // for (st.. } } #ifdef USE_KERNEL int connect_pppol2tp(struct tunnel *t) { if (!kernel_support) return 0; int ufd = -1, fd2 = -1; int flags; struct sockaddr_pppol2tp sax; struct sockaddr_in server; memset(&server, 0, sizeof(struct sockaddr_in)); server.sin_family = AF_INET; server.sin_addr.s_addr = gconfig.listenaddr; server.sin_port = htons (gconfig.port); if ((ufd = socket (PF_INET, SOCK_DGRAM, 0)) < 0) { l2tp_log (LOG_CRIT, "%s: Unable to allocate UDP socket. Terminating.\n", __FUNCTION__); return -EINVAL; }; flags=1; setsockopt(ufd, SOL_SOCKET, SO_REUSEADDR, &flags, sizeof(flags)); #ifdef SO_NO_CHECK setsockopt(ufd, SOL_SOCKET, SO_NO_CHECK, &flags, sizeof(flags)); #endif if (bind (ufd, (struct sockaddr *) &server, sizeof (server))) { close (ufd); l2tp_log (LOG_CRIT, "%s: Unable to bind UDP socket: %s. Terminating.\n", __FUNCTION__, strerror(errno), errno); return -EINVAL; }; server = t->peer; flags = fcntl(ufd, F_GETFL); if (flags == -1 || fcntl(ufd, F_SETFL, flags | O_NONBLOCK) == -1) { l2tp_log (LOG_WARNING, "%s: Unable to set UDP socket nonblock.\n", __FUNCTION__); return -EINVAL; } if (connect (ufd, (struct sockaddr *) &server, sizeof(server)) < 0) { l2tp_log (LOG_CRIT, "%s: Unable to connect UDP peer. Terminating.\n", __FUNCTION__); close(ufd); return -EINVAL; } t->udp_fd=ufd; fd2 = socket(AF_PPPOX, SOCK_DGRAM, PX_PROTO_OL2TP); if (fd2 < 0) { l2tp_log (LOG_WARNING, "%s: Unable to allocate PPPoL2TP socket.\n", __FUNCTION__); return -EINVAL; } flags = fcntl(fd2, F_GETFL); if (flags == -1 || fcntl(fd2, F_SETFL, flags | O_NONBLOCK) == -1) { l2tp_log (LOG_WARNING, "%s: Unable to set PPPoL2TP socket nonblock.\n", __FUNCTION__); close(fd2); return -EINVAL; } memset(&sax, 0, sizeof(sax)); sax.sa_family = AF_PPPOX; sax.sa_protocol = PX_PROTO_OL2TP; sax.pppol2tp.fd = t->udp_fd; sax.pppol2tp.addr.sin_addr.s_addr = t->peer.sin_addr.s_addr; sax.pppol2tp.addr.sin_port = t->peer.sin_port; sax.pppol2tp.addr.sin_family = AF_INET; sax.pppol2tp.s_tunnel = t->ourtid; sax.pppol2tp.d_tunnel = t->tid; if ((connect(fd2, (struct sockaddr *)&sax, sizeof(sax))) < 0) { l2tp_log (LOG_WARNING, "%s: Unable to connect PPPoL2TP socket. %d %s\n", __FUNCTION__, errno, strerror(errno)); close(fd2); return -EINVAL; } t->pppox_fd = fd2; return 0; } #endif xl2tpd-1.3.16/osport.h000066400000000000000000000026131374460464600145360ustar00rootroot00000000000000/* * Layer Two Tunnelling Protocol Daemon * Copyright (C) 1998 Adtran, Inc. * Copyright (C) 2002 Jeff McAdams * * Mark Spencer * * This software is distributed under the terms * of the GPL, which you should have received * along with this source. * * OS Portability header file. try to map some * "standard" routines into OS-specific routines. * */ #ifndef _OSPORT_H_ #define _OSPORT_H_ #if defined(SOLARIS) # define index(x, y) strchr(x, y) # define bcopy(S1, S2, LEN) ((void)memmove(S2, S1, LEN)) # define bzero(S1, LEN) ((void)memset(S1, 0, LEN)) # define bcmp(S1,S2,LEN) ((memcmp(S2, S1, LEN)==0)?0:1) /* pre 2.6 solaris didn't include random(), etc prototypes * (as of 2.6) has the correct prototypes. */ # if SOLARIS < 260 # define random(X) ((int)rand(X)) # define srandom(X) ((void)srand(X)) # endif /* SOLARIS < 260 */ #endif /* defined(SOLARIS) */ #if !defined(LINUX) /* Declare empty structure to make code portable and keep simple */ struct in_pktinfo { }; #endif #if defined __UCLIBC__ && !defined UCLIBC_SUSV3_LEGACY_MACROS # define index(x, y) strchr(x, y) # define bcopy(S1, S2, LEN) ((void)memmove(S2, S1, LEN)) # define bzero(S1, LEN) ((void)memset(S1, 0, LEN)) # define bcmp(S1,S2,LEN) ((memcmp(S2, S1, LEN)==0)?0:1) #endif /* defined __UCLIBC__ && !defined UCLIBC_SUSV3_LEGACY_MACROS */ #endif /* _OSPORT_H_ */ xl2tpd-1.3.16/packaging/000077500000000000000000000000001374460464600147615ustar00rootroot00000000000000xl2tpd-1.3.16/packaging/fedora/000077500000000000000000000000001374460464600162215ustar00rootroot00000000000000xl2tpd-1.3.16/packaging/fedora/xl2tpd.init000066400000000000000000000035341374460464600203300ustar00rootroot00000000000000#!/bin/sh # # xl2tpd This shell script takes care of starting and stopping l2tpd. # # chkconfig: - 80 30 # description: Layer 2 Tunnelling Protocol Daemon (RFC 2661) # # processname: /usr/sbin/xl2tpd # config: /etc/xl2tpd/xl2tpd.conf # pidfile: /var/run/xl2tpd.pid ### BEGIN INIT INFO # Provides: xl2tpd # Required-Start: $local_fs $network $syslog # Required-Stop: $local_fs $network $syslog # Default-Start: # Default-Stop: 0 1 2 3 4 5 6 # Short-Description: start|stop|status|restart|try-restart|reload|force-reload xl2tpd server # Description: control xl2tpd server ### END INIT INFO #Servicename SERVICE=xl2tpd PATHTOSERV=/usr/sbin/ # Source function library. . /etc/rc.d/init.d/functions # Source networking configuration. . /etc/sysconfig/network if [ "${NETWORKING}" = "no" ] then echo -n "No Networking" exit 0 fi if [ ! -x $PATHTOSERV$SERVICE ] then echo -n "No bin $SERVICE found, try to find auto" SERVICE=$(find / -name $SERVICE | grep bin) if [ ! -x $SERVICE ] then echo -n "No bin $SERVICE auto found, please check this" exit 0 fi else SERVICE=$PATHTOSERV$SERVICE fi RETVAL=0 start() { echo -n "Starting $SERVICE: " if [ ! -d /var/run/xl2tpd ] then mkdir /var/run/xl2tpd fi daemon $SERVICE RETVAL=$? echo if [ $RETVAL -eq 0 ];then touch /var/lock/subsys/$SERVICE else exit 7; fi return 0; } stop() { echo -n "Stopping $SERVICE: " killproc $SERVICE RETVAL=$? if [ $RETVAL -eq 0 ]; then rm -f /var/run/xl2tpd/$SERVICE rm -f /var/lock/subsys/$SERVICE fi echo return $RETVAL } restart() { stop start } # See how we were called. case "$1" in start) start ;; stop) stop ;; status) status $SERVICE RETVAL=$? ;; restart|reload) restart ;; condrestart) [ -f /var/lock/subsys/$SERVICE ] && restart || : ;; *) echo "Usage: $SERVICE {start|stop|status|restart|reload|condrestart}" exit 1 esac xl2tpd-1.3.16/packaging/fedora/xl2tpd.spec000066400000000000000000000311161374460464600203140ustar00rootroot00000000000000Summary: Layer 2 Tunnelling Protocol Daemon (RFC 2661) Name: xl2tpd Version: 1.3.16 Release: 1%{?dist} License: GPLv2 Url: http://www.xelerance.com/software/xl2tpd/ Group: System Environment/Daemons Source0: https://github.com/xelerance/xl2tpd/archive/v%{version}.tar.gz BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) Requires: ppp BuildRequires: kernel-headers => 2.6.23 %if 0%{?el3}%{?el4} BuildRequires: libpcap %else BuildRequires: libpcap-devel %endif Obsoletes: l2tpd <= 0.69-0.6.20051030.fc6 Provides: l2tpd = 0.69-0.6.20051030.fc7 Requires(post): /sbin/chkconfig Requires(preun): /sbin/chkconfig Requires(preun): /sbin/service %description xl2tpd is an implementation of the Layer 2 Tunnelling Protocol (RFC 2661). L2TP allows you to tunnel PPP over UDP. Some ISPs use L2TP to tunnel user sessions from dial-in servers (modem banks, ADSL DSLAMs) to back-end PPP servers. Another important application is Virtual Private Networks where the IPsec protocol is used to secure the L2TP connection (L2TP/IPsec, RFC 3193). The L2TP/IPsec protocol is mainly used by Windows and Mac OS X clients. On Linux, xl2tpd can be used in combination with IPsec implementations such as Openswan. Example configuration files for such a setup are included in this RPM. xl2tpd works by opening a pseudo-tty for communicating with pppd. It runs completely in userspace but supports kernel mode L2TP. xl2tpd supports IPsec SA Reference tracking to enable overlapping internak NAT'ed IP's by different clients (eg all clients connecting from their linksys internal IP 192.168.1.101) as well as multiple clients behind the same NAT router. xl2tpd supports the pppol2tp kernel mode operations on 2.6.23 or higher, or via a patch in contrib for 2.4.x kernels. Xl2tpd is based on the 0.69 L2TP by Jeff McAdams It was de-facto maintained by Jacco de Leeuw in 2002 and 2003. %prep %setup -q %build # Customer test case proved the first make line failed, the second one worked # the failing one had incoming l2tp packets, but never got a tunnel up. #make DFLAGS="$RPM_OPT_FLAGS -g -DDEBUG_PPPD -DDEBUG_CONTROL -DDEBUG_ENTROPY" make DFLAGS="-g -DDEBUG_HELLO -DDEBUG_CLOSE -DDEBUG_FLOW -DDEBUG_PAYLOAD -DDEBUG_CONTROL -DDEBUG_CONTROL_XMIT -DDEBUG_FLOW_MORE -DDEBUG_MAGIC -DDEBUG_ENTROPY -DDEBUG_HIDDEN -DDEBUG_PPPD -DDEBUG_AAA -DDEBUG_FILE -DDEBUG_FLOW -DDEBUG_HELLO -DDEBUG_CLOSE -DDEBUG_ZLB -DDEBUG_AUTH" %install rm -rf %{buildroot} make DESTDIR=%{buildroot} PREFIX=%{_prefix} install install -p -D -m644 examples/xl2tpd.conf %{buildroot}%{_sysconfdir}/xl2tpd/xl2tpd.conf install -p -D -m644 examples/ppp-options.xl2tpd %{buildroot}%{_sysconfdir}/ppp/options.xl2tpd install -p -D -m600 doc/l2tp-secrets.sample %{buildroot}%{_sysconfdir}/xl2tpd/l2tp-secrets install -p -D -m600 examples/chapsecrets.sample %{buildroot}%{_sysconfdir}/ppp/chap-secrets.sample install -p -D -m755 packaging/fedora/xl2tpd.init %{buildroot}%{_initrddir}/xl2tpd install -p -D -m755 -d %{buildroot}%{_localstatedir}/run/xl2tpd %clean rm -rf %{buildroot} %post /sbin/chkconfig --add xl2tpd # if we migrate from l2tpd to xl2tpd, copy the configs if [ -f /etc/l2tpd/l2tpd.conf ] then echo "Old /etc/l2tpd configuration found, migrating to /etc/xl2tpd" mv /etc/xl2tpd/xl2tpd.conf /etc/xl2tpd/xl2tpd.conf.rpmsave cat /etc/l2tpd/l2tpd.conf | sed "s/options.l2tpd/options.xl2tpd/" > /etc/xl2tpd/xl2tpd.conf mv /etc/ppp/options.xl2tpd /etc/ppp/options.xl2tpd.rpmsave mv /etc/ppp/options.l2tpd /etc/ppp/options.xl2tpd mv /etc/xl2tpd/l2tp-secrets /etc/xl2tpd/l2tpd-secrets.rpmsave cp -pa /etc/l2tpd/l2tp-secrets /etc/xl2tpd/l2tp-secrets fi %preun if [ $1 -eq 0 ]; then /sbin/service xl2tpd stop > /dev/null 2>&1 /sbin/chkconfig --del xl2tpd fi %postun if [ $1 -ge 1 ]; then /sbin/service xl2tpd condrestart 2>&1 >/dev/null fi %files %defattr(-,root,root) %doc BUGS CHANGES CREDITS LICENSE README.* TODO %doc doc/README.patents examples/chapsecrets.sample %attr(0755,root,root) %{_sbindir}/xl2tpd %attr(0755,root,root) %{_sbindir}/xl2tpd-control %attr(0755,root,root) %{_bindir}/pfc %{_mandir}/*/* %dir %{_sysconfdir}/xl2tpd %config(noreplace) %{_sysconfdir}/xl2tpd/* %config(noreplace) %{_sysconfdir}/ppp/* %attr(0755,root,root) %{_initrddir}/xl2tpd %dir %{_localstatedir}/run/xl2tpd %ghost %attr(0600,root,root) %{_localstatedir}/run/xl2tpd/l2tp-control %changelog * Sun Oct 26 2008 Paul Wouters 1.2.2-1 - Updated Suse init scripts and spec file - Added pfc for pppd's precompiled-active-filter * Tue Jun 26 2007 Paul Wouters 1.1.11-1 - Minor changes to spec file to accomodate new README files * Fri Feb 23 2007 Paul Wouters 1.1.08-1 - Upgraded to 1.1.08 - This works around the ppp-2.4.2-6.4 issue of not dying on SIGTERM * Mon Feb 19 2007 Paul Wouters 1.1.07-2 - Upgraded to 1.1.07 - Fixes from Tuomo Soini for pidfile handling with Fedora - Fix hardcoded version for Source in spec file. * Thu Dec 7 2006 Paul Wouters 1.1.06-5 - Changed space/tab replacing method * Wed Dec 6 2006 Paul Wouters 1.1.06-4 - Added -p to keep original timestamps - Added temporary hack to change space/tab in init file. - Added /sbin/service dependancy * Tue Dec 5 2006 Paul Wouters 1.1.06-3 - Added Requires(post) / Requires(preun) - changed init file to create /var/run/xl2tpd fixed a tab/space - changed control file to be within /var/run/xl2tpd/ * Tue Dec 5 2006 Paul Wouters 1.1.06-2 - Changed Mr. Karlsen's name to not be a utf8 problem - Fixed Obosoletes/Provides to be more specific wrt l2tpd. - Added dist tag which accidentally got deleted. * Mon Dec 4 2006 Paul Wouters 1.1.06-1 - Rebased spec file on Fedora Extras copy, but using xl2tpd as package name * Sun Nov 27 2005 Paul Wouters 0.69.20051030 - Pulled up sourceforget.net CVS fixes. - various debugging added, but debugging should not be on by default. - async/sync conversion routines must be ready for possibility that the read will block due to routing loops. - refactor control socket handling. - move all logic about pty usage to pty.c. Try ptmx first, if it fails try legacy ptys - rename log() to l2tp_log(), as "log" is a math function. - if we aren't deamonized, then log to stderr. - added install: and DESTDIR support. * Thu Oct 20 2005 Paul Wouters 0.69-13 - Removed suse/mandrake specifics. Comply for Fedora Extras guidelines * Tue Jun 21 2005 Jacco de Leeuw 0.69-12jdl - Added log() patch by Paul Wouters so that l2tpd compiles on FC4. * Sat Jun 4 2005 Jacco de Leeuw - l2tpd.org has been hijacked. Project moved back to SourceForge: http://l2tpd.sourceforge.net * Tue May 3 2005 Jacco de Leeuw - Small Makefile fixes. Explicitly use gcc instead of cc. Network services library was not linked on Solaris due to typo. * Thu Mar 17 2005 Jacco de Leeuw 0.69-11jdl - Choosing between SysV or BSD style ptys is now configurable through a compile-time boolean "unix98pty". * Fri Feb 4 2005 Jacco de Leeuw - Added code from Roaring Penguin (rp-l2tp) to support SysV-style ptys. Requires the N_HDLC kernel module. * Fri Nov 26 2004 Jacco de Leeuw - Updated the README. * Wed Nov 10 2004 Jacco de Leeuw 0.69-10jdl - Patch by Marald Klein and Roger Luethi. Fixes writing PID file. (http://l2tpd.graffl.net/msg01790.html) Long overdue. Rereleasing 10jdl. * Tue Nov 9 2004 Jacco de Leeuw 0.69-10jdl - [SECURITY FIX] Added fix from Debian because of a bss-based buffer overflow. (http://www.mail-archive.com/l2tpd-devel@l2tpd.org/msg01071.html) - Mandrake's FreeS/WAN, Openswan and Strongswan RPMS use configuration directories /etc/{freeswan,openswan,strongswan}. Install our configuration files to /etc/ipsec.d and create symbolic links in those directories. * Tue Aug 18 2004 Jacco de Leeuw - Removed 'leftnexthop=' lines. Not relevant for recent versions of FreeS/WAN and derivates. * Tue Jan 20 2004 Jacco de Leeuw 0.69-9jdl - Added "noccp" because of too much MPPE/CCP messages sometimes. * Wed Dec 31 2003 Jacco de Leeuw - Added patch in order to prevent StopCCN messages. * Sat Aug 23 2003 Jacco de Leeuw - MTU/MRU 1410 seems to be the lowest possible for MSL2TP. For Windows 2000/XP it doesn't seem to matter. - Typo in l2tpd.conf (192.168.128/25). * Fri Aug 8 2003 Jacco de Leeuw 0.69-8jdl - Added MTU/MRU 1400 to options.l2tpd. I don't know the optimal value but some apps had problems with the default value. * Fri Aug 1 2003 Jacco de Leeuw - Added workaround for the missing hostname bug in the MSL2TP client ('Specify your hostname', error 629: "You have been disconnected from the computer you are dialing"). * Thu Jul 20 2003 Jacco de Leeuw 0.69-7jdl - Added the "listen-addr" global parameter for l2tpd.conf. By default, the daemon listens on *all* interfaces. Use "listen-addr" if you want it to bind to one specific IP address (interface), for security reasons. (See also: http://www.jacco2.dds.nl/networking/freeswan-l2tp.html#Firewallwarning) - Explained in l2tpd.conf that two different IP addresses should be used for 'listen-addr' and 'local ip'. - Modified init script. Upgrades should work better now. You still need to start/chkconfig l2tpd manually. - Renamed the example Openswan .conf files to better reflect the situation. There are two variants using different portselectors. Previously I thought Windows 2000/XP used portselector 17/0 and the rest used 17/1701. But with the release of an updated IPsec client by Microsoft, it turns out that 17/0 must have been a mistake: the updated client now also uses 17/1701. * Mon Apr 10 2003 Jacco de Leeuw 0.69-6jdl - Changed sample chap-secrets to be valid only for specific IP addresses. * Thu Mar 13 2003 Bernhard Thoni - Adjustments for SuSE8.x (thanks, Bernhard!) - Added sample chap-secrets. * Thu Mar 6 2003 Jacco de Leeuw 0.69-5jdl - Replaced Dominique's patch by Damion de Soto's, which does not depend on the N_HDLC kernel module. * Wed Feb 26 2003 Jacco de Leeuw 0.69-4jdl - Seperate example config files for Win9x (MSL2TP) and Win2K/XP due to left/rightprotoport differences. Fixing preun for Red Hat. * Mon Feb 3 2003 Jacco de Leeuw 0.69-3jdl - Mandrake uses /etc/freeswan/ instead of /etc/ipsec.d/ Error fixed: source6 was used for both PSK and CERT. * Wed Jan 29 2003 Jacco de Leeuw 0.69-3jdl - Added Dominique Cressatti's pty patch in another attempt to prevent the Windows 2000 Professional "loopback detected" error. Seems to work! * Wed Dec 25 2002 Jacco de Leeuw 0.69-2jdl - Added 'connect-delay' to PPP parameters in an attempt to prevent the Windows 2000 Professional "loopback detected" error. Didn't seem to work. * Fri Dec 13 2002 Jacco de Leeuw 0.69-1jdl - Did not build on Red Hat 8.0. Solved by adding comments(?!). Bug detected in spec file: chkconfig --list l2tpd does not work on Red Hat 8.0. Not important enough to look into yet. * Sun Nov 17 2002 Jacco de Leeuw 0.69-1jdl - Tested on Red Hat, required some changes. No gprintf. Used different pty patch, otherwise wouldn't run. Added buildroot sanity check. * Sun Nov 10 2002 Jacco de Leeuw - Specfile adapted from Mandrake Cooker. The original RPM can be retrieved through: http://www.rpmfind.net/linux/rpm2html/search.php?query=l2tpd - Config path changed from /etc/l2tp/ to /etc/l2tpd/ (Seems more logical and rp-l2tp already uses /etc/l2tp/). - Do not run at boot or install. The original RPM uses a config file which is completely commented out, but it still starts l2tpd on all interfaces. Could be a security risk. This RPM does not start l2tpd, the sysadmin has to edit the config file and start l2tpd explicitly. - Renamed patches to start with l2tpd- - Added dependencies for pppd, glibc-devel. - Use %%{name} as much as possible. - l2tp-secrets contains passwords, thus should not be world readable. - Removed dependency on rpm-helper. * Mon Oct 21 2002 Lenny Cartier 0.69-3mdk - from Per 0yvind Karlsen : - PreReq and Requires - Fix preun_service * Thu Oct 17 2002 Per 0yvind Karlsen 0.69-2mdk - Move l2tpd from /usr/bin to /usr/sbin - Added SysV initscript - Patch0 - Patch1 * Thu Oct 17 2002 Per 0yvind Karlsen 0.69-1mdk - Initial release xl2tpd-1.3.16/packaging/openwrt/000077500000000000000000000000001374460464600164575ustar00rootroot00000000000000xl2tpd-1.3.16/packaging/openwrt/Config.in000066400000000000000000000003741374460464600202200ustar00rootroot00000000000000config BR2_PACKAGE_XL2TPD tristate "Xl2tpd - an L2TP daemon for use with IPsec" select BR2_PACKAGE_OPENSWAN default m if CONFIG_DEVEL help Xl2tpd is an L2TP implementation for use with IPsec http://www.xelerance.com/software/xl2tpd/ xl2tpd-1.3.16/packaging/openwrt/Makefile000066400000000000000000000027351374460464600201260ustar00rootroot00000000000000 include $(TOPDIR)/rules.mk PKG_NAME:=xl2tpd PKG_VERSION:=1.3.16 PKG_RELEASE:=1 PKG_MD5SUM:=ab5656eb5a3d1973f7f69b039675332e-NEEDSUPDATING PKG_SOURCE_URL:=http://www.xelerance.com/software/xl2tpd/ PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION) PKG_CAT:=zcat include $(TOPDIR)/package/rules.mk $(eval $(call PKG_template,XL2TPD,xl2tpd,$(PKG_VERSION)-$(PKG_RELEASE),$(ARCH))) FLAGS := $(TARGET_CFLAGS) -I$(PKG_BUILD_DIR)/linux/include -L$(STAGING_DIR)/usr/lib -I$(STAGING_DIR)/usr/include $(PKG_BUILD_DIR)/.built: $(MAKE) -C $(PKG_BUILD_DIR) \ $(TARGET_CONFIGURE_OPTS) \ ARCH="mips" \ LD_LIBRARY_PATH="$(STAGING_DIR)/usr/lib" \ EXTRA_INCLUDE="-I$(STAGING_DIR)/usr/include" \ all $(IPKG_XL2TPD): $(MAKE) -C $(PKG_BUILD_DIR) \ $(TARGET_CONFIGURE_OPTS) \ DESTDIR="$(IDIR_XL2TPD)" \ ARCH="mips" \ install -$(STRIP) $(IDIR_XL2TPD)/usr/sbin/xl2tpd rm -rf $(IDIR_XL2TPD)/usr/share rm -rf $(IDIR_XL2TPD)/usr/man rm -rf $(IDIR_XL2TPD)/var rm -rf $(IDIR_XL2TPD)/etc/rc.d/rc*.d mkdir -p $(IDIR_XL2TPD)/etc/init.d mkdir -p $(IDIR_XL2TPD)/etc/ppp mkdir -p $(IDIR_XL2TPD)/etc/xl2tpd cp $(PKG_BUILD_DIR)/examples/ppp-options.xl2tpd $(IDIR_XL2TPD)/etc/ppp/options.xl2tpd cp $(PKG_BUILD_DIR)/examples/xl2tpd.conf $(IDIR_XL2TPD)/etc/xl2tpd cp $(PKG_BUILD_DIR)/packaging/openwrt $(IDIR_XL2TPD)/etc/init.d/ find $(PKG_BUILD_DIR) -name \*.old | xargs rm -rf mkdir -p $(PACKAGE_DIR) $(IPKG_BUILD) $(IDIR_XL2TPD) $(PACKAGE_DIR) xl2tpd-1.3.16/packaging/openwrt/README000066400000000000000000000007551374460464600173460ustar00rootroot00000000000000 To (re)build xl2tpd for openwrt: cat OpenWrt-SDK-Linux-i686-1.tar.bz2 | tar -xvf - cd ~/OpenWrt-SDK-Linux-i686-1 rm -r package/helloworld svn co https://svn.openwrt.org/openwrt/branches/whiterussian whiterussian cp xl2tpd-latest.tar.gz dl/ tar zxvf dl/xl2tpd-latest.tar.gz cp -av dl/xl2tpd-latest/packaging/openwrt package/xl2tpd md5sum dl/xl2tpd-latest.tar.gz [ edit package/xl2tpd/Makefile and update PKG_VERSION and PKG_MD5SUM ] make V=99 This should then give you the xl2tpd package. xl2tpd-1.3.16/packaging/openwrt/ipkg/000077500000000000000000000000001374460464600174115ustar00rootroot00000000000000xl2tpd-1.3.16/packaging/openwrt/ipkg/xl2tpd.conffiles000066400000000000000000000000601374460464600225140ustar00rootroot00000000000000/etc/xl2tpd/xl2tpd.conf /etc/ppp/options.xl2tpd xl2tpd-1.3.16/packaging/openwrt/ipkg/xl2tpd.control000066400000000000000000000001671374460464600222340ustar00rootroot00000000000000Package: xl2tpd Section: net Priority: optional Depends: openswan Obsoletes: l2tpd Description: Xelerance Xl2tp daemon xl2tpd-1.3.16/packaging/openwrt/xl2tpd.init000077500000000000000000000003321374460464600205620ustar00rootroot00000000000000#!/bin/sh /etc/rc.common START=60 BIN=xl2tpd DEFAULT=/etc/default/$BIN RUN_D=/var/run PID_F=$RUN_D/$BIN.pid start() { [ -f $DEFAULT ] && . $DEFAULT $BIN $OPTIONS } stop() { [ -f $PID_F ] && kill $(cat $PID_F) } xl2tpd-1.3.16/packaging/suse/000077500000000000000000000000001374460464600157405ustar00rootroot00000000000000xl2tpd-1.3.16/packaging/suse/Makefile.patch000066400000000000000000000021531374460464600204770ustar00rootroot00000000000000--- ./Makefile.orig 2011-07-24 04:13:59.000000000 +0400 +++ ./Makefile 2011-10-19 05:27:27.451967117 +0400 @@ -47,13 +47,13 @@ # trust pppd. This work around will be removed in the near future. # DFLAGS= -g -DDEBUG_HELLO -DDEBUG_CLOSE -DDEBUG_FLOW -DDEBUG_PAYLOAD -DDEBUG_CONTROL -DDEBUG_CONTROL_XMIT -DDEBUG_FLOW_MORE -DDEBUG_MAGIC -DDEBUG_ENTROPY -DDEBUG_HIDDEN -DDEBUG_PPPD -DDEBUG_AAA -DDEBUG_FILE -DDEBUG_FLOW -DDEBUG_HELLO -DDEBUG_CLOSE -DDEBUG_ZLB -DDEBUG_AUTH -DFLAGS?= -DDEBUG_PPPD -DTRUST_PPPD_TO_DIE +#DFLAGS?= -DDEBUG_PPPD -DTRUST_PPPD_TO_DIE # Uncomment the next line for Linux. KERNELSRC is needed for if_pppol2tp.h, # but we use a local copy if we don't find it. # -#KERNELSRC=/lib/modules/`uname -r`/build/ -KERNELSRC?=./linux +KERNELSRC=/lib/modules/`uname -r`/build/ +#KERNELSRC?=./linux OSFLAGS?= -DLINUX -I$(KERNELSRC)/include/ # # Uncomment the following to use the kernel interface under Linux @@ -99,7 +99,7 @@ EXEC=xl2tpd CONTROL_EXEC=xl2tpd-control -PREFIX?=/usr/local +PREFIX?=/usr SBINDIR?=$(DESTDIR)${PREFIX}/sbin BINDIR?=$(DESTDIR)${PREFIX}/bin MANDIR?=$(DESTDIR)${PREFIX}/share/man xl2tpd-1.3.16/packaging/suse/README000066400000000000000000000002411374460464600166150ustar00rootroot00000000000000These files can be used to build openSUSE/SLE packages by using Open Build Service (standard system to build packages used by openSUSE project and SUSE itself). xl2tpd-1.3.16/packaging/suse/sles10.spec000066400000000000000000000300231374460464600177210ustar00rootroot00000000000000Summary: Layer 2 Tunnelling Protocol Daemon (RFC 2661) Name: xl2tpd Version: 1.3.16 Release: 1%{?dist} License: GPLv2 Url: http://www.xelerance.com/software/xl2tpd/ Group: Productivity/Networking/Other Source0: https://github.com/xelerance/xl2tpd/archive/v%{version}.tar.gz BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) Requires: ppp >= 2.4.3 BuildRequires: libpcap Obsoletes: l2tpd < 0.69 Provides: l2tpd = 0.69 Requires(post): /sbin/chkconfig Requires(preun): /sbin/chkconfig Requires(preun): /sbin/service %description xl2tpd is an implementation of the Layer 2 Tunnelling Protocol (RFC 2661). L2TP allows you to tunnel PPP over UDP. Some ISPs use L2TP to tunnel user sessions from dial-in servers (modem banks, ADSL DSLAMs) to back-end PPP servers. Another important application is Virtual Private Networks where the IPsec protocol is used to secure the L2TP connection (L2TP/IPsec, RFC 3193). The L2TP/IPsec protocol is mainly used by Windows and Mac OS X clients. On Linux, xl2tpd can be used in combination with IPsec implementations such as Openswan. Example configuration files for such a setup are included in this RPM. xl2tpd works by opening a pseudo-tty for communicating with pppd. It runs completely in userspace but supports kernel mode L2TP. xl2tpd supports IPsec SA Reference tracking to enable overlapping internak NAT'ed IP's by different clients (eg all clients connecting from their linksys internal IP 192.168.1.101) as well as multiple clients behind the same NAT router. xl2tpd supports the pppol2tp kernel mode operations on 2.6.23 or higher, or via a patch in contrib for 2.4.x kernels. Xl2tpd is based on the 0.69 L2TP by Jeff McAdams It was de-facto maintained by Jacco de Leeuw in 2002 and 2003. %prep %setup -q %build make DFLAGS="$RPM_OPT_FLAGS -g -DDEBUG_PPPD -DDEBUG_CONTROL -DDEBUG_ENTROPY -DTRUST_PPPD_TO_DIE" %install make PREFIX=%{_prefix} DESTDIR=%{buildroot} MANDIR=%{buildroot}/%{_mandir} install install -p -D -m644 examples/xl2tpd.conf %{buildroot}%{_sysconfdir}/xl2tpd/xl2tpd.conf install -p -D -m644 examples/ppp-options.xl2tpd %{buildroot}%{_sysconfdir}/ppp/options.xl2tpd install -p -D -m600 doc/l2tp-secrets.sample %{buildroot}%{_sysconfdir}/xl2tpd/l2tp-secrets install -p -D -m600 examples/chapsecrets.sample %{buildroot}%{_sysconfdir}/ppp/chap-secrets.sample install -p -D -m755 packaging/suse/xl2tpd.init %{buildroot}%{_initrddir}/xl2tpd ln -sf /etc/init.d/xl2tpd $RPM_BUILD_ROOT/usr/sbin/rcxl2tpd install -p -D -m755 -d %{buildroot}%{_localstatedir}/run/xl2tpd %clean rm -rf %{buildroot} %post %{fillup_and_insserv xl2tpd} # if we migrate from l2tpd to xl2tpd, copy the configs if [ -f /etc/l2tpd/l2tpd.conf ] then echo "Old /etc/l2tpd configuration found, migrating to /etc/xl2tpd" mv /etc/xl2tpd/xl2tpd.conf /etc/xl2tpd/xl2tpd.conf.rpmsave cat /etc/l2tpd/l2tpd.conf | sed "s/options.l2tpd/options.xl2tpd/" > /etc/xl2tpd/xl2tpd.conf mv /etc/ppp/options.xl2tpd /etc/ppp/options.xl2tpd.rpmsave mv /etc/ppp/options.l2tpd /etc/ppp/options.xl2tpd mv /etc/xl2tpd/l2tp-secrets /etc/xl2tpd/l2tpd-secrets.rpmsave cp -pa /etc/l2tpd/l2tp-secrets /etc/xl2tpd/l2tp-secrets fi %preun %stop_on_removal xl2tpd exit 0 %postun %restart_on_update xl2tpd %insserv_cleanup exit 0 %files %defattr(-,root,root) %doc BUGS CHANGES CREDITS LICENSE README.* TODO %doc doc/README.patents examples/chapsecrets.sample %{_sbindir}/rcxl2tpd %{_sbindir}/xl2tpd %{_sbindir}/xl2tpd-control %{_bindir}/pfc %{_mandir}/*/* %dir %{_sysconfdir}/xl2tpd %config(noreplace) %{_sysconfdir}/xl2tpd/* %config(noreplace) %{_sysconfdir}/ppp/* %attr(0755,root,root) %{_initrddir}/xl2tpd %dir %{_localstatedir}/run/xl2tpd %changelog * Sun Oct 26 2008 Paul Wouters 1.2.2-1 - Updated Suse init scripts and spec file - Added pfc for pppd's precompiled-active-filter * Fri Apr 18 2008 Paul Wouters 1.2.1-1 - Updated Suse init scripts and spec file * Tue Jun 26 2007 Paul Wouters 1.1.11-1 - Minor changes to spec file to accomodate new README files * Fri Feb 23 2007 Paul Wouters 1.1.08-1 - Upgraded to 1.1.08 - This works around the ppp-2.4.2-6.4 issue of not dying on SIGTERM * Mon Feb 19 2007 Paul Wouters 1.1.07-2 - Upgraded to 1.1.07 - Fixes from Tuomo Soini for pidfile handling with Fedora - Fix hardcoded version for Source in spec file. * Thu Dec 7 2006 Paul Wouters 1.1.06-5 - Changed space/tab replacing method * Wed Dec 6 2006 Paul Wouters 1.1.06-4 - Added -p to keep original timestamps - Added temporary hack to change space/tab in init file. - Added /sbin/service dependancy * Tue Dec 5 2006 Paul Wouters 1.1.06-3 - Added Requires(post) / Requires(preun) - changed init file to create /var/run/xl2tpd fixed a tab/space - changed control file to be within /var/run/xl2tpd/ * Tue Dec 5 2006 Paul Wouters 1.1.06-2 - Changed Mr. Karlsen's name to not be a utf8 problem - Fixed Obosoletes/Provides to be more specific wrt l2tpd. - Added dist tag which accidentally got deleted. * Mon Dec 4 2006 Paul Wouters 1.1.06-1 - Rebased spec file on Fedora Extras copy, but using xl2tpd as package name * Sun Nov 27 2005 Paul Wouters 0.69.20051030 - Pulled up sourceforget.net CVS fixes. - various debugging added, but debugging should not be on by default. - async/sync conversion routines must be ready for possibility that the read will block due to routing loops. - refactor control socket handling. - move all logic about pty usage to pty.c. Try ptmx first, if it fails try legacy ptys - rename log() to l2tp_log(), as "log" is a math function. - if we aren't deamonized, then log to stderr. - added install: and DESTDIR support. * Thu Oct 20 2005 Paul Wouters 0.69-13 - Removed suse/mandrake specifics. Comply for Fedora Extras guidelines * Tue Jun 21 2005 Jacco de Leeuw 0.69-12jdl - Added log() patch by Paul Wouters so that l2tpd compiles on FC4. * Sat Jun 4 2005 Jacco de Leeuw - l2tpd.org has been hijacked. Project moved back to SourceForge: http://l2tpd.sourceforge.net * Tue May 3 2005 Jacco de Leeuw - Small Makefile fixes. Explicitly use gcc instead of cc. Network services library was not linked on Solaris due to typo. * Thu Mar 17 2005 Jacco de Leeuw 0.69-11jdl - Choosing between SysV or BSD style ptys is now configurable through a compile-time boolean "unix98pty". * Fri Feb 4 2005 Jacco de Leeuw - Added code from Roaring Penguin (rp-l2tp) to support SysV-style ptys. Requires the N_HDLC kernel module. * Fri Nov 26 2004 Jacco de Leeuw - Updated the README. * Wed Nov 10 2004 Jacco de Leeuw 0.69-10jdl - Patch by Marald Klein and Roger Luethi. Fixes writing PID file. (http://l2tpd.graffl.net/msg01790.html) Long overdue. Rereleasing 10jdl. * Tue Nov 9 2004 Jacco de Leeuw 0.69-10jdl - [SECURITY FIX] Added fix from Debian because of a bss-based buffer overflow. (http://www.mail-archive.com/l2tpd-devel@l2tpd.org/msg01071.html) - Mandrake's FreeS/WAN, Openswan and Strongswan RPMS use configuration directories /etc/{freeswan,openswan,strongswan}. Install our configuration files to /etc/ipsec.d and create symbolic links in those directories. * Tue Aug 18 2004 Jacco de Leeuw - Removed 'leftnexthop=' lines. Not relevant for recent versions of FreeS/WAN and derivates. * Tue Jan 20 2004 Jacco de Leeuw 0.69-9jdl - Added "noccp" because of too much MPPE/CCP messages sometimes. * Wed Dec 31 2003 Jacco de Leeuw - Added patch in order to prevent StopCCN messages. * Sat Aug 23 2003 Jacco de Leeuw - MTU/MRU 1410 seems to be the lowest possible for MSL2TP. For Windows 2000/XP it doesn't seem to matter. - Typo in l2tpd.conf (192.168.128/25). * Fri Aug 8 2003 Jacco de Leeuw 0.69-8jdl - Added MTU/MRU 1400 to options.l2tpd. I don't know the optimal value but some apps had problems with the default value. * Fri Aug 1 2003 Jacco de Leeuw - Added workaround for the missing hostname bug in the MSL2TP client ('Specify your hostname', error 629: "You have been disconnected from the computer you are dialing"). * Thu Jul 20 2003 Jacco de Leeuw 0.69-7jdl - Added the "listen-addr" global parameter for l2tpd.conf. By default, the daemon listens on *all* interfaces. Use "listen-addr" if you want it to bind to one specific IP address (interface), for security reasons. (See also: http://www.jacco2.dds.nl/networking/freeswan-l2tp.html#Firewallwarning) - Explained in l2tpd.conf that two different IP addresses should be used for 'listen-addr' and 'local ip'. - Modified init script. Upgrades should work better now. You still need to start/chkconfig l2tpd manually. - Renamed the example Openswan .conf files to better reflect the situation. There are two variants using different portselectors. Previously I thought Windows 2000/XP used portselector 17/0 and the rest used 17/1701. But with the release of an updated IPsec client by Microsoft, it turns out that 17/0 must have been a mistake: the updated client now also uses 17/1701. * Mon Apr 10 2003 Jacco de Leeuw 0.69-6jdl - Changed sample chap-secrets to be valid only for specific IP addresses. * Thu Mar 13 2003 Bernhard Thoni - Adjustments for SuSE8.x (thanks, Bernhard!) - Added sample chap-secrets. * Thu Mar 6 2003 Jacco de Leeuw 0.69-5jdl - Replaced Dominique's patch by Damion de Soto's, which does not depend on the N_HDLC kernel module. * Wed Feb 26 2003 Jacco de Leeuw 0.69-4jdl - Seperate example config files for Win9x (MSL2TP) and Win2K/XP due to left/rightprotoport differences. Fixing preun for Red Hat. * Mon Feb 3 2003 Jacco de Leeuw 0.69-3jdl - Mandrake uses /etc/freeswan/ instead of /etc/ipsec.d/ Error fixed: source6 was used for both PSK and CERT. * Wed Jan 29 2003 Jacco de Leeuw 0.69-3jdl - Added Dominique Cressatti's pty patch in another attempt to prevent the Windows 2000 Professional "loopback detected" error. Seems to work! * Wed Dec 25 2002 Jacco de Leeuw 0.69-2jdl - Added 'connect-delay' to PPP parameters in an attempt to prevent the Windows 2000 Professional "loopback detected" error. Didn't seem to work. * Fri Dec 13 2002 Jacco de Leeuw 0.69-1jdl - Did not build on Red Hat 8.0. Solved by adding comments(?!). Bug detected in spec file: chkconfig --list l2tpd does not work on Red Hat 8.0. Not important enough to look into yet. * Sun Nov 17 2002 Jacco de Leeuw 0.69-1jdl - Tested on Red Hat, required some changes. No gprintf. Used different pty patch, otherwise wouldn't run. Added buildroot sanity check. * Sun Nov 10 2002 Jacco de Leeuw - Specfile adapted from Mandrake Cooker. The original RPM can be retrieved through: http://www.rpmfind.net/linux/rpm2html/search.php?query=l2tpd - Config path changed from /etc/l2tp/ to /etc/l2tpd/ (Seems more logical and rp-l2tp already uses /etc/l2tp/). - Do not run at boot or install. The original RPM uses a config file which is completely commented out, but it still starts l2tpd on all interfaces. Could be a security risk. This RPM does not start l2tpd, the sysadmin has to edit the config file and start l2tpd explicitly. - Renamed patches to start with l2tpd- - Added dependencies for pppd, glibc-devel. - Use %%{name} as much as possible. - l2tp-secrets contains passwords, thus should not be world readable. - Removed dependency on rpm-helper. * Mon Oct 21 2002 Lenny Cartier 0.69-3mdk - from Per 0yvind Karlsen : - PreReq and Requires - Fix preun_service * Thu Oct 17 2002 Per 0yvind Karlsen 0.69-2mdk - Move l2tpd from /usr/bin to /usr/sbin - Added SysV initscript - Patch0 - Patch1 * Thu Oct 17 2002 Per 0yvind Karlsen 0.69-1mdk - Initial release xl2tpd-1.3.16/packaging/suse/xl2tpd.changes000066400000000000000000000412151374460464600205120ustar00rootroot00000000000000------------------------------------------------------------------- Sun Oct 13 18:22:24 UTC 2019 - Martin Hauke - Update to version 1.3.15 * Specify missing log arguments * Sockopt bug fix for multiple IP's ------------------------------------------------------------------- Wed Apr 17 17:42:30 UTC 2019 - Martin Hauke - Update to version 1.3.14 * Bugfix release, mostly code cleanup ------------------------------------------------------------------- Wed Mar 20 19:03:16 UTC 2019 - Jan Engelhardt - Drop ||true from %tmpfiles_create, this is already included in the macro. - Reduce hard dependency on systemd during build. ------------------------------------------------------------------- Fri Mar 8 20:54:23 UTC 2019 - Martin Hauke - Run spec-cleaner - Remove support for non-systemd distros - Remove -doc subpackage (contained only some KB text-files and and manpages) - Fix handling of tmpfilesdir - Update to version 1.3.13 * Fix compile warning with USE_KERNEL in xl2tpd.c * Applying patch that reduces compile warnings and fixes warnings from gcc and clang. * Fix compiler warnings in network.c * Add a preproc for Watchguard firewall (Github issue #136) * Convert from ISO-8859 to UTF-8 [Simon Deziel] Update README to provide latest info on xl2tpd + Linux kernel 4.15+ - Update to version 1.3.12 * TOS value to copy to the tunnel header * Fix for ENODEV (No such device) error with Linux kernel 4.15 * Update xl2tpd.init * fix version number and upload - Update to version 1.3.11 * only changes related to debian packaging ------------------------------------------------------------------- Thu Oct 26 12:38:37 UTC 2017 - badshah400@gmail.com - Update to version 1.3.10 * Update STRLEN in file.h to 100 (from 80). * xl2tpd-control: fix xl2tpd hanged up in "fopen". * Update version in spec and opewnrt Makefile. - Update source URL in specfile. ------------------------------------------------------------------- Thu Jun 29 15:04:34 UTC 2017 - dimstar@opensuse.org - Own /etc/ppp (mode 750, like other packages too). ------------------------------------------------------------------- Thu May 16 10:33:42 UTC 2017 - alexander_naumov@opensuse.org - Update to version 1.3.9 * Add xl2tpd-control man pages (Samir Hussain) * Update spec file with newest Soure0 and version (Samir Hussain) * Update License file (Samir Hussain) * Display PID for call in the logs (Samir Hussain) * Use left shift rather than pow() function. (Samir Hussain) * Enable Travis integration (Samir Hussain) * Remove unnecessary casting of malloc() results (Andrew Clayton) * Remove an unused line of code in init_config() (Andrew Clayton) * Fix some undefined behaviour in read_result() (Andrew Clayton) * Fix feature test macro deprecation warnings (Andrew Clayton) ------------------------------------------------------------------- Sun Apr 12 00:55:33 UTC 2015 - p.drouand@gmail.com - Update to version 1.3.6 * Fix the size of the lenght param for AVP headers. This should fix Android support no matter how the compiler optimizes. - For changes from other versions, please read the CHANGES files - Use download Url as source - Remove redundant %clean section - Remove xl2tpd-1.3.0-0001-Add-kernel-support-for-2.6.32.patch; fixed by upstream - Adapt Makefile.patch and xl2tpd.init.patch to upstream changes - Do not provide sysvinit and systemd support on the same system; it's redundant - Add backward compatibility symlinl to systemd service ------------------------------------------------------------------- Thu Jun 26 15:27:11 UTC 2014 - dvlaeev@suse.com - switch to /run on openSUSE newer than 13.1 ------------------------------------------------------------------- Wed Jan 1 21:53:05 UTC 2014 - dvlaeev@suse.com - Remove newline from description in xl2tpd.conf (bnc#856928) ------------------------------------------------------------------- Sun Mar 17 16:14:54 UTC 2013 - dvaleev@suse.com - Use /usr/lib/tmpfile.d for tmpfiles configuration ------------------------------------------------------------------- Wed Mar 6 21:15:13 YEKT 2013 - avm.xandry@gmail.com - Added /etc/tmpfiles.d/xl2tpd.conf file (bnc#807605) ------------------------------------------------------------------- Mon Nov 26 10:24:38 UTC 2012 - dvaleev@suse.com - don't use old version of if_pppol2tp.h (bnc#791109) ------------------------------------------------------------------- Wed Nov 21 06:04:50 UTC 2012 - binli@opensuse.org - xl2tpd Add kernel support for 2.6.23+ (patch v12) xl2tpd-1.3.0-0001-Add-kernel-support-for-2.6.32.patch Public Clone URL: git://gist.github.com/1306094.git (bnc#790250). ------------------------------------------------------------------- Fri Aug 31 21:45:57 UTC 2012 - crrodriguez@opensuse.org - Add systemd support. ------------------------------------------------------------------- Thu Oct 26 20:10:00 UTC 2011 - nekolayer@yandex.ru - update to xl2tpd 1.3.0 * added xl2tpd-control tool (activates/disconnects the tunnel, actions with lac configuration file) * fixed bug causing "Resource temporarily unavailable(11)" in log * fixed xl2tpd hungs and won't redial after communication fail * fixed buffer overrun in reading >16 char l2tp-secrets ------------------------------------------------------------------- Tue May 4 12:30:00 CEST 2010 - dvaleev@novell.com - fixed rpmlint dir-or-file-in-var-run ------------------------------------------------------------------- Thu Apr 22 09:23:57 UTC 2010 - aj@suse.de - Fix specfile, debug_package will get inserted automatically. - Do not use license package. ------------------------------------------------------------------- Fri Apr 16 15:01:13 CEST 2010 - eri_zaq@please-enter-an-email-address - xl2tpd-1.2.4-4 - Fix init script to stop service correctly - *.changes ------------------------------------------------------------------- Mon Mar 15 00:00:00 CET 2010 - k0da@opensuse.org - xl2tpd-1.2.4-3 - avoid a huge overload of duplicated files ------------------------------------------------------------------- Thu Mar 11 00:00:00 CET 2010 - k0da@opensuse.org - xl2tpd-1.2.4-2 - xl2tpd-doc-1.2.4-2 - *-doc package - cleanup init script ------------------------------------------------------------------- Wed Mar 10 00:00:00 CET 2010 - k0da@opensuse.org - xl2tpd-1.2.4-1 - patch for init file ------------------------------------------------------------------- Tue Oct 28 00:00:00 CET 2008 - k0da@opensuse.org - Adjust build requires ------------------------------------------------------------------- Sun Oct 26 00:00:00 CEST 2008 - paul@xelerance.com - Updated Suse init scripts and spec file - Added pfc for pppd's precompiled-active-filter ------------------------------------------------------------------- Fri Apr 18 00:00:00 CEST 2008 - paul@xelerance.com - Updated Suse init scripts and spec file ------------------------------------------------------------------- Tue Jun 26 00:00:00 CEST 2007 - paul@xelerance.com - Minor changes to spec file to accomodate new README files ------------------------------------------------------------------- Fri Feb 23 00:00:00 CET 2007 - paul@xelerance.com - Upgraded to 1.1.08 - This works around the ppp-2.4.2-6.4 issue of not dying on SIGTERM ------------------------------------------------------------------- Mon Feb 19 00:00:00 CET 2007 - paul@xelerance.com - Upgraded to 1.1.07 - Fixes from Tuomo Soini for pidfile handling with Fedora - Fix hardcoded version for Source in spec file. ------------------------------------------------------------------- Thu Dec 7 00:00:00 CET 2006 - paul@xelerance.com - Changed space/tab replacing method ------------------------------------------------------------------- Wed Dec 6 00:00:00 CET 2006 - paul@xelerance.com - Added -p to keep original timestamps - Added temporary hack to change space/tab in init file. - Added /sbin/service dependancy ------------------------------------------------------------------- Tue Dec 5 00:00:00 CET 2006 - paul@xelerance.com - Changed Mr. Karlsen's name to not be a utf8 problem - Fixed Obosoletes/Provides to be more specific wrt l2tpd. - Added dist tag which accidentally got deleted. ------------------------------------------------------------------- Mon Dec 4 00:00:00 CET 2006 - paul@xelerance.com - Rebased spec file on Fedora Extras copy, but using xl2tpd as package name ------------------------------------------------------------------- Sun Nov 27 00:00:00 CET 2005 - paul@xelerance.com - Pulled up sourceforget.net CVS fixes. - various debugging added, but debugging should not be on by default. - async/sync conversion routines must be ready for possibility that the read will block due to routing loops. - refactor control socket handling. - move all logic about pty usage to pty.c. Try ptmx first, if it fails try legacy ptys - rename log() to l2tp_log(), as "log" is a math function. - if we aren't deamonized, then log to stderr. - added install: and DESTDIR support. ------------------------------------------------------------------- Thu Oct 20 00:00:00 CEST 2005 - paul@xelerance.com - Removed suse/mandrake specifics. Comply for Fedora Extras guidelines ------------------------------------------------------------------- Tue Jun 21 00:00:00 CEST 2005 - jacco2@dds.nl - Added log() patch by Paul Wouters so that l2tpd compiles on FC4. ------------------------------------------------------------------- Sat Jun 4 00:00:00 CEST 2005 - jacco2@dds.nl - l2tpd.org has been hijacked. Project moved back to SourceForge: http://l2tpd.sourceforge.net ------------------------------------------------------------------- Tue May 3 00:00:00 CEST 2005 - jacco2@dds.nl - Small Makefile fixes. Explicitly use gcc instead of cc. Network services library was not linked on Solaris due to typo. ------------------------------------------------------------------- Thu Mar 17 00:00:00 CET 2005 - jacco2@dds.nl - Choosing between SysV or BSD style ptys is now configurable through a compile-time boolean "unix98pty". ------------------------------------------------------------------- Fri Feb 4 00:00:00 CET 2005 - jacco2@dds.nl - Added code from Roaring Penguin (rp-l2tp) to support SysV-style ptys. Requires the N_HDLC kernel module. ------------------------------------------------------------------- Fri Nov 26 00:00:00 CET 2004 - jacco2@dds.nl - Updated the README. ------------------------------------------------------------------- Wed Nov 10 00:00:00 CET 2004 - jacco2@dds.nl - Patch by Marald Klein and Roger Luethi. Fixes writing PID file. (http://l2tpd.graffl.net/msg01790.html) Long overdue. Rereleasing 10jdl. ------------------------------------------------------------------- Tue Nov 9 00:00:00 CET 2004 - jacco2@dds.nl - [SECURITY FIX] Added fix from Debian because of a bss-based buffer overflow. (http://www.mail-archive.com/l2tpd-devel@l2tpd.org/msg01071.html) - Mandrake's FreeS/WAN, Openswan and Strongswan RPMS use configuration directories /etc/{freeswan,openswan,strongswan}. Install our configuration files to /etc/ipsec.d and create symbolic links in those directories. ------------------------------------------------------------------- Wed Aug 18 00:00:00 CEST 2004 - jacco2@dds.nl - Removed 'leftnexthop=' lines. Not relevant for recent versions of FreeS/WAN and derivates. ------------------------------------------------------------------- Tue Jan 20 00:00:00 CET 2004 - jacco2@dds.nl - Added "noccp" because of too much MPPE/CCP messages sometimes. ------------------------------------------------------------------- Wed Dec 31 00:00:00 CET 2003 - jacco2@dds.nl - Added patch in order to prevent StopCCN messages. ------------------------------------------------------------------- Sat Aug 23 00:00:00 CEST 2003 - jacco2@dds.nl - MTU/MRU 1410 seems to be the lowest possible for MSL2TP. For Windows 2000/XP it doesn't seem to matter. - Typo in l2tpd.conf (192.168.128/25). ------------------------------------------------------------------- Fri Aug 8 00:00:00 CEST 2003 - jacco2@dds.nl - Added MTU/MRU 1400 to options.l2tpd. I don't know the optimal value but some apps had problems with the default value. ------------------------------------------------------------------- Fri Aug 1 00:00:00 CEST 2003 - jacco2@dds.nl - Added workaround for the missing hostname bug in the MSL2TP client ('Specify your hostname', error 629: "You have been disconnected from the computer you are dialing"). ------------------------------------------------------------------- Sun Jul 20 00:00:00 CEST 2003 - jacco2@dds.nl - Added the "listen-addr" global parameter for l2tpd.conf. By default, the daemon listens on *all* interfaces. Use "listen-addr" if you want it to bind to one specific IP address (interface), for security reasons. (See also: http://www.jacco2.dds.nl/networking/freeswan-l2tp.html#Firewallwarning) - Explained in l2tpd.conf that two different IP addresses should be used for 'listen-addr' and 'local ip'. - Modified init script. Upgrades should work better now. You still need to start/chkconfig l2tpd manually. - Renamed the example Openswan .conf files to better reflect the situation. There are two variants using different portselectors. Previously I thought Windows 2000/XP used portselector 17/0 and the rest used 17/1701. But with the release of an updated IPsec client by Microsoft, it turns out that 17/0 must have been a mistake: the updated client now also uses 17/1701. ------------------------------------------------------------------- Thu Apr 10 00:00:00 CEST 2003 - jacco2@dds.nl - Changed sample chap-secrets to be valid only for specific IP addresses. ------------------------------------------------------------------- Thu Mar 13 00:00:00 CET 2003 - tech-role@tronicplanet.de - Adjustments for SuSE8.x (thanks, Bernhard!) - Added sample chap-secrets. ------------------------------------------------------------------- Thu Mar 6 00:00:00 CET 2003 - jacco2@dds.nl - Replaced Dominique's patch by Damion de Soto's, which does not depend on the N_HDLC kernel module. ------------------------------------------------------------------- Wed Feb 26 00:00:00 CET 2003 - jacco2@dds.nl - Seperate example config files for Win9x (MSL2TP) and Win2K/XP due to left/rightprotoport differences. Fixing preun for Red Hat. ------------------------------------------------------------------- Mon Feb 3 00:00:00 CET 2003 - jacco2@dds.nl - Mandrake uses /etc/freeswan/ instead of /etc/ipsec.d/ Error fixed: source6 was used for both PSK and CERT. ------------------------------------------------------------------- Wed Jan 29 00:00:00 CET 2003 - jacco2@dds.nl - Added Dominique Cressatti's pty patch in another attempt to prevent the Windows 2000 Professional "loopback detected" error. Seems to work! ------------------------------------------------------------------- Wed Dec 25 00:00:00 CET 2002 - jacco2@dds.nl - Added 'connect-delay' to PPP parameters in an attempt to prevent the Windows 2000 Professional "loopback detected" error. Didn't seem to work. ------------------------------------------------------------------- Fri Dec 13 00:00:00 CET 2002 - jacco2@dds.nl - Did not build on Red Hat 8.0. Solved by adding comments(?!). Bug detected in spec file: chkconfig --list l2tpd does not work on Red Hat 8.0. Not important enough to look into yet. ------------------------------------------------------------------- Sun Nov 17 00:00:00 CET 2002 - jacco2@dds.nl - Tested on Red Hat, required some changes. No gprintf. Used different pty patch, otherwise wouldn't run. Added buildroot sanity check. ------------------------------------------------------------------- Sun Nov 10 00:00:00 CET 2002 - jacco2@dds.nl - Specfile adapted from Mandrake Cooker. The original RPM can be retrieved through: http://www.rpmfind.net/linux/rpm2html/search.php?query=l2tpd - Config path changed from /etc/l2tp/ to /etc/l2tpd/ (Seems more logical and rp-l2tp already uses /etc/l2tp/). - Do not run at boot or install. The original RPM uses a config file which is completely commented out, but it still starts l2tpd on all interfaces. Could be a security risk. This RPM does not start l2tpd, the sysadmin has to edit the config file and start l2tpd explicitly. - Renamed patches to start with l2tpd- - Added dependencies for pppd, glibc-devel. - Use %%{name} as much as possible. - l2tp-secrets contains passwords, thus should not be world readable. - Removed dependency on rpm-helper. ------------------------------------------------------------------- Mon Oct 21 00:00:00 CEST 2002 - lenny@mandrakesoft.com - from Per 0yvind Karlsen : - PreReq and Requires - Fix preun_service ------------------------------------------------------------------- Thu Oct 17 00:00:00 CEST 2002 - peroyvind@delonic.no - Initial release xl2tpd-1.3.16/packaging/suse/xl2tpd.init000066400000000000000000000124211374460464600200420ustar00rootroot00000000000000#! /bin/sh # Copyright (c) 1995-2003 Bernhard Thoni # Tronicplanet Datendienst GmbH, Simbach am INN, Germany. # All rights reserved. # Copyright (c) 2006-2008 Paul Wouters # Xeleracne Corporation # # /etc/init.d/xl2tpd # # and its symbolic link # # /usr/sbin/rcxl2tpd # # LSB compliant service control script; see http://www.linuxbase.org/spec/ # # System startup script for L2TP daemon xl2tpd # ### BEGIN INIT INFO # Provides: xl2tpd # Required-Start: $syslog $remote_fs # Required-Stop: $syslog $remote_fs # Default-Start: 3 5 # Default-Stop: 0 1 2 6 # Short-Description: Start xl2tpd (to provide L2TP VPN's) # Description: Start xl2tpd to provide L2TP VPN tunnels # normally used with IPsec (openswan) ### END INIT INFO # # Note on Required-Start: It does specify the init script ordering, # not real dependencies. Depencies have to be handled by admin # resp. the configuration tools (s)he uses. # Source SuSE config (if still necessary, most info has been moved) test -r /etc/rc.config && . /etc/rc.config # Check for missing binaries (stale symlinks should not happen) XL2TPD_BIN=/usr/sbin/xl2tpd test -x $YPBIND_BIN || { echo "$YPBIND_BIN not installed"; if [ "$1" = "stop" ]; then exit 0; else exit 5; fi; } # Check for existence of needed config file and read it #XL2TPD_CONFIG=/etc/sysconfig/xl2tpd #test -r $YPBIND_CONFIG || { echo "$YPBIND_CONFIG not existing"; # if [ "$1" = "stop" ]; then exit 0; else exit 6; fi; } #. $XL2TPD_CONFIG # Shell functions sourced from /etc/rc.status: # rc_check check and set local and overall rc status # rc_status check and set local and overall rc status # rc_status -v ditto but be verbose in local rc status # rc_status -v -r ditto and clear the local rc status # rc_failed set local and overall rc status to failed # rc_failed set local and overall rc status to # rc_reset clear local rc status (overall remains) # rc_exit exit appropriate to overall rc status # rc_active checks whether a service is activated by symlinks . /etc/rc.status # First reset status of this service rc_reset # Return values acc. to LSB for all commands but status: # 0 - success # 1 - generic or unspecified error # 2 - invalid or excess argument(s) # 3 - unimplemented feature (e.g. "reload") # 4 - insufficient privilege # 5 - program is not installed # 6 - program is not configured # 7 - program is not running # # Note that starting an already running service, stopping # or restarting a not-running service as well as the restart # with force-reload (in case signalling is not supported) are # considered a success. case "$1" in start) echo -n "Starting xl2tpd" ## Start daemon with startproc(8). If this fails ## the echo return value is set appropriate. # NOTE: startproc returns 0, even if service is # already running to match LSB spec. startproc $XL2TPD_BIN >/dev/null 2>&1 # Remember status and be verbose rc_status -v ;; stop) echo -n "Shutting down xl2tpd" ## Stop daemon with killproc(8) and if this fails ## set echo the echo return value. killproc -TERM $XL2TPD_BIN rm -f /var/run/xl2tpd/xl2tpd.pid # Remember status and be verbose rc_status -v ;; try-restart|condrestart) ## Do a restart only if the service was active before. ## Note: try-restart is now part of LSB (as of 1.9). ## RH has a similar command named condrestart. if test "$1" = "condrestart"; then echo "${attn} Use try-restart ${done}(LSB)${attn} rather than condrestart ${warn}(RH)${norm}" fi $0 status if test $? = 0; then $0 restart else rc_reset # Not running is not a failure. fi rc_status ;; restart) $0 stop sleep 1 $0 start rc_status ;; force-reload) ## Signal the daemon to reload its config. Most daemons ## do this on signal 1 (SIGHUP). ## If it does not support it, restart. echo -n "Reload service xl2tpd" ## if it supports it: killproc -HUP $XL2TPD_BIN #touch /var/run/xl2tpd/xl2tpd.pid rc_status -v ## Otherwise: #$0 stop && $0 start #rc_status ;; reload) ## Like force-reload, but if daemon does not support ## signalling, do nothing (!) # If it supports signalling: echo -n "Reload service xl2tpd" killproc -HUP $XL2TPD_BIN #touch /var/run/xl2tpd.pid rc_status -v ## Otherwise if it does not support reload: #rc_failed 3 #rc_status -v ;; status) echo -n "Checking for service xl2tpd: " ## Check status with checkproc(8), if process is running ## checkproc will return with exit status 0. # Return value is slightly different for the status command: # 0 - service running # 1 - service dead, but /var/run/ pid file exists # 2 - service dead, but /var/lock/ lock file exists # 3 - service not running # NOTE: checkproc returns LSB compliant status values. checkproc $XL2TPD_BIN rc_status -v ;; probe) ## Optional: Probe for the necessity of a reload, ## print out the argument which is required for a reload. test /etc/xl2tpd/xl2tpd.conf -nt /var/run/xltpd/xl2tpd.pid && echo reload ;; *) echo "Usage: $0 {start|stop|status|try-restart|restart|force-reload|reload|probe}" exit 1 ;; esac rc_exit xl2tpd-1.3.16/packaging/suse/xl2tpd.init.patch000066400000000000000000000057321374460464600211470ustar00rootroot00000000000000--- packaging/suse/xl2tpd.init.orig 2010-05-04 12:01:25.000000000 +0200 +++ packaging/suse/xl2tpd.init 2010-05-04 12:08:08.000000000 +0200 @@ -17,8 +17,10 @@ # ### BEGIN INIT INFO # Provides: xl2tpd -# Required-Start: $syslog $remote_fs -# Required-Stop: $syslog $remote_fs +# Required-Start: $remote_fs $syslog $network +# Required-Stop: $remote_fs $syslog $network +# Should-Start: ypbind +# Should-Stop: ypbind # Default-Start: 3 5 # Default-Stop: 0 1 2 6 # Short-Description: Start xl2tpd (to provide L2TP VPN's) @@ -30,20 +32,11 @@ # not real dependencies. Depencies have to be handled by admin # resp. the configuration tools (s)he uses. -# Source SuSE config (if still necessary, most info has been moved) -test -r /etc/rc.config && . /etc/rc.config - # Check for missing binaries (stale symlinks should not happen) XL2TPD_BIN=/usr/sbin/xl2tpd -test -x $YPBIND_BIN || { echo "$YPBIND_BIN not installed"; - if [ "$1" = "stop" ]; then exit 0; else exit 5; fi; } - -# Check for existence of needed config file and read it -#XL2TPD_CONFIG=/etc/sysconfig/xl2tpd -#test -r $YPBIND_CONFIG || { echo "$YPBIND_CONFIG not existing"; -# if [ "$1" = "stop" ]; then exit 0; else exit 6; fi; } -#. $XL2TPD_CONFIG - +XL2TPD_PID=/var/run/xl2tpd/xl2tpd.pid +XL2TPD_CONF=/etc/xl2tpd/xl2tpd.conf +XL2TPD_PIDDIR=/var/run/xl2tpd # Shell functions sourced from /etc/rc.status: # rc_check check and set local and overall rc status # rc_status check and set local and overall rc status @@ -82,7 +75,10 @@ # NOTE: startproc returns 0, even if service is # already running to match LSB spec. - startproc $XL2TPD_BIN >/dev/null 2>&1 + if [ ! -d $XL2TPD_PIDDIR ]; then + mkdir -p $XL2TPD_PIDDIR + fi + startproc -p $XL2TPD_PID $XL2TPD_BIN # Remember status and be verbose rc_status -v @@ -92,8 +88,7 @@ ## Stop daemon with killproc(8) and if this fails ## set echo the echo return value. - killproc -TERM $XL2TPD_BIN - rm -f /var/run/xl2tpd/xl2tpd.pid + killproc -G -TERM $XL2TPD_BIN # Remember status and be verbose rc_status -v ;; @@ -123,13 +118,8 @@ ## do this on signal 1 (SIGHUP). ## If it does not support it, restart. echo -n "Reload service xl2tpd" - ## if it supports it: killproc -HUP $XL2TPD_BIN - #touch /var/run/xl2tpd/xl2tpd.pid rc_status -v - ## Otherwise: - #$0 stop && $0 start - #rc_status ;; reload) ## Like force-reload, but if daemon does not support @@ -137,7 +127,6 @@ # If it supports signalling: echo -n "Reload service xl2tpd" killproc -HUP $XL2TPD_BIN - #touch /var/run/xl2tpd.pid rc_status -v ## Otherwise if it does not support reload: #rc_failed 3 @@ -162,7 +151,7 @@ ## Optional: Probe for the necessity of a reload, ## print out the argument which is required for a reload. - test /etc/xl2tpd/xl2tpd.conf -nt /var/run/xltpd/xl2tpd.pid && echo reload + test $XL2TPD_CONF -nt $XL2TPD_PID && echo reload ;; *) echo "Usage: $0 {start|stop|status|try-restart|restart|force-reload|reload|probe}" xl2tpd-1.3.16/packaging/suse/xl2tpd.spec000066400000000000000000000126231374460464600200350ustar00rootroot00000000000000# # spec file for package xl2tpd # # Copyright (c) 2019 SUSE LINUX GmbH, Nuernberg, Germany. # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed # upon. The license for this file, and modifications and additions to the # file, is the same license as for the pristine package itself (unless the # license for the pristine package is not an Open Source License, in which # case the license is the MIT License). An "Open Source License" is a # license that conforms to the Open Source Definition (Version 1.9) # published by the Open Source Initiative. # Please submit bugfixes or comments via https://bugs.opensuse.org/ # %if 0%{?suse_version} <= 1310 %define rundir %{_localstatedir}/run %else %define rundir /run %endif Name: xl2tpd Version: 1.3.16 Release: 0 Summary: Layer 2 Tunnelling Protocol Daemon (RFC 2661) License: GPL-2.0-only Group: Productivity/Networking/System URL: http://www.xelerance.com/software/xl2tpd/ Source0: https://github.com/xelerance/xl2tpd/archive/v%{version}.tar.gz Source1: %{name}.service Source2: %{name}.conf Patch0: Makefile.patch Patch1: xl2tpd.init.patch BuildRequires: libpcap BuildRequires: libpcap-devel BuildRequires: linux-kernel-headers >= 2.6.19 BuildRequires: systemd-rpm-macros Requires: ppp Obsoletes: l2tpd <= 0.68 Provides: l2tpd = 0.69 %{?systemd_ordering} %description xl2tpd is an implementation of the Layer 2 Tunnelling Protocol (RFC 2661). L2TP allows you to tunnel PPP over UDP. Some ISPs use L2TP to tunnel user sessions from dial-in servers (modem banks, ADSL DSLAMs) to back-end PPP servers. Another important application is Virtual Private Networks where the IPsec protocol is used to secure the L2TP connection (L2TP/IPsec, RFC 3193). The L2TP/IPsec protocol is mainly used by Windows and Mac OS X clients. On Linux, xl2tpd can be used in combination with IPsec implementations such as Openswan. Example configuration files for such a setup are included in this RPM. xl2tpd works by opening a pseudo-tty for communicating with pppd. It runs completely in userspace but supports kernel mode L2TP. xl2tpd supports IPsec SA Reference tracking to enable overlapping internak NAT'ed IP's by different clients (eg all clients connecting from their linksys internal IP 192.168.1.101) as well as multiple clients behind the same NAT router. xl2tpd supports the pppol2tp kernel mode operations on 2.6.23 or higher, or via a patch in contrib for 2.4.x kernels. Xl2tpd is based on the 0.69 L2TP by Jeff McAdams It was de-facto maintained by Jacco de Leeuw in 2002 and 2003. %prep %setup -q %patch0 %patch1 %build make %{?_smp_mflags} DFLAGS="%{optflags} -D_GNU_SOURCE $(getconf LFS_CFLAGS)" %install export PREFIX=%{_prefix} %make_install install -p -D -m644 examples/xl2tpd.conf %{buildroot}%{_sysconfdir}/xl2tpd/xl2tpd.conf install -p -d -m750 %{buildroot}%{_sysconfdir}/ppp install -p -D -m644 examples/ppp-options.xl2tpd %{buildroot}%{_sysconfdir}/ppp/options.xl2tpd install -p -D -m600 doc/l2tp-secrets.sample %{buildroot}%{_sysconfdir}/xl2tpd/l2tp-secrets install -p -D -m600 examples/chapsecrets.sample %{buildroot}%{_sysconfdir}/ppp/chap-secrets.sample install -p -D -m755 -d %{buildroot}%{rundir}/xl2tpd install -D -m0644 %{SOURCE1} %{buildroot}%{_unitdir}/%{name}.service install -D -m0644 %{SOURCE2} %{buildroot}%{_tmpfilesdir}/%{name}.conf %if 0%{?suse_version} > 1310 sed -i 's|%{_localstatedir}/run/|/run/|' %{buildroot}%{_tmpfilesdir}/%{name}.conf %endif mkdir -p %{buildroot}%{_prefix}/lib/modules-load.d echo "l2tp_ppp" > %{buildroot}%{_prefix}/lib/modules-load.d/%{name}.conf ln -s %{_sbindir}/service %{buildroot}%{_sbindir}/rc%{name} %pre %service_add_pre %{name}.service %post # if we migrate from l2tpd to xl2tpd, copy the configs if [ -f %{_sysconfdir}/l2tpd/l2tpd.conf ] then echo "Old %{_sysconfdir}/l2tpd configuration found, migrating to %{_sysconfdir}/xl2tpd" mv %{_sysconfdir}/xl2tpd/xl2tpd.conf %{_sysconfdir}/xl2tpd/xl2tpd.conf.rpmsave cat %{_sysconfdir}/l2tpd/l2tpd.conf | sed "s/options.l2tpd/options.xl2tpd/" > %{_sysconfdir}/xl2tpd/xl2tpd.conf mv %{_sysconfdir}/ppp/options.xl2tpd %{_sysconfdir}/ppp/options.xl2tpd.rpmsave mv %{_sysconfdir}/ppp/options.l2tpd %{_sysconfdir}/ppp/options.xl2tpd mv %{_sysconfdir}/xl2tpd/l2tp-secrets %{_sysconfdir}/xl2tpd/l2tpd-secrets.rpmsave cp -pa %{_sysconfdir}/l2tpd/l2tp-secrets %{_sysconfdir}/xl2tpd/l2tp-secrets fi %service_add_post %{name}.service %fillup_only %tmpfiles_create %{_tmpfilesdir}/%{name}.conf %preun %service_del_preun %{name}.service %postun %service_del_postun %{name}.service %files %license LICENSE %doc BUGS CHANGES CREDITS README.* TODO %doc doc/README.patents examples/chapsecrets.sample %{_sbindir}/rcxl2tpd %{_sbindir}/xl2tpd %{_sbindir}/xl2tpd-control %{_bindir}/pfc %dir %{_sysconfdir}/xl2tpd %config(noreplace) %{_sysconfdir}/xl2tpd/* %dir %{_sysconfdir}/ppp %config(noreplace) %{_sysconfdir}/ppp/* %dir %ghost %{rundir}/xl2tpd %ghost %{rundir}/xl2tpd/l2tp-control %{_tmpfilesdir}/%{name}.conf %{_unitdir}/%{name}.service %dir %{_prefix}/lib/modules-load.d %{_prefix}/lib/modules-load.d/%{name}.conf %{_mandir}/man1/pfc.1%{?ext_man} %{_mandir}/man5/l2tp-secrets.5%{?ext_man} %{_mandir}/man5/xl2tpd.conf.5%{?ext_man} %{_mandir}/man8/xl2tpd-control.8%{?ext_man} %{_mandir}/man8/xl2tpd.8%{?ext_man} %changelog xl2tpd-1.3.16/pty.c000066400000000000000000000062601374460464600140210ustar00rootroot00000000000000/* * Layer Two Tunnelling Protocol Daemon * Copyright (C) 1998 Adtran, Inc. * Copyright (C) 2002 Jeff McAdams * * Mark Spencer * * This software is distributed under the terms * of the GPL, which you should have received * along with this source. * * Pseudo-pty allocation routines... Concepts and code borrowed * from pty-redir by Magosanyi Arpad. * */ #define _ISOC99_SOURCE #define _XOPEN_SOURCE #define _BSD_SOURCE #define _DEFAULT_SOURCE #define _XOPEN_SOURCE_EXTENDED #include #include #include #include #include #include #include "l2tp.h" #ifdef SOLARIS #define PTY00 "/dev/ptyXX" #define PTY10 "pqrstuvwxyz" #define PTY01 "0123456789abcdef" #endif #ifdef LINUX #define PTY00 "/dev/ptyXX" #define PTY10 "pqrstuvwxyzabcde" #define PTY01 "0123456789abcdef" #endif #if defined(FREEBSD) || defined(NETBSD) #define PTY00 "/dev/ptyXX" #define PTY10 "p" #define PTY01 "0123456789abcdefghijklmnopqrstuv" #endif #ifndef OPENBSD int getPtyMaster_pty (char *tty10, char *tty01) { char *p10; char *p01; static char dev[] = PTY00; int fd; for (p10 = PTY10; *p10; p10++) { dev[8] = *p10; for (p01 = PTY01; *p01; p01++) { dev[9] = *p01; fd = open (dev, O_RDWR | O_NONBLOCK); if (fd >= 0) { *tty10 = *p10; *tty01 = *p01; return fd; } } } l2tp_log (LOG_CRIT, "%s: No more free pseudo-tty's\n", __FUNCTION__); return -1; } int getPtyMaster_ptmx(char *ttybuf, int ttybuflen) { int fd; char *tty; fd = open("/dev/ptmx", O_RDWR); if (fd == -1) { l2tp_log (LOG_WARNING, "%s: unable to open /dev/ptmx to allocate pty\n", __FUNCTION__); return -EINVAL; } /* No need to call grantpt */ if (unlockpt(fd)) { l2tp_log (LOG_WARNING, "%s: unable to unlockpt() on pty\n", __FUNCTION__); close(fd); return -EINVAL; } tty = ptsname(fd); if (tty == NULL) { l2tp_log (LOG_WARNING, "%s: unable to obtain name of slave tty\n", __FUNCTION__); close(fd); return -EINVAL; } ttybuf[0]='\0'; strncat(ttybuf, tty, ttybuflen); return fd; } #endif #ifdef OPENBSD int getPtyMaster_ptm(char *ttybuf, int ttybuflen) { int amaster, aslave; char *tty = malloc(64); if((openpty(&amaster, &aslave, tty, NULL, NULL)) == -1) { l2tp_log (LOG_WARNING, "%s: openpty() returned %s\n", __FUNCTION__, strerror(errno)); free(tty); return -EINVAL; } ttybuf[0] = '\0'; strncat(ttybuf, tty, ttybuflen); free(tty); return amaster; } #endif /* OPENBSD */ int getPtyMaster(char *ttybuf, int ttybuflen) { int fd; #ifndef OPENBSD fd = getPtyMaster_ptmx(ttybuf, ttybuflen); char a, b; if(fd >= 0) { return fd; } l2tp_log (LOG_WARNING, "%s: failed to use pts -- using legacy ptys\n", __FUNCTION__); fd = getPtyMaster_pty(&a,&b); if(fd >= 0) { snprintf(ttybuf, ttybuflen, "/dev/tty%c%c", a, b); return fd; } #endif #ifdef OPENBSD fd = getPtyMaster_ptm(ttybuf, ttybuflen); if(fd >= 0) { return fd; } #endif /* OPENBSD */ return -EINVAL; } xl2tpd-1.3.16/scheduler.c000066400000000000000000000074421374460464600151660ustar00rootroot00000000000000/* * Layer Two Tunnelling Protocol Daemon * Copyright (C) 1998 Adtran, Inc. * Copyright (C) 2002 Jeff McAdams * * Mark Spencer * * This software is distributed under the terms * of the GPL, which you should have received * along with this source. * * Scheduler code for time based functionality * */ #include #include #include "l2tp.h" #include "scheduler.h" struct schedule_entry *events; void init_scheduler (void) { events = NULL; } struct timeval *process_schedule (struct timeval *ptv) { /* Check queue for events which should be executed right now. Execute them, then see how long we should set the next timer */ struct schedule_entry *p = events; struct timeval now; struct timeval then; while (events) { gettimeofday (&now, NULL); p = events; if (TVLESSEQ (p->tv, now)) { events = events->next; /* This needs to be executed, as it has expired. It is expected that p->func will free p->data if it is necessary */ (*p->func) (p->data); free (p); } else break; } /* When we get here, either there are no more events in the queue, or the remaining events need to happen in the future, so we should schedule another alarm */ if (events) { then.tv_sec = events->tv.tv_sec - now.tv_sec; then.tv_usec = events->tv.tv_usec - now.tv_usec; if (then.tv_usec < 0) { then.tv_sec -= 1; then.tv_usec += 1000000; } if ((then.tv_sec <= 0) && (then.tv_usec <= 0)) { l2tp_log (LOG_WARNING, "%s: Whoa... Scheduling for <=0 time???\n", __FUNCTION__); then.tv_sec = 1; then.tv_usec = 0; } *ptv = then; return ptv; } else { return NULL; } } struct schedule_entry *schedule (struct timeval tv, void (*func) (void *), void *data) { /* Schedule func to be run at relative time tv with data as arguments. If it has already expired, run it immediately. The queue should be in order of increasing time */ struct schedule_entry *p = events, *q = NULL; struct timeval diff; diff = tv; gettimeofday (&tv, NULL); tv.tv_sec += diff.tv_sec; tv.tv_usec += diff.tv_usec; if (tv.tv_usec > 1000000) { tv.tv_sec++; tv.tv_usec -= 1000000; } while (p) { if (TVLESS (tv, p->tv)) break; q = p; p = p->next; }; if (q) { q->next = malloc (sizeof (struct schedule_entry)); q = q->next; } else { q = malloc (sizeof (struct schedule_entry)); events = q; } q->tv = tv; q->func = func; q->data = data; q->next = p; return q; } inline struct schedule_entry *aschedule (struct timeval tv, void (*func) (void *), void *data) { /* Schedule func to be run at absolute time tv in the future with data as arguments */ struct timeval now; gettimeofday (&now, NULL); tv.tv_usec -= now.tv_usec; if (tv.tv_usec < 0) { tv.tv_usec += 1000000; tv.tv_sec--; } tv.tv_sec -= now.tv_sec; return schedule (tv, func, data); } void deschedule (struct schedule_entry *s) { struct schedule_entry *p = events, *q = NULL; if (!s) return; while (p) { if (p == s) { if (q) { q->next = p->next; } else { events = events->next; } free (p); break; } q = p; p = p->next; } } xl2tpd-1.3.16/scheduler.h000066400000000000000000000034701374460464600151700ustar00rootroot00000000000000/* * Layer Two Tunnelling Protocol Daemon * Copyright (C) 1998 Adtran, Inc. * Copyright (C) 2002 Jeff McAdams * * Mark Spencer * * This software is distributed under the terms * of the GPL, which you should have received * along with this source. * * Scheduler structures and functions * */ #ifndef _SCHEDULER_H #define _SCHEDULER_H #include /* * The idea is to provide a general scheduler which can schedule * events to be run periodically */ struct schedule_entry { struct timeval tv; /* Scheduled time to execute */ void (*func) (void *); /* Function to execute */ void *data; /* Data to be passed to func */ struct schedule_entry *next; /* Next entry in queue */ }; extern struct schedule_entry *events; /* Schedule func to be executed with argument data sometime tv in the future. */ struct schedule_entry *schedule (struct timeval tv, void (*func) (void *), void *data); /* Like schedule() but tv represents an absolute time in the future */ struct schedule_entry *aschedule (struct timeval tv, void (*func) (void *), void *data); /* Remove a scheduled event from the queue */ void deschedule (struct schedule_entry *); /* Initialization function */ void init_scheduler (void); /* Scheduled event processor */ struct timeval *process_schedule(struct timeval *); /* Compare two timeval functions and see if a <= b */ #define TVLESS(a,b) ((a).tv_sec == (b).tv_sec ? \ ((a).tv_usec < (b).tv_usec) : \ ((a).tv_sec < (b).tv_sec)) #define TVLESSEQ(a,b) ((a).tv_sec == (b).tv_sec ? \ ((a).tv_usec <= (b).tv_usec) : \ ((a).tv_sec <= (b).tv_sec)) #define TVGT(a,b) ((a).tv_sec == (b).tv_sec ? \ ((a).tv_usec > (b).tv_usec) : \ ((a).tv_sec > (b).tv_sec)) #endif xl2tpd-1.3.16/scripts/000077500000000000000000000000001374460464600145245ustar00rootroot00000000000000xl2tpd-1.3.16/scripts/init.suse000066400000000000000000000112371374460464600163740ustar00rootroot00000000000000#! /bin/sh # Copyright (c) 1995-2003 # Tronicplanet Datendienst GmbH, Simbach am INN, Germany. # All rights reserved. # # Author: Bernhard Thoni # # /etc/init.d/l2tpd # # and its symbolic link # # /(usr/)sbin/rcl2tpd # # LSB compliant service control script; see http://www.linuxbase.org/spec/ # # System startup script for L2TP daemon l2tpd # ### BEGIN INIT INFO # Provides: FOO # Required-Start: $syslog # Required-Stop: $syslog # Default-Start: 3 5 # Default-Stop: 0 1 2 6 # Description: Start l2tpd to allow XY and provide YZ # continued on second line by '#' ### END INIT INFO # # Note on Required-Start: It does specify the init script ordering, # not real dependencies. Depencies have to be handled by admin # resp. the configuration tools (s)he uses. # Source SuSE config (if still necessary, most info has been moved) test -r /etc/rc.config && . /etc/rc.config # Check for missing binaries (stale symlinks should not happen) L2TPD_BIN=/usr/sbin/l2tpd test -x $L2TPD_BIN || exit 5 # Check for existence of needed config file and read it #L2TPD_CONFIG=/etc/sysconfig/FOO #test -r $L2TPD_CONFIG || exit 6 #. $L2TPD_CONFIG # Shell functions sourced from /etc/rc.status: # rc_check check and set local and overall rc status # rc_status check and set local and overall rc status # rc_status -v ditto but be verbose in local rc status # rc_status -v -r ditto and clear the local rc status # rc_failed set local and overall rc status to failed # rc_failed set local and overall rc status to # rc_reset clear local rc status (overall remains) # rc_exit exit appropriate to overall rc status # rc_active checks whether a service is activated by symlinks . /etc/rc.status # First reset status of this service rc_reset # Return values acc. to LSB for all commands but status: # 0 - success # 1 - generic or unspecified error # 2 - invalid or excess argument(s) # 3 - unimplemented feature (e.g. "reload") # 4 - insufficient privilege # 5 - program is not installed # 6 - program is not configured # 7 - program is not running # # Note that starting an already running service, stopping # or restarting a not-running service as well as the restart # with force-reload (in case signalling is not supported) are # considered a success. case "$1" in start) echo -n "Starting L2TPD" ## Start daemon with startproc(8). If this fails ## the echo return value is set appropriate. # NOTE: startproc returns 0, even if service is # already running to match LSB spec. startproc $L2TPD_BIN >/dev/null 2>&1 # Remember status and be verbose rc_status -v ;; stop) echo -n "Shutting down L2TPD" ## Stop daemon with killproc(8) and if this fails ## set echo the echo return value. killproc -TERM $L2TPD_BIN # Remember status and be verbose rc_status -v ;; try-restart) ## Stop the service and if this succeeds (i.e. the ## service was running before), start it again. ## Note: try-restart is not (yet) part of LSB (as of 0.7.5) $0 status >/dev/null && $0 restart # Remember status and be quiet rc_status ;; restart) ## Stop the service and regardless of whether it was ## running or not, start it again. $0 stop $0 start # Remember status and be quiet rc_status ;; force-reload) ## Signal the daemon to reload its config. Most daemons ## do this on signal 1 (SIGHUP). ## If it does not support it, restart. echo -n "Reload service L2TPD" ## if it supports it: killproc -HUP $L2TPD_BIN #touch /var/run/l2tpd.pid rc_status -v ## Otherwise: #$0 stop && $0 start #rc_status ;; reload) ## Like force-reload, but if daemon does not support ## signalling, do nothing (!) # If it supports signalling: echo -n "Reload service L2TPD" killproc -HUP $L2TPD_BIN #touch /var/run/l2tpd.pid rc_status -v ## Otherwise if it does not support reload: #rc_failed 3 #rc_status -v ;; status) echo -n "Checking for service L2TPD: " ## Check status with checkproc(8), if process is running ## checkproc will return with exit status 0. # Return value is slightly different for the status command: # 0 - service running # 1 - service dead, but /var/run/ pid file exists # 2 - service dead, but /var/lock/ lock file exists # 3 - service not running # NOTE: checkproc returns LSB compliant status values. checkproc $L2TPD_BIN rc_status -v ;; probe) ## Optional: Probe for the necessity of a reload, ## print out the argument which is required for a reload. test /etc/l2tpd/l2tpd.conf -nt /var/run/l2tpd.pid && echo reload ;; *) echo "Usage: $0 {start|stop|status|try-restart|restart|force-reload|reload|probe}" exit 1 ;; esac rc_exit xl2tpd-1.3.16/xl2tpd-control.c000066400000000000000000000324511374460464600161010ustar00rootroot00000000000000/* * xl2tpd-control - the xl2tpd control utility * * Copyright (C) 2011 Alexander Dorokhov * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * 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 (see the file LICENSE); if not, see * https://www.gnu.org/licenses/, or contact Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * **************************************************************** */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include "l2tp.h" /* Paul: Alex: can we change this to use stdout, and let applications using * xl2tpd-control capture the output, instead of creating tmp files? */ /* result filename format including absolute path and formatting %i for pid */ #define RESULT_FILENAME_FORMAT "/var/run/xl2tpd/xl2tpd-control-%i.out" #define ERROR_LEVEL 1 #define DEBUG_LEVEL 2 #define TUNNEL_REQUIRED 1 #define TUNNEL_NOT_REQUIRED 0 #define TIMEOUT 1000000 //timeout is 1s char result_filename[128]; int result_fd = -1; int log_level = ERROR_LEVEL; void print_error (int level, const char *fmt, ...); int read_result(int result_fd, char* buf, ssize_t size); /* Definition of a command */ struct command_t { char *name; int (*handler) (FILE*, char* tunnel, int optc, char *optv[]); int requires_tunnel; }; int command_add_lac (FILE*, char* tunnel, int optc, char *optv[]); int command_connect_lac (FILE*, char* tunnel, int optc, char *optv[]); int command_disconnect_lac(FILE*, char* tunnel, int optc, char *optv[]); int command_status_lac (FILE*, char* tunnel, int optc, char *optv[]); int command_remove_lac (FILE*, char* tunnel, int optc, char *optv[]); int command_available (FILE*, char* tunnel, int optc, char *optv[]); int command_add_lns (FILE*, char* tunnel, int optc, char *optv[]); int command_status_lns (FILE*, char* tunnel, int optc, char *optv[]); int command_remove_lns (FILE*, char* tunnel, int optc, char *optv[]); struct command_t commands[] = { {"add-lac", &command_add_lac, TUNNEL_REQUIRED}, {"connect-lac", &command_connect_lac, TUNNEL_REQUIRED}, {"disconnect-lac",&command_disconnect_lac,TUNNEL_REQUIRED}, {"status-lac", &command_status_lac, TUNNEL_REQUIRED}, {"remove-lac", &command_remove_lac, TUNNEL_REQUIRED}, {"available", &command_available, TUNNEL_NOT_REQUIRED}, {"add-lns", &command_add_lns, TUNNEL_REQUIRED}, {"status-lns", &command_status_lns, TUNNEL_REQUIRED}, {"remove-lns", &command_remove_lns, TUNNEL_REQUIRED} }; void usage() { printf ("Usage: xl2tpd-control [-c ] []\n\n" " -c set xl2tpd control file\n" " -d enable debugging mode\n" "--version show version\n" " --help show this help message\n\n" "List of supported commands:\n" "add-lac, status-lac, remove-lac, connect-lac, disconnect-lac\n" "add-lns, status-lns, remove-lns, avaliable\n\n" "See xl2tpd-control(8) man page for more details.\n"); } void cleanup(void) { /* cleaning up */ unlink (result_filename); if (result_fd >= 0) close (result_fd); } int main (int argc, char *argv[]) { char* control_filename = NULL; char* tunnel_name = NULL; struct command_t* command = NULL; int i; /* argv iterator */ if (argv[1] && !strncmp (argv[1], "--help", 6)) { usage(); return 0; } if (argv[1] && !strncmp (argv[1], "--version", 9)) { printf ("Version: %s\n", SERVER_VERSION); return 0; } /* parse global options */ for (i = 1; i < argc; i++) { if (!strncmp (argv[i], "-c", 2)) { control_filename = argv[++i]; } else if (!strncmp (argv[i], "-d", 2)) { log_level = DEBUG_LEVEL; } else { break; } } if (i >= argc) { print_error (ERROR_LEVEL, "error: command not specified\n"); usage(); return -1; } if (!control_filename) { control_filename = strdup (CONTROL_PIPE); } /* parse command name */ for (command = commands; command->name; command++) { if (!strcasecmp (argv[i], command->name)) { i++; break; } } if (!command->name) { print_error (ERROR_LEVEL, "error: no such command\n"); free(control_filename); usage(); return -1; } /* get tunnel name */ if(command->requires_tunnel){ if (i >= argc) { print_error (ERROR_LEVEL, "error: tunnel name not specified\n"); usage(); free(control_filename); return -1; } tunnel_name = argv[i++]; /* check tunnel name for whitespaces */ if (strstr (tunnel_name, " ")) { print_error (ERROR_LEVEL, "error: tunnel name shouldn't include spaces\n"); usage(); free(control_filename); return -1; } } char buf[CONTROL_PIPE_MESSAGE_SIZE] = ""; FILE* mesf = fmemopen (buf, CONTROL_PIPE_MESSAGE_SIZE, "w"); /* create result pipe for reading */ snprintf (result_filename, 128, RESULT_FILENAME_FORMAT, getpid()); unlink (result_filename); mkfifo (result_filename, 0600); atexit(cleanup); result_fd = open (result_filename, O_RDONLY | O_NONBLOCK, 0600); if (result_fd < 0) { print_error (ERROR_LEVEL, "error: unable to open %s for reading.\n", result_filename); return -2; } /* turn off O_NONBLOCK */ if (fcntl (result_fd, F_SETFL, O_RDONLY) == -1) { print_error (ERROR_LEVEL, "Can not turn off nonblocking mode for result_fd: %s\n", strerror(errno)); return -2; } /* pass result filename to command */ fprintf (mesf, "@%s ", result_filename); if (ferror (mesf)) { print_error (ERROR_LEVEL, "internal error: message buffer to short"); return -2; } /* format command with remaining arguments */ int command_res = command->handler ( mesf, tunnel_name, argc - i, argv + i ); if (command_res < 0) { print_error (ERROR_LEVEL, "error: command parse error\n"); return -1; } fflush (mesf); if (ferror (mesf)) { print_error (ERROR_LEVEL, "error: message too long (max = %i ch.)\n", CONTROL_PIPE_MESSAGE_SIZE - 1); return -1; } print_error (DEBUG_LEVEL, "command to be passed:\n%s\n", buf); /* try to open control file for writing */ int control_fd = open (control_filename, O_WRONLY | O_NONBLOCK, 0600); if (control_fd < 0) { int errorno = errno; switch (errorno) { case EACCES: print_error (ERROR_LEVEL, "Unable to open %s for writing." " Is xl2tpd running and you have appropriate permissions?\n", control_filename); break; default: print_error (ERROR_LEVEL, "Unable to open %s for writing: %s\n", control_filename, strerror (errorno)); } return -1; } /* turn off O_NONBLOCK */ if (fcntl (control_fd, F_SETFL, O_WRONLY) == -1) { print_error (ERROR_LEVEL, "Can not turn off nonblocking mode for control_fd: %s\n", strerror(errno)); return -2; } /* pass command to control pipe */ if (write (control_fd, buf, ftell (mesf)) < 0) { int errorno = errno; print_error (ERROR_LEVEL, "Unable to write to %s: %s\n", control_filename, strerror (errorno)); close (control_fd); return -1; } close (control_fd); /* read result from pipe */ char rbuf[CONTROL_PIPE_MESSAGE_SIZE] = ""; int command_result_code = read_result ( result_fd, rbuf, CONTROL_PIPE_MESSAGE_SIZE ); /* rbuf contains a newline, make it double to form a boundary. */ print_error (DEBUG_LEVEL, "command response: \n%s\n", rbuf); return command_result_code; } void print_error (int level, const char *fmt, ...) { if (level > log_level) return; va_list args; va_start (args, fmt); fprintf (stderr, "xl2tpd-control: "); vfprintf (stderr, fmt, args); va_end (args); } int read_result(int result_fd, char* buf, ssize_t size) { /* read result from result_fd */ /*FIXME: there is a chance to hang up reading. Should I create watching thread with timeout? */ ssize_t readed = 0; ssize_t len; int write_pipe = 0; struct timeval tvs; struct timeval tve; unsigned long diff; gettimeofday(&tvs, NULL); do { len = read (result_fd, buf + readed, size - readed); if (len < 0) { if (errno == EINTR) continue; print_error (ERROR_LEVEL, "error: can't read command result: %s\n", strerror (errno)); break; } else if (len == 0) { if(!write_pipe) { gettimeofday(&tve, NULL); diff = (tve.tv_sec - tvs.tv_sec) * 1000000 + (tve.tv_usec - tvs.tv_usec); if (diff >= TIMEOUT) { print_error (DEBUG_LEVEL, "error: read timout\n"); break; } else { usleep(10); continue; } } break; } else { write_pipe = 1; readed += len; if ((size - readed) <= 0) break; } } while (1); buf[readed] = '\0'; /* scan result code */ int command_result_code = -3; sscanf (buf, "%i", &command_result_code); return command_result_code; } int command_add (FILE* mesf, char* tunnel, int optc, char *optv[], int reqopt) { if (optc <= 0) { print_error (ERROR_LEVEL, "error: tunnel configuration expected\n"); return -1; } fprintf (mesf, "%c %s ", reqopt, tunnel); int i; int wait_key = 1; for (i = 0; i < optc; i++) { fprintf (mesf, "%s", optv[i]); if (wait_key) { /* try to find '=' */ char* eqv = strstr (optv[i], "="); if (eqv) { /* check is it not last symbol */ if (eqv != (optv[i] + strlen(optv[i]) - 1)) { fprintf (mesf, ";"); /* end up option */ } else { wait_key = 0; /* now we waiting for value */ } } else { /* two-word key */ fprintf (mesf, " "); /* restore space */ } } else { fprintf (mesf, ";"); /* end up option */ wait_key = 1; /* now we again waiting for key */ } } return 0; } int command_add_lac (FILE* mesf, char* tunnel, int optc, char *optv[]) { return command_add(mesf, tunnel, optc, optv, CONTROL_PIPE_REQ_LAC_ADD_MODIFY); } int command_add_lns (FILE* mesf, char* tunnel, int optc, char *optv[]) { return command_add(mesf, tunnel, optc, optv, CONTROL_PIPE_REQ_LNS_ADD_MODIFY); } int command_connect_lac (FILE* mesf, char* tunnel, int optc, char *optv[]) { fprintf (mesf, "%c %s", CONTROL_PIPE_REQ_LAC_CONNECT, tunnel); /* try to read authname and password from opts */ if (optc > 0) { if (optc == 1) fprintf (mesf, " %s", optv[0]); else // optc >= 2 fprintf (mesf, " %s %s", optv[0], optv[1]); } return 0; } int command_disconnect_lac (FILE* mesf, char* tunnel, int optc, char *optv[]) { UNUSED(optc); UNUSED(optv); fprintf (mesf, "%c %s", CONTROL_PIPE_REQ_LAC_DISCONNECT, tunnel); return 0; } int command_remove_lac (FILE* mesf, char* tunnel, int optc, char *optv[]) { UNUSED(optc); UNUSED(optv); fprintf (mesf, "%c %s", CONTROL_PIPE_REQ_LAC_REMOVE, tunnel); return 0; } int command_status_lns (FILE* mesf, char* tunnel, int optc, char *optv[]) { UNUSED(optc); UNUSED(optv); fprintf (mesf, "%c %s", CONTROL_PIPE_REQ_LNS_STATUS, tunnel); return 0; } int command_status_lac (FILE* mesf, char* tunnel, int optc, char *optv[]) { UNUSED(optc); UNUSED(optv); fprintf (mesf, "%c %s", CONTROL_PIPE_REQ_LAC_STATUS, tunnel); return 0; } int command_available (FILE* mesf, char* tunnel, int optc, char *optv[]) { UNUSED(optc); UNUSED(optv); fprintf (mesf, "%c %s", CONTROL_PIPE_REQ_AVAILABLE, tunnel); return 0; } int command_remove_lns (FILE* mesf, char* tunnel, int optc, char *optv[]) { UNUSED(optc); UNUSED(optv); fprintf (mesf, "%c %s", CONTROL_PIPE_REQ_LNS_REMOVE, tunnel); return 0; } xl2tpd-1.3.16/xl2tpd.c000066400000000000000000001526541374460464600144330ustar00rootroot00000000000000/* * Layer Two Tunnelling Protocol Daemon * Copyright (C) 1998 Adtran, Inc. * Copyright (C) 2002 Jeff McAdams * * * Mark Spencer * * This software is distributed under the terms * of the GPL, which you should have received * along with this source. * * Main Daemon source. * */ #define _ISOC99_SOURCE #define _XOPEN_SOURCE #define _BSD_SOURCE #define _DEFAULT_SOURCE #define _XOPEN_SOURCE_EXTENDED 1 #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #ifndef LINUX # include #endif #include #include #include #include #include #include #include "l2tp.h" struct tunnel_list tunnels; int rand_source; int ppd = 1; /* Packet processing delay */ int control_fd; /* descriptor of control area */ static char *dial_no_tmp; /* jz: Dialnumber for Outgoing Call */ int switch_io = 0; /* jz: Switch for Incoming or Outgoing Call */ static void open_controlfd(void); static volatile sig_atomic_t sigterm_received; static volatile sig_atomic_t sigint_received; static volatile sig_atomic_t sigchld_received; static volatile sig_atomic_t sigusr1_received;; static volatile sig_atomic_t sighup_received; struct control_requests_handler { char type; int (*handler) (FILE* resf, char* bufp); }; static int control_handle_available(FILE* resf, char* bufp); static int control_handle_lns_add_modify(FILE* resf, char* bufp); static int control_handle_lns_status(FILE* resf, char* bufp); static int control_handle_tunnel(FILE* respf, char* bufp); static int control_handle_lac_connect(FILE* resf, char* bufp); static int control_handle_lac_outgoing_call(FILE* resf, char* bufp); static int control_handle_lac_hangup(FILE* resf, char* bufp); static int control_handle_lac_disconnect(FILE* resf, char* bufp); static int control_handle_lac_add_modify(FILE* resf, char* bufp); static int control_handle_lac_remove(FILE* resf, char* bufp); static int control_handle_lac_status(); static int control_handle_lns_remove(FILE* resf, char* bufp); static struct control_requests_handler control_handlers[] = { {CONTROL_PIPE_REQ_AVAILABLE, &control_handle_available}, {CONTROL_PIPE_REQ_LNS_ADD_MODIFY, &control_handle_lns_add_modify}, {CONTROL_PIPE_REQ_LNS_STATUS, &control_handle_lns_status}, {CONTROL_PIPE_REQ_TUNNEL, &control_handle_tunnel}, {CONTROL_PIPE_REQ_LAC_CONNECT, &control_handle_lac_connect}, {CONTROL_PIPE_REQ_LAC_OUTGOING_CALL, &control_handle_lac_outgoing_call}, {CONTROL_PIPE_REQ_LAC_HANGUP, &control_handle_lac_hangup}, {CONTROL_PIPE_REQ_LAC_DISCONNECT, &control_handle_lac_disconnect}, {CONTROL_PIPE_REQ_LAC_ADD_MODIFY, &control_handle_lac_add_modify}, {CONTROL_PIPE_REQ_LAC_REMOVE, &control_handle_lac_remove}, {CONTROL_PIPE_REQ_LAC_STATUS, &control_handle_lac_status}, {CONTROL_PIPE_REQ_LNS_REMOVE, &control_handle_lns_remove}, {0, NULL} }; static void init_tunnel_list (struct tunnel_list *t) { t->head = NULL; t->count = 0; t->calls = 0; } /* Now sends to syslog instead - MvO */ static void show_status (void) { struct schedule_entry *se; struct tunnel *t; struct call *c; struct lns *tlns; struct lac *tlac; struct host *h; unsigned long cnt = 0; int s = 0; l2tp_log (LOG_WARNING, "====== xl2tpd statistics ========\n"); l2tp_log (LOG_WARNING, " Scheduler entries:\n"); se = events; while (se) { s++; t = (struct tunnel *) se->data; tlac = (struct lac *) se->data; c = (struct call *) se->data; if (se->func == &hello) { l2tp_log (LOG_WARNING, "%d: HELLO to %d\n", s, t->tid); } else if (se->func == &magic_lac_dial) { l2tp_log (LOG_WARNING, "%d: Magic dial on %s\n", s, tlac->entname); } else if (se->func == &send_zlb) { l2tp_log (LOG_WARNING, "%d: Send payload ZLB on call %d:%d\n", s, c->container->tid, c->cid); } else if (se->func == &dethrottle) { l2tp_log (LOG_WARNING, "%d: Dethrottle call %d:%d\n", s, c->container->tid, c->cid); } else if (se->func == &control_xmit) { l2tp_log (LOG_WARNING, "%d: Control xmit on %d\n", s,((struct buffer *)se->data)->tunnel->tid); } else l2tp_log (LOG_WARNING, "%d: Unknown event\n", s); se = se->next; }; l2tp_log (LOG_WARNING, "Total Events scheduled: %d\n", s); l2tp_log (LOG_WARNING, "Number of tunnels open: %d\n", tunnels.count); t = tunnels.head; while (t) { l2tp_log (LOG_WARNING, "Tunnel %s, ID = %d (local), %d (remote) to %s:%d," " control_seq_num = %d, control_rec_seq_num = %d," " cLr = %d, call count = %d ref=%u/refhim=%u", (t->lac ? t->lac->entname : (t->lns ? t->lns->entname : "")), t->ourtid, t->tid, IPADDY (t->peer.sin_addr), ntohs (t->peer.sin_port), t->control_seq_num, t->control_rec_seq_num, t->cLr, t->count, t->refme, t->refhim); c = t->call_head; while (c) { cnt++; l2tp_log (LOG_WARNING, "Call %s # %lu, ID = %d (local), %d (remote), serno = %u," " data_seq_num = %d, data_rec_seq_num = %d," " pLr = %d, tx = %u bytes (%u), rx= %u bytes (%u)", (c->lac ? c->lac-> entname : (c->lns ? c->lns->entname : "")), cnt, c->ourcid, c->cid, c->serno, c->data_seq_num, c->data_rec_seq_num, c->pLr, c->tx_bytes, c->tx_pkts, c->rx_bytes, c->rx_pkts); c = c->next; } t = t->next; } l2tp_log (LOG_WARNING, "==========Config File===========\n"); tlns = lnslist; while (tlns) { l2tp_log (LOG_WARNING, "LNS entry %s\n", tlns->entname[0] ? tlns->entname : "(unnamed)"); tlns = tlns->next; }; tlac = laclist; while (tlac) { l2tp_log (LOG_WARNING, "LAC entry %s, LNS is/are:", tlac->entname[0] ? tlac->entname : "(unnamed)"); h = tlac->lns; if (h) { while (h) { l2tp_log (LOG_WARNING, " %s", h->hostname); h = h->next; } } else l2tp_log (LOG_WARNING, " [none]"); tlac = tlac->next; }; l2tp_log (LOG_WARNING, "================================\n"); } static void null_handler(int sig) { UNUSED(sig); /* FIXME * A sighup is received when a call is terminated, unknown origine .. * I catch it and ll looks good, but .. */ } static void status_handler (int sig) { UNUSED(sig); show_status (); } static void child_handler (int sig) { UNUSED(sig); /* * Oops, somebody we launched was killed. * It's time to reap them and close that call. * But first, we have to find out what PID died. * unfortunately, pppd will */ struct tunnel *t; struct call *c; pid_t pid; int status; /* Keep looping until all are cleared */ for(;;) { pid = waitpid (-1, &status, WNOHANG); if (pid < 1) { /* * Oh well, nobody there. Maybe we reaped it * somewhere else already */ return; } /* find the call that "owned" the pppd which just died */ t = tunnels.head; while (t) { c = t->call_head; t = t->next; while (c) { if (c->pppd == pid) { if ( WIFEXITED( status ) ) { l2tp_log (LOG_DEBUG, "%s : pppd exited for call %d with code %d\n", __FUNCTION__, c->cid, WEXITSTATUS( status ) ); } else if( WIFSIGNALED( status ) ) { l2tp_log (LOG_DEBUG, "%s : pppd terminated for call %d by signal %d\n", __FUNCTION__, c->cid, WTERMSIG( status ) ); } else { l2tp_log (LOG_DEBUG, "%s : pppd exited for call %d for unknown reason\n", __FUNCTION__, c->cid ); } c->needclose = -1; /* * OK...pppd died, we can go ahead and close the pty for * it */ #ifdef USE_KERNEL if (!kernel_support) { #endif close (c->fd); #ifdef USE_KERNEL } #endif c->fd = -1; /* * terminate tunnel and call loops, returning to the * for(;;) loop (and possibly get the next pid) */ t = NULL; break; } c = c->next; } } } } static void death_handler (int signal) { /* * If we get here, somebody terminated us with a kill or a control-c. * we call call_close on each tunnel twice to get a StopCCN out * for each one (we can't pause to make sure it's received. * Then we close the connections */ struct tunnel *st, *st2; int sec; l2tp_log (LOG_CRIT, "%s: Fatal signal %d received\n", __FUNCTION__, signal); #ifdef USE_KERNEL if (kernel_support || signal != SIGTERM) { #else if (signal != SIGTERM) { #endif st = tunnels.head; while (st) { st2 = st->next; strcpy (st->self->errormsg, "Server closing"); sec = st->self->closing; if (st->lac) st->lac->redial = 0; call_close (st->self); if (!sec) { st->self->closing = -1; call_close (st->self); } st = st2; } } /* erase pid and control files */ unlink (gconfig.pidfile); unlink (gconfig.controlfile); free(dial_no_tmp); close(server_socket); close(control_fd); closelog(); exit (1); } static void sigterm_handler(int sig) { UNUSED(sig); sigterm_received = 1; } static void sigint_handler(int sig) { UNUSED(sig); sigint_received = 1; } static void sigchld_handler(int sig) { UNUSED(sig); sigchld_received = 1; } static void sigusr1_handler(int sig) { UNUSED(sig); sigusr1_received = 1; } static void sighup_handler(int sig) { UNUSED(sig); sighup_received = 1; } void process_signal(void) { if (sigterm_received) { sigterm_received = 0; death_handler(SIGTERM); } if (sigint_received) { sigint_received = 0; death_handler(SIGINT); } if (sigchld_received) { sigchld_received = 0; child_handler(SIGCHLD); } if (sigusr1_received) { sigusr1_received = 0; status_handler(SIGUSR1); } if (sighup_received) { sighup_received = 0; null_handler(SIGHUP); } } int start_pppd (struct call *c, struct ppp_opts *opts) { /* char a, b; */ char tty[512]; char *stropt[80]; #ifdef USE_KERNEL struct sockaddr_pppol2tp sax; int flags; #endif int pos = 1; int fd2 = -1; #ifdef DEBUG_PPPD int x; #endif struct termios ptyconf; struct call *sc; struct tunnel *st; stropt[0] = strdup (PPPD); if (c->pppd > 0) { l2tp_log(LOG_WARNING, "%s: PPP already started on call!\n", __FUNCTION__); return -EINVAL; } if (c->fd > -1) { l2tp_log (LOG_WARNING, "%s: file descriptor already assigned!\n", __FUNCTION__); return -EINVAL; } #ifdef USE_KERNEL if (kernel_support) { fd2 = socket(AF_PPPOX, SOCK_DGRAM, PX_PROTO_OL2TP); if (fd2 < 0) { l2tp_log (LOG_WARNING, "%s: Unable to allocate PPPoL2TP socket.\n", __FUNCTION__); return -EINVAL; } flags = fcntl(fd2, F_GETFL); if (flags == -1 || fcntl(fd2, F_SETFL, flags | O_NONBLOCK) == -1) { l2tp_log (LOG_WARNING, "%s: Unable to set PPPoL2TP socket nonblock.\n", __FUNCTION__); return -EINVAL; } memset(&sax, 0, sizeof(sax)); sax.sa_family = AF_PPPOX; sax.sa_protocol = PX_PROTO_OL2TP; sax.pppol2tp.fd = c->container->udp_fd; sax.pppol2tp.addr.sin_addr.s_addr = c->container->peer.sin_addr.s_addr; sax.pppol2tp.addr.sin_port = c->container->peer.sin_port; sax.pppol2tp.addr.sin_family = AF_INET; sax.pppol2tp.s_tunnel = c->container->ourtid; sax.pppol2tp.s_session = c->ourcid; sax.pppol2tp.d_tunnel = c->container->tid; sax.pppol2tp.d_session = c->cid; if (connect(fd2, (struct sockaddr *)&sax, sizeof(sax)) < 0) { l2tp_log (LOG_WARNING, "%s: Unable to connect PPPoL2TP socket.\n", __FUNCTION__); close(fd2); return -EINVAL; } stropt[pos++] = strdup ("plugin"); stropt[pos++] = strdup ("pppol2tp.so"); stropt[pos++] = strdup ("pppol2tp"); stropt[pos] = malloc (11); snprintf (stropt[pos], 11, "%d", fd2); pos++; if (c->container->lns) { stropt[pos++] = strdup ("pppol2tp_lns_mode"); stropt[pos++] = strdup ("pppol2tp_tunnel_id"); stropt[pos] = malloc (11); snprintf (stropt[pos], 11, "%d", c->container->ourtid); pos++; stropt[pos++] = strdup ("pppol2tp_session_id"); stropt[pos] = malloc (11); snprintf (stropt[pos], 11, "%d", c->ourcid); pos++; } } else #endif { if ((c->fd = getPtyMaster (tty, sizeof(tty))) < 0) { l2tp_log (LOG_WARNING, "%s: unable to allocate pty, abandoning!\n", __FUNCTION__); return -EINVAL; } /* set fd opened above to not echo so we don't see read our own packets back of the file descriptor that we just wrote them to */ tcgetattr (c->fd, &ptyconf); *(c->oldptyconf) = ptyconf; ptyconf.c_cflag &= ~(ICANON | ECHO); ptyconf.c_lflag &= ~ECHO; tcsetattr (c->fd, TCSANOW, &ptyconf); if(fcntl(c->fd, F_SETFL, O_NONBLOCK)!=0) { l2tp_log(LOG_WARNING, "failed to set nonblock: %s\n", strerror(errno)); return -EINVAL; } fd2 = open (tty, O_RDWR); if (fd2 < 0) { l2tp_log (LOG_WARNING, "unable to open tty %s, cannot start pppd", tty); return -EINVAL; } stropt[pos++] = strdup(tty); } { struct ppp_opts *p = opts; int maxn_opts = sizeof(stropt) / sizeof(stropt[0]) - 1; while (p && pos < maxn_opts) { stropt[pos] = strdup (p->option); pos++; p = p->next; } stropt[pos] = NULL; } #ifdef DEBUG_PPPD l2tp_log (LOG_DEBUG, "%s: I'm running: \n", __FUNCTION__); for (x = 0; stropt[x]; x++) { l2tp_log (LOG_DEBUG, "\"%s\" \n", stropt[x]); }; #endif #ifdef __uClinux__ c->pppd = vfork (); #else c->pppd = fork (); #endif if (c->pppd < 0) { /* parent */ l2tp_log(LOG_WARNING,"%s: unable to fork(), abandoning!\n", __FUNCTION__); close(fd2); return -EINVAL; } else if (!c->pppd) { /* child */ close (0); /* redundant; the dup2() below would do that, too */ close (1); /* ditto */ /* close (2); No, we want to keep the connection to /dev/null. */ #ifdef USE_KERNEL if (!kernel_support) #endif { /* connect the pty to stdin and stdout */ dup2 (fd2, 0); dup2 (fd2, 1); close(fd2); } /* close all the calls pty fds */ st = tunnels.head; while (st) { #ifdef USE_KERNEL if (kernel_support) { if(st->udp_fd!=-1) close(st->udp_fd); /* tunnel UDP fd */ if(st->pppox_fd!=-1) close(st->pppox_fd); /* tunnel PPPoX fd */ } else #endif { sc = st->call_head; while (sc) { if(sc->fd!=-1) close (sc->fd); /* call pty fd */ sc = sc->next; } } st = st->next; } /* close the UDP socket fd */ if(server_socket!=-1) close (server_socket); /* close the control pipe fd */ if(control_fd!=-1) close (control_fd); if( c->dialing[0] ) { setenv( "CALLER_ID", c->dialing, 1 ); } execv (PPPD, stropt); l2tp_log (LOG_WARNING, "%s: Exec of %s failed!\n", __FUNCTION__, PPPD); _exit (1); } close (fd2); pos = 0; while (stropt[pos]) { free (stropt[pos]); pos++; }; return 0; } void destroy_tunnel (struct tunnel *t) { /* * Immediately destroy a tunnel (and all its calls) * and free its resources. This may be called * by the tunnel itself,so it needs to be * "suicide safe" */ struct call *c, *me, *next; struct tunnel *p; struct timeval tv; if (!t) return; /* * Save ourselves until the very * end, since we might be calling this ourselves. * We must divorce ourself from the tunnel * structure, however, to avoid recursion * because of the logic of the destroy_call */ me = t->self; /* * Destroy all the member calls */ c = t->call_head; while (c) { next = c->next; destroy_call (c); c = next; }; /* * Remove ourselves from the list of tunnels */ if (tunnels.head == t) { tunnels.head = t->next; tunnels.count--; } else { p = tunnels.head; if (p) { while (p->next && (p->next != t)) p = p->next; if (p->next) { p->next = t->next; tunnels.count--; } else { l2tp_log (LOG_WARNING, "%s: unable to locate tunnel in tunnel list\n", __FUNCTION__); } } else { l2tp_log (LOG_WARNING, "%s: tunnel list is empty!\n", __FUNCTION__); } } if (t->lac) { t->lac->t = NULL; if (t->lac->redial && (t->lac->rtimeout > 0) && !t->lac->rsched && t->lac->active) { l2tp_log (LOG_INFO, "Will redial in %d seconds\n", t->lac->rtimeout); tv.tv_sec = t->lac->rtimeout; tv.tv_usec = 0; t->lac->rsched = schedule (tv, magic_lac_dial, t->lac); } } /* XXX L2TP/IPSec: remove relevant SAs here? NTB 20011010 * XXX But what if another tunnel is using same SA? */ if (t->lns) t->lns->t = NULL; if (t->chal_us.challenge) free (t->chal_us.challenge); if (t->chal_them.challenge) free (t->chal_them.challenge); /* we need no free(t->chal_us.vector) here because we malloc() and free() the memory pointed to by t->chal_us.vector at some other place */ if (t->chal_them.vector) free (t->chal_them.vector); if (t->pppox_fd > -1 ) close (t->pppox_fd); if (t->udp_fd > -1 ) close (t->udp_fd); destroy_call (me); free (t); } static struct tunnel *l2tp_call (char *host, int port, struct lac *lac, struct lns *lns) { /* * Establish a tunnel from us to host * on port port */ struct call *tmp = NULL; struct hostent *hp; struct in_addr addr; port = htons (port); hp = gethostbyname (host); if (!hp) { l2tp_log (LOG_WARNING, "Host name lookup failed for %s.\n", host); return NULL; } bcopy (hp->h_addr, &addr.s_addr, hp->h_length); /* Force creation of a new tunnel and set it's tid to 0 to cause negotiation to occur */ /* * to do IPsec properly here, we need to set a socket policy, * and/or communicate with pluto. */ tmp = get_call (0, 0, addr, port, IPSEC_SAREF_NULL, IPSEC_SAREF_NULL); if (!tmp) { l2tp_log (LOG_WARNING, "%s: Unable to create tunnel to %s.\n", __FUNCTION__, host); return NULL; } tmp->container->tid = 0; tmp->container->lac = lac; tmp->container->lns = lns; tmp->lac = lac; tmp->lns = lns; if (lac) lac->t = tmp->container; if (lns) lns->t = tmp->container; /* * Since our state is 0, we will establish a tunnel now */ l2tp_log (LOG_NOTICE, "Connecting to host %s, port %d\n", host, ntohs (port)); control_finish (tmp->container, tmp); return tmp->container; } static void magic_lac_tunnel (void *data) { struct lac *lac; lac = (struct lac *) data; if (!lac) { l2tp_log (LOG_WARNING, "%s: magic_lac_tunnel: called on NULL lac!\n", __FUNCTION__); return; } if (lac->lns) { /* FIXME: I should try different LNS's if I get failures */ l2tp_call (lac->lns->hostname, lac->lns->port, lac, NULL); } else if (deflac && deflac->lns) { l2tp_call (deflac->lns->hostname, deflac->lns->port, lac, NULL); } else { l2tp_log (LOG_WARNING, "%s: Unable to find hostname to dial for '%s'\n", __FUNCTION__, lac->entname); } } static struct call *lac_call (int tid, struct lac *lac, struct lns *lns) { struct tunnel *t = tunnels.head; struct call *tmp; while (t) { if (t->ourtid == tid) { tmp = new_call (t); if (!tmp) { l2tp_log (LOG_WARNING, "%s: unable to create new call\n", __FUNCTION__); return NULL; } tmp->next = t->call_head; t->call_head = tmp; t->count++; tmp->cid = 0; tmp->lac = lac; tmp->lns = lns; if (lac) lac->c = tmp; l2tp_log (LOG_NOTICE, "Calling on tunnel %d\n", tid); strcpy (tmp->dial_no, dial_no_tmp); /* jz: copy dialnumber to tmp->dial_no */ control_finish (t, tmp); return tmp; } t = t->next; }; l2tp_log (LOG_DEBUG, "%s: No such tunnel %d to generate call.\n", __FUNCTION__, tid); return NULL; } void magic_lac_dial (void *data) { struct lac *lac; lac = (struct lac *) data; if (!lac) { l2tp_log (LOG_WARNING, "%s : called on NULL lac!\n", __FUNCTION__); return; } if (!lac->active) { l2tp_log (LOG_DEBUG, "%s: LAC %s not active", __FUNCTION__, lac->entname); return; } lac->rsched = NULL; lac->rtries++; if (lac->rmax && (lac->rtries > lac->rmax)) { l2tp_log (LOG_INFO, "%s: maximum retries exceeded.\n", __FUNCTION__); return; } if (!lac->t) { #ifdef DEGUG_MAGIC l2tp_log (LOG_DEBUG, "%s : tunnel not up! Connecting!\n", __FUNCTION__); #endif magic_lac_tunnel (lac); return; } lac_call (lac->t->ourtid, lac, NULL); } static void lac_hangup (int cid) { struct tunnel *t = tunnels.head; struct call *tmp; while (t) { tmp = t->call_head; while (tmp) { if (tmp->ourcid == cid) { l2tp_log (LOG_INFO, "%s :Hanging up call %d, Local: %d, Remote: %d\n", __FUNCTION__, tmp->serno, tmp->ourcid, tmp->cid); strcpy (tmp->errormsg, "Goodbye!"); /* tmp->needclose = -1; */ kill (tmp->pppd, SIGTERM); return; } tmp = tmp->next; } t = t->next; }; l2tp_log (LOG_DEBUG, "%s : No such call %d to hang up.\n", __FUNCTION__, cid); return; } static void lac_disconnect (int tid) { struct tunnel *t = tunnels.head; while (t) { if (t->ourtid == tid) { l2tp_log (LOG_INFO, "Disconnecting from %s, Local: %d, Remote: %d\n", IPADDY (t->peer.sin_addr), t->ourtid, t->tid); t->self->needclose = -1; strcpy (t->self->errormsg, "Goodbye!"); call_close (t->self); return; } t = t->next; }; l2tp_log (LOG_DEBUG, "No such tunnel %d to hang up.\n", tid); return; } struct tunnel *new_tunnel () { struct tunnel *tmp = calloc (1, sizeof (struct tunnel)); unsigned char entropy_buf[2] = "\0"; if (!tmp) return NULL; tmp->debug = -1; tmp->tid = -1; #ifndef TESTING /* while(get_call((tmp->ourtid = rand() & 0xFFFF),0,0,0)); */ /* tmp->ourtid = rand () & 0xFFFF; */ /* get_entropy((char *)&tmp->ourtid, 2); */ get_entropy(entropy_buf, 2); { unsigned short *temp; temp = (unsigned short *)entropy_buf; tmp->ourtid = *temp & 0xFFFF; #ifdef DEBUG_ENTROPY l2tp_log(LOG_DEBUG, "ourtid = %u, entropy_buf = %hx\n", tmp->ourtid, *temp); #endif } #else tmp->ourtid = 0x6227; #endif tmp->peer.sin_family = AF_INET; bzero (&(tmp->peer.sin_addr), sizeof (tmp->peer.sin_addr)); #ifdef SANITY tmp->sanity = -1; #endif tmp->qtid = -1; tmp->ourfc = ASYNC_FRAMING | SYNC_FRAMING; tmp->ourtb = (((_u64) rand ()) << 32) | ((_u64) rand ()); tmp->fc = -1; /* These really need to be specified by the peer */ tmp->bc = -1; /* And we want to know if they forgot */ if (!(tmp->self = new_call (tmp))) { free (tmp); return NULL; }; tmp->ourrws = DEFAULT_RWS_SIZE; tmp->self->ourfbit = FBIT; tmp->rxspeed = DEFAULT_RX_BPS; tmp->txspeed = DEFAULT_TX_BPS; memset (tmp->chal_us.reply, 0, MD_SIG_SIZE); memset (tmp->chal_them.reply, 0, MD_SIG_SIZE); tmp->chal_them.vector = malloc (VECTOR_SIZE); return tmp; } static void write_res (FILE* res_file, const char *fmt, ...) { if (!res_file || ferror (res_file) || feof (res_file)) return; va_list args; va_start (args, fmt); vfprintf (res_file, fmt, args); va_end (args); } static int parse_one_line (char* bufp, int context, void* tc) { /* FIXME: I should check for incompatible options */ char *s, *d, *t; int linenum = 0; s = strtok (bufp, ";"); // parse options token by token while (s != NULL) { linenum++; while ((*s < 33) && *s) s++; /* Skip over beginning white space */ t = s + strlen (s); while ((t >= s) && (*t < 33)) *(t--) = 0; /* Ditch trailing white space */ if (!strlen (s)) continue; if (!(t = strchr (s, '='))) { l2tp_log (LOG_WARNING, "%s: token %d: no '=' in data\n", __FUNCTION__, linenum); return -1; } d = t; d--; t++; while ((d >= s) && (*d < 33)) d--; d++; *d = 0; while (*t && (*t < 33)) t++; #ifdef DEBUG_CONTROL l2tp_log (LOG_DEBUG, "%s: field is %s, value is %s\n", __FUNCTION__, s, t); #endif /* Okay, bit twidling is done. Let's handle this */ switch (parse_one_option (s, t, context, tc)) { case -1: l2tp_log (LOG_WARNING, "%s: error token %d\n", __FUNCTION__, linenum); return -1; case -2: l2tp_log (LOG_CRIT, "%s: token %d: Unknown field '%s'\n", __FUNCTION__, linenum, s); return -1; } s = strtok (NULL, ";"); } return 0; } static int parse_one_line_lac (char* bufp, struct lac *tc){ return parse_one_line(bufp, CONTEXT_LAC, tc); } static int parse_one_line_lns (char* bufp, struct lns *tc){ return parse_one_line(bufp, CONTEXT_LNS, tc); } static struct lns* find_lns_by_name(char* name){ struct lns *cursor; /* ml: First check to see if we are searching for default */ if(strcmp(name, "default") == 0){ return deflns; } cursor = lnslist; while (cursor) { if(strcasecmp (cursor->entname, name) ==0){ return cursor; } cursor = cursor->next; }; return NULL; /* ml: Ok we could not find anything*/ } static int control_handle_available(FILE* resf, char* bufp) { UNUSED(bufp); struct lac *lac; struct lns *lns; write_res (resf, "%02i OK\n", 0); lns = lnslist; int lns_count = 0; while (lns) { write_res (resf, "%02i AVAILABLE lns.%d.name=%s\n", 0, lns_count, lns->entname); lns_count++; lns= lns->next; }; /* Can the default really be NULL?*/ if(deflns){ write_res (resf, "%02i AVAILABLE lns.%d.name=%s\n", 0, lns_count, deflns->entname); lns_count++; } write_res (resf, "%02i AVAILABLE lns.count=%d\n", 0, lns_count); lac = laclist; int lac_count = 0; while (lac) { write_res (resf, "%02i AVAILABLE lac.%d.name=%s\n", 0, lac_count, lac->entname); lac_count++; lac= lac->next; }; if(deflac){ write_res (resf, "%02i AVAILABLE lac.%d.name=%s\n", 0, lac_count, deflac->entname); lac_count++; } write_res (resf, "%02i AVAILABLE lac.count=%d\n", 0, lac_count); struct tunnel *st; st = tunnels.head; while (st) { write_res (resf, "%02i AVAILABLE tunnel %p, id %d, ourtid %d has %d calls and self %p\n", 0, st, st->tid, st->ourtid, st->count, st->self); st = st->next; } write_res (resf, "%02i AVAILABLE tunnels count=%d\n", 0, tunnels.count); write_res (resf, "%02i AVAILABLE calls count=%d\n", 0, tunnels.calls); return 1; } static int control_handle_lns_add_modify(FILE* resf, char* bufp){ struct lns *lns; char* tunstr; char delims[] = " "; tunstr = strtok (&bufp[1], delims); lns = find_lns_by_name(tunstr); if(!lns){ lns = new_lns(); if(lns){ /* This seems a bit stupid, but new_lns() can return NULL */ /* ml: Give me a name please :) */ strncpy (lns->entname, tunstr, sizeof (lns->entname)); /* ml: Is there any good reason why I cant add it now? */ lns->next = lnslist; lnslist = lns; } } if(lns){ bufp = tunstr + strlen (tunstr) + 1; if (parse_one_line_lns (bufp, lns)) { write_res (resf, "%02i Configuration parse error\n", 3); }else{ write_res (resf, "%02i OK: Saved value\n", 0); } }else{ write_res (resf, "%02i Error: Could not find lns and could not create it\n", 1); } return 1; } static int control_handle_lns_remove(FILE* resf, char* bufp){ char *tunstr; struct lns* lns; struct lns* prev_lns; struct tunnel* t; struct call* c; tunstr = strchr (bufp, ' ') + 1; lns = lnslist; prev_lns = NULL; while (lns && strcasecmp (lns->entname, tunstr) != 0) { prev_lns = lns; lns= lns->next; } if (!lns) { l2tp_log (LOG_DEBUG, "No such tunnel '%s'\n", tunstr); write_res (resf, "%02i No such tunnel '%s'\n", 1, tunstr); return 0; } /* We need to destroy the tunnels associated with this guy */ t = tunnels.head; while(t){ if(t->lns == lns){ c = t->call_head; while (c) { call_close (c); c = c->next; }; } t = t->next; } if (prev_lns == NULL){ lnslist = lns->next; }else{ prev_lns->next = lns->next; } free(lns); write_res (resf, "%02i OK\n", 0); return 1; } static int control_handle_lns_status(FILE* resf, char* bufp){ struct lns *lns; char* tunstr; char delims[] = " "; tunstr = strtok (&bufp[1], delims); lns = find_lns_by_name(tunstr); if(lns){ /* Lets keep it simple, what is useful first */ write_res (resf, "%02i OK\n", 0); int active_tunnel_count = 0; struct tunnel* t = tunnels.head; while(t){ if(t->lns == lns){ /* Lets provide some information on each tunnel */ write_res (resf, "%02i STATUS tunnels.%d.id=%d\n", 0, active_tunnel_count, t->tid); write_res (resf, "%02i STATUS tunnels.%d.peer=%s:%d\n", 0, active_tunnel_count, IPADDY (t->peer.sin_addr), ntohs (t->peer.sin_port)); /* And some call stats */ struct call *c = t->call_head; int active_call_count = 0; while(c){ write_res (resf, "%02i STATUS tunnels.%d.calls.%d.id=%d\n", 0, active_tunnel_count, active_call_count, c->ourcid); write_res (resf, "%02i STATUS tunnels.%d.calls.%d.tx_bytes=%d\n", 0, active_tunnel_count, active_call_count, c->tx_bytes); write_res (resf, "%02i STATUS tunnels.%d.calls.%d.rx_bytes=%d\n", 0, active_tunnel_count, active_call_count, c->rx_bytes); write_res (resf, "%02i STATUS tunnels.%d.calls.%d.tx_pkts=%d\n", 0, active_tunnel_count, active_call_count, c->tx_pkts); write_res (resf, "%02i STATUS tunnels.%d.calls.%d.rx_pkts=%d\n", 0, active_tunnel_count, active_call_count, c->rx_pkts); c = c->next; active_call_count++; } write_res (resf, "%02i STATUS tunnels.%d.calls.count=%d\n", 0, active_tunnel_count, active_call_count); active_tunnel_count++; } t = t->next; } write_res (resf, "%02i STATUS tunnels.count=%d\n", 0, active_tunnel_count); }else{ write_res (resf, "%02i Error: Could not find lns\n", 1); } return 1; } static int control_handle_tunnel(FILE* resf, char* bufp){ char* host; host = strchr (bufp, ' ') + 1; #ifdef DEBUG_CONTROL l2tp_log (LOG_DEBUG, "%s: Attempting to tunnel to %s\n", __FUNCTION__, host); #endif if (l2tp_call (host, UDP_LISTEN_PORT, NULL, NULL)) write_res (resf, "%02i OK\n", 0); else write_res (resf, "%02i Error\n", 1); return 1; } static int control_handle_lac_connect(FILE* resf, char* bufp){ char* tunstr = NULL; char* authname= NULL; char* password = NULL; int tunl = 0; char delims[] = " "; struct lac* lac; switch_io = 1; /* jz: Switch for Incoming - Outgoing Calls */ tunstr = strtok (&bufp[1], delims); /* Are these passed on the command line? */ authname = strtok (NULL, delims); password = strtok (NULL, delims); lac = laclist; while (lac && strcasecmp (lac->entname, tunstr)!=0) { lac = lac->next; } if(lac) { lac->active = -1; lac->rtries = 0; if (authname != NULL) strncpy (lac->authname, authname, STRLEN); if (password != NULL) strncpy (lac->password, password, STRLEN); if (!lac->c) { magic_lac_dial (lac); write_res (resf, "%02i OK\n", 0); } else { l2tp_log (LOG_DEBUG, "Session '%s' already active!\n", lac->entname); write_res (resf, "%02i Session '%s' already active!\n", 1, lac->entname); } return 0; } /* did not find a tunnel by name, look by number */ tunl = atoi (tunstr); if (!tunl) { l2tp_log (LOG_DEBUG, "No such tunnel '%s'\n", tunstr); write_res (resf, "%02i No such tunnel '%s'\n", 1, tunstr); return 0; } #ifdef DEBUG_CONTROL l2tp_log (LOG_DEBUG, "%s: Attempting to call on tunnel %d\n", __FUNCTION__, tunl); #endif if (lac_call (tunl, NULL, NULL)) write_res (resf, "%02i OK\n", 0); else write_res (resf, "%02i Error\n", 1); return 1; } static int control_handle_lac_outgoing_call(FILE* resf, char* bufp){ char* sub_str; char* tunstr; char* tmp_ptr; struct lac* lac; int tunl; switch_io = 0; /* jz: Switch for incoming - outgoing Calls */ sub_str = strchr (bufp, ' ') + 1; tunstr = strtok (sub_str, " "); /* jz: using strtok function to get */ tmp_ptr = strtok (NULL, " "); /* params out of the pipe */ strcpy (dial_no_tmp, tmp_ptr); lac = laclist; while (lac && strcasecmp (lac->entname, tunstr)!=0) { lac = lac->next; } if(lac) { lac->active = -1; lac->rtries = 0; if (!lac->c) { magic_lac_dial (lac); write_res (resf, "%02i OK\n", 0); } else { l2tp_log (LOG_DEBUG, "Session '%s' already active!\n", lac->entname); write_res (resf, "%02i Session '%s' already active!\n", 1, lac->entname); } return 0; } /* did not find a tunnel by name, look by number */ tunl = atoi (tunstr); if (!tunl) { l2tp_log (LOG_DEBUG, "No such tunnel '%s'\n", tunstr); write_res (resf, "%02i No such tunnel '%s'\n", 1, tunstr); return 0; } #ifdef DEBUG_CONTROL l2tp_log (LOG_DEBUG, "%s: Attempting to call on tunnel %d\n", __FUNCTION__, tunl); #endif if (lac_call (tunl, NULL, NULL)) write_res (resf, "%02i OK\n", 0); else write_res (resf, "%02i Error\n", 1); return 1; } static int control_handle_lac_hangup(FILE* resf, char* bufp){ char* callstr; int call; callstr = strchr (bufp, ' ') + 1; call = atoi (callstr); #ifdef DEBUG_CONTROL l2tp_log (LOG_DEBUG, "%s: Attempting to hangup call %d\n", __FUNCTION__, call); #endif lac_hangup (call); write_res (resf, "%02i OK\n", 0); return 1; } static int control_handle_lac_disconnect(FILE* resf, char* bufp){ char* tunstr; struct lac* lac; int tunl = 0; tunstr = strchr (bufp, ' ') + 1; lac = laclist; while (lac) { if (!strcasecmp (lac->entname, tunstr)) { lac->active = 0; lac->rtries = 0; if (lac->t) { lac_disconnect (lac->t->ourtid); write_res (resf, "%02i OK\n", 0); } else { l2tp_log (LOG_DEBUG, "Session '%s' not up\n", lac->entname); write_res (resf, "%02i Session '%s' not up\n", 1, lac->entname); } return 0; } lac = lac->next; } if (lac) return 0; tunl = atoi (tunstr); if (!tunl) { l2tp_log (LOG_DEBUG, "No such tunnel '%s'\n", tunstr); write_res (resf, "%02i No such tunnel '%s'\n", 1, tunstr); return 0; } #ifdef DEBUG_CONTROL l2tp_log (LOG_DEBUG, "%s: Attempting to disconnect tunnel %d\n", __FUNCTION__, tunl); #endif lac_disconnect (tunl); write_res (resf, "%02i OK\n", 0); return 1; } static int control_handle_lac_add_modify(FILE* resf, char* bufp){ char* tunstr; struct lac* lac; char delims[] = " "; int create_new_lac = 0; tunstr = strtok (&bufp[1], delims); if ((!tunstr) || (!strlen (tunstr))) { write_res (resf, "%02i Configuration parse error: lac-name expected\n", 1); l2tp_log (LOG_CRIT, "%s: lac-name expected\n", __FUNCTION__); return 0; } /* go to the end of tunnel name*/ bufp = tunstr + strlen (tunstr) + 1; /* try to find lac with _tunstr_ name in laclist */ lac = laclist; while (lac) { if (!strcasecmp (tunstr, lac->entname)) return 0; lac = lac->next; } /* nothing found, create new lac */ lac = new_lac (); if (!lac) { write_res (resf, "%02i Could't create new lac: no memory\n", 2); l2tp_log (LOG_CRIT, "%s: Couldn't create new lac\n", __FUNCTION__); return 0; } create_new_lac = 1; strncpy (lac->entname, tunstr, sizeof (lac->entname)); if (parse_one_line_lac (bufp, lac)) { write_res (resf, "%02i Configuration parse error\n", 3); return 0; } if (create_new_lac) { lac->next = laclist; laclist = lac; } if (lac->autodial) { #ifdef DEBUG_MAGIC l2tp_log (LOG_DEBUG, "%s: Autodialing '%s'\n", __FUNCTION__, lac->entname[0] ? lac->entname : "(unnamed)"); #endif lac->active = -1; switch_io = 1; /* If we're a LAC, autodials will be ICRQ's */ magic_lac_dial (lac); /* FIXME: Should I check magic_lac_dial result somehow? */ } write_res (resf, "%02i OK\n", 0); return 1; } static int control_handle_lac_remove(FILE* resf, char* bufp){ char *tunstr; struct lac* lac; struct lac* prev_lac; // find lac in laclist tunstr = strchr (bufp, ' ') + 1; lac = laclist; prev_lac = NULL; while (lac && strcasecmp (lac->entname, tunstr) != 0) { prev_lac = lac; lac = lac->next; } if (!lac) { l2tp_log (LOG_DEBUG, "No such tunnel '%s'\n", tunstr); write_res (resf, "%02i No such tunnel '%s'\n", 1, tunstr); return 0; } // disconnect lac lac->active = 0; lac->rtries = 0; if (lac->t) { lac_disconnect (lac->t->ourtid); /* destroy_tunnel may clear lac->t */ if (lac->t) { lac->t->lac = NULL; if(lac->t->self) lac->t->self->lac = NULL; } } if (lac->c) { struct call *c = lac->c; while (c) { c->lac = NULL; c = c->next; } } if (lac->lns) { struct host *t, *h = lac->lns; while (h) { t = h->next; free(h); h = t; } } // removes lac from laclist if (prev_lac == NULL) laclist = lac->next; else prev_lac->next = lac->next; free(lac); write_res (resf, "%02i OK\n", 0); return 1; } static int control_handle_lac_status(){ show_status (); return 1; } void do_control () { char buf[CONTROL_PIPE_MESSAGE_SIZE]; char *bufp; /* current buffer pointer */ int cnt = -1; int done = 0; int handler_found = 0; struct control_requests_handler* handler = NULL; bzero(buf, sizeof(buf)); buf[0]='\0'; char* res_filename; /* name of file to write result of command */ FILE* resf; /* stream for write result of command */ while (!done) { cnt = read (control_fd, buf, sizeof (buf)); if (cnt <= 0) { if(cnt < 0 && errno != EINTR) { perror("controlfd"); } done = 1; break; } if (buf[cnt - 1] == '\n') buf[--cnt] = 0; #ifdef DEBUG_CONTROL l2tp_log (LOG_DEBUG, "%s: Got message %s (%d bytes long)\n", __FUNCTION__, buf, cnt); #endif bufp = buf; /* check if caller want to get result */ if (bufp[0] == '@') { /* parse filename (@/path/to/file *...), where * is command */ res_filename = &bufp[1]; int fnlength = strcspn(res_filename, " "); if ((fnlength == 0) || (res_filename[fnlength] == '\0')){ l2tp_log (LOG_DEBUG, "%s: Can't parse result filename or command\n", __FUNCTION__ ); continue; } res_filename[fnlength] = '\0'; bufp = &res_filename[fnlength + 1]; /* skip filename in bufp */ /*FIXME: check quotes to allow filenames with spaces? (do not forget quotes escaping to allow filenames with quotes)*/ resf = fopen (res_filename, "w"); if (!resf) { l2tp_log (LOG_DEBUG, "%s: Can't open result file %s\n", __FUNCTION__, res_filename); continue; } }else{ resf = NULL; res_filename = NULL; /* to avoid 'may be used unitialized' warning */ } /* Search for a handler based on request type */ for(handler = control_handlers; handler->handler; handler++){ /* If handler is found, then handle the request and set handler_found = 1 */ if(handler->type == bufp[0]){ handler->handler(resf, bufp); handler_found = 1; break; } } /* Does nto appear as though we found a handler, so respond with an error*/ if(!handler_found){ l2tp_log (LOG_DEBUG, "Unknown command %c\n", bufp[0]); write_res (resf, "%02i Unknown command %c\n", 1, bufp[0]); } if (resf) { fclose (resf); /* unlink it anyway to prevent leftover a regular file. */ unlink(res_filename); } } /* Otherwise select goes nuts. Yeah, this just seems wrong */ close (control_fd); open_controlfd(); } static void usage(void) { printf("\nxl2tpd version: %s\n", SERVER_VERSION); printf("Usage: xl2tpd [-c ] [-s ] [-p ]\n" " [-C ] [-D] [-l] [-q ]\n" " [-v, --version]\n"); printf("\n"); exit(1); } static void init_args(int argc, char *argv[]) { int i=0; gconfig.daemon=1; gconfig.syslog=-1; memset(gconfig.altauthfile,0,STRLEN); memset(gconfig.altconfigfile,0,STRLEN); memset(gconfig.authfile,0,STRLEN); memset(gconfig.configfile,0,STRLEN); memset(gconfig.pidfile,0,STRLEN); memset(gconfig.controlfile,0,STRLEN); memset(gconfig.controltos,0,STRLEN); strncpy(gconfig.altauthfile,ALT_DEFAULT_AUTH_FILE, sizeof(gconfig.altauthfile) - 1); strncpy(gconfig.altconfigfile,ALT_DEFAULT_CONFIG_FILE, sizeof(gconfig.altconfigfile) - 1); strncpy(gconfig.authfile,DEFAULT_AUTH_FILE, sizeof(gconfig.authfile) - 1); strncpy(gconfig.configfile,DEFAULT_CONFIG_FILE, sizeof(gconfig.configfile) - 1); strncpy(gconfig.pidfile,DEFAULT_PID_FILE, sizeof(gconfig.pidfile) - 1); strncpy(gconfig.controlfile,CONTROL_PIPE, sizeof(gconfig.controlfile) - 1); gconfig.ipsecsaref = 0; for (i = 1; i < argc; i++) { if ((! strncmp(argv[i],"--version",9)) || (! strncmp(argv[i],"-v",2))) { printf("\nxl2tpd version: %s\n",SERVER_VERSION); exit(1); } if(! strncmp(argv[i],"-c",2)) { if(++i == argc) usage(); else strncpy(gconfig.configfile,argv[i], sizeof(gconfig.configfile) - 1); } else if (! strncmp(argv[i],"-D",2)) { gconfig.daemon=0; } else if (! strncmp(argv[i],"-l",2)) { gconfig.syslog=1; } else if (! strncmp(argv[i],"-s",2)) { if(++i == argc) usage(); else strncpy(gconfig.authfile,argv[i], sizeof(gconfig.authfile) - 1); } else if (! strncmp(argv[i],"-p",2)) { if(++i == argc) usage(); else strncpy(gconfig.pidfile,argv[i], sizeof(gconfig.pidfile) - 1); } else if (! strncmp(argv[i],"-C",2)) { if(++i == argc) usage(); else strncpy(gconfig.controlfile,argv[i], sizeof(gconfig.controlfile) - 1); } else if (! strncmp(argv[i],"-q",2)) { if(++i == argc) usage(); else { strncpy(gconfig.controltos,argv[i], sizeof(gconfig.controltos) - 1); if (atoi(gconfig.controltos)<0 || atoi(gconfig.controltos)>255) { printf ("TOS value %s out of range(0-255)!\n", gconfig.controltos); usage(); } } } else { usage(); } } /* * defaults to syslog if no log facility was explicitly * specified and we are about to daemonize */ if (gconfig.syslog < 0) gconfig.syslog = gconfig.daemon; } static void daemonize() { int pid=0; int i; #ifndef CONFIG_SNAPGEAR if((pid = fork()) < 0) { l2tp_log(LOG_INFO, "%s: Unable to fork ()\n",__FUNCTION__); close(server_socket); exit(1); } else if (pid) { close(server_socket); closelog(); exit(0); } close(0); i = open("/dev/null", O_RDWR); if (i == -1) { l2tp_log(LOG_INFO, "Redirect of stdin to /dev/null failed\n"); } else { if (dup2(0, 1) == -1) l2tp_log(LOG_INFO, "Redirect of stdout to /dev/null failed\n"); if (dup2(0, 2) == -1) l2tp_log(LOG_INFO, "Redirect of stderr to /dev/null failed\n"); close(i); } #endif } static void consider_pidfile() { int pid=0; int i,l; char buf[STRLEN]; /* Read previous pid file. */ i = open(gconfig.pidfile,O_RDONLY); if (i < 0) { /* l2tp_log(LOG_DEBUG, "%s: Unable to read pid file [%s]\n", __FUNCTION__, gconfig.pidfile); */ } else { l=read(i,buf,sizeof(buf)-1); close (i); if (l >= 0) { buf[l] = '\0'; pid = atoi(buf); } /* If the previous server process is still running, complain and exit immediately. */ if (pid && pid != getpid () && kill (pid, 0) == 0) { l2tp_log(LOG_INFO, "%s: There's already a xl2tpd server running.\n", __FUNCTION__); close(server_socket); exit(1); } } pid = setsid(); unlink(gconfig.pidfile); if ((i = open (gconfig.pidfile, O_WRONLY | O_CREAT, 0640)) >= 0) { snprintf (buf, sizeof(buf), "%d\n", (int)getpid()); if (-1 == write (i, buf, strlen(buf))) { l2tp_log (LOG_CRIT, "%s: Unable to write to %s.\n", __FUNCTION__, gconfig.pidfile); close (i); exit(1); } close (i); } } static void open_controlfd() { control_fd = open (gconfig.controlfile, O_RDONLY | O_NONBLOCK, 0600); if (control_fd < 0) { l2tp_log (LOG_CRIT, "%s: Unable to open %s for reading.\n", __FUNCTION__, gconfig.controlfile); exit (1); } /* turn off O_NONBLOCK */ if(fcntl(control_fd, F_SETFL, O_RDONLY)==-1) { l2tp_log(LOG_CRIT, "Can not turn off nonblocking mode for controlfd: %s\n", strerror(errno)); exit(1); } } static void init (int argc,char *argv[]) { struct lac *lac; struct in_addr listenaddr; struct utsname uts; init_args (argc,argv); srand( time(NULL) ); rand_source = 0; init_addr (); if (init_config ()) { l2tp_log (LOG_CRIT, "%s: Unable to load config file\n", __FUNCTION__); exit (1); } if (uname (&uts)<0) { l2tp_log (LOG_CRIT, "%s : Unable to determine host system\n", __FUNCTION__); exit (1); } init_tunnel_list (&tunnels); if (init_network ()) exit (1); if (gconfig.daemon) daemonize (); consider_pidfile(); signal (SIGTERM, &sigterm_handler); signal (SIGINT, &sigint_handler); signal (SIGCHLD, &sigchld_handler); signal (SIGUSR1, &sigusr1_handler); signal (SIGHUP, &sighup_handler); signal (SIGPIPE, SIG_IGN); init_scheduler (); unlink(gconfig.controlfile); mkfifo (gconfig.controlfile, 0600); open_controlfd(); l2tp_log (LOG_INFO, "xl2tpd version " SERVER_VERSION " started on %s PID:%d\n", hostname, getpid ()); l2tp_log (LOG_INFO, "Written by Mark Spencer, Copyright (C) 1998, Adtran, Inc.\n"); l2tp_log (LOG_INFO, "Forked by Scott Balmos and David Stipp, (C) 2001\n"); l2tp_log (LOG_INFO, "Inherited by Jeff McAdams, (C) 2002\n"); l2tp_log (LOG_INFO, "Forked again by Xelerance (www.xelerance.com) (C) 2006-2016\n"); listenaddr.s_addr = gconfig.listenaddr; l2tp_log (LOG_INFO, "Listening on IP address %s, port %d\n", inet_ntoa(listenaddr), gconfig.port); lac = laclist; while (lac) { if (lac->autodial) { #ifdef DEBUG_MAGIC l2tp_log (LOG_DEBUG, "%s: Autodialing '%s'\n", __FUNCTION__, lac->entname[0] ? lac->entname : "(unnamed)"); #endif lac->active = -1; switch_io = 1; /* If we're a LAC, autodials will be ICRQ's */ magic_lac_dial (lac); } lac = lac->next; } } int main (int argc, char *argv[]) { init(argc,argv); dial_no_tmp = calloc (128, sizeof (char)); network_thread (); return 0; }