diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000..c9ad81c
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,131 @@
+project(n2n)
+cmake_minimum_required(VERSION 2.6)
+
+# N2n information
+set(N2N_VERSION 2.1.0)
+set(N2N_OSNAME ${CMAKE_SYSTEM})
+
+# N2n specific params
+if(NOT DEFINED N2N_OPTION_AES)
+set(N2N_OPTION_AES ON)
+endif(NOT DEFINED N2N_OPTION_AES)
+
+add_definitions(-DN2N_VERSION='\"${N2N_VERSION}\"' -DN2N_OSNAME='\"${N2N_OSNAME}\"')
+
+if(N2N_OPTION_AES)
+add_definitions(-DN2N_HAVE_AES)
+endif(N2N_OPTION_AES)
+
+# Build information
+if(NOT DEFINED BUILD_SHARED_LIBS)
+set(BUILD_SHARED_LIBS OFF)
+endif(NOT DEFINED BUILD_SHARED_LIBS)
+
+if(NOT DEFINED CMAKE_BUILD_TYPE)
+set(CMAKE_BUILD_TYPE None)
+endif(NOT DEFINED CMAKE_BUILD_TYPE)
+#set(CMAKE_BUILD_TYPE Debug)
+#set(CMAKE_BUILD_TYPE Release)
+
+#Ultrasparc64 users experiencing SIGBUS should try the following gcc options
+#(thanks to Robert Gibbon)
+#PLATOPTS_SPARC64=-mcpu=ultrasparc -pipe -fomit-frame-pointer -ffast-math -finline-functions -fweb -frename-registers -mapp-regs
+
+# None
+set(CMAKE_C_FLAGS "-Wall -Wshadow -Wpointer-arith -Wmissing-declarations -Wnested-externs")
+set(CMAKE_CXX_FLAGS "-Wall -Wshadow -Wpointer-arith -Wmissing-declarations -Wnested-externs")
+# Debug
+set(CMAKE_C_FLAGS_DEBUG "-g")
+set(CMAKE_CXX_FLAGS_DEBUG "-g")
+# Release
+set(CMAKE_C_FLAGS_RELEASE "-O2 -DNDEBUG")
+set(CMAKE_CXX_FLAGS_RELEASE "-O2 -DNDEBUG")
+
+## DEBUG FOR CMAKE
+#message(${N2N_VERSION})
+#message(${N2N_OSNAME})
+##message(${CMAKE_BUILD_TYPE})
+#message(${N2N_OPTION_AES})
+## DEBUG FOR CMAKE
+
+add_library(n2n n2n.c
+ n2n_keyfile.c
+ wire.c
+ minilzo.c
+ twofish.c
+ transform_null.c
+ transform_tf.c
+ transform_aes.c
+ tuntap_freebsd.c
+ tuntap_netbsd.c
+ tuntap_linux.c
+ tuntap_osx.c
+ version.c
+ )
+
+if(DEFINED WIN32)
+add_subdirectory(win32)
+target_link_libraries(n2n n2n_win32)
+endif(DEFINED WIN32)
+
+if(N2N_OPTION_AES)
+target_link_libraries(n2n crypto)
+endif(N2N_OPTION_AES)
+
+# For Solaris (or OpenSolaris?)
+#target_link_libraries(n2n socket nsl)
+
+add_executable(edge edge.c)
+target_link_libraries(edge n2n)
+
+add_executable(supernode sn.c)
+target_link_libraries(supernode n2n)
+
+add_executable(test test.c)
+target_link_libraries(test n2n)
+
+add_executable(benchmark benchmark.c)
+target_link_libraries(benchmark n2n)
+
+install(TARGETS edge supernode
+ RUNTIME DESTINATION sbin
+ LIBRARY DESTINATION lib
+ ARCHIVE DESTINATION lib
+ )
+
+# Documentation
+if(DEFINED UNIX)
+add_dependencies(n2n doc)
+file(MAKE_DIRECTORY ${PROJECT_BINARY_DIR}/doc)
+add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/doc/edge.8.gz
+ COMMAND gzip -c ${PROJECT_SOURCE_DIR}/edge.8 > ${PROJECT_BINARY_DIR}/doc/edge.8.gz
+ DEPENDS ${PROJECT_SOURCE_DIR}/edge.8
+ )
+
+add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/doc/supernode.1.gz
+ COMMAND gzip -c ${PROJECT_SOURCE_DIR}/supernode.1 > ${PROJECT_BINARY_DIR}/doc/supernode.1.gz
+ DEPENDS ${PROJECT_SOURCE_DIR}/supernode.1
+ )
+
+add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/doc/n2n_v2.7.gz
+ COMMAND gzip -c ${PROJECT_SOURCE_DIR}/n2n_v2.7 > ${PROJECT_BINARY_DIR}/doc/n2n_v2.7.gz
+ DEPENDS ${PROJECT_SOURCE_DIR}/n2n_v2.7
+ )
+
+add_custom_target(doc DEPENDS ${PROJECT_BINARY_DIR}/doc/edge.8.gz
+ ${PROJECT_BINARY_DIR}/doc/supernode.1.gz
+ ${PROJECT_BINARY_DIR}/doc/n2n_v2.7.gz
+ )
+
+set_source_files_properties(${PROJECT_BINARY_DIR}/doc/edge.8.gz
+ ${PROJECT_BINARY_DIR}/doc/supernode.1.gz
+ ${PROJECT_BINARY_DIR}/doc/n2n_v2.7.gz
+ PROPERTIES GENERATED 1)
+
+install(FILES ${PROJECT_BINARY_DIR}/doc/edge.8.gz
+ DESTINATION /usr/share/man8)
+install(FILES ${PROJECT_BINARY_DIR}/doc/supernode.1.gz
+ DESTINATION /usr/share/man1)
+install(FILES ${PROJECT_BINARY_DIR}/doc/n2n_v2.7.gz
+ DESTINATION /usr/share/man7)
+endif(DEFINED UNIX)
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..b33b35d
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,674 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc.
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. 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
+them 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 prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. 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.
+
+ Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+ For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+ Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+ Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey 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;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If 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 convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Use with the GNU Affero General Public License.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU 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 that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ 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.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+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.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ 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
+state 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 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+ n2n Copyright (C) 2007-08 Luca Deri
+ This program 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, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+.
+
+ The GNU 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. But first, please read
+.
diff --git a/HACKING b/HACKING
new file mode 100644
index 0000000..8a86a03
--- /dev/null
+++ b/HACKING
@@ -0,0 +1,255 @@
+file: HACKING
+
+Last updated: 2010-01-01 09:55 UTC
+
+--------
+(C) 2008-2010 - Richard Andrews
+
+This program and document is free software; you can redistribute
+it and/or modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 3 of the
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not see see
+
+--------
+
+
+This file describes the internals of n2n. Read this before starting to modify
+the code. Because coding examples may be present in this document it is licensed
+under the GPL rather than FDL.
+
+
+SYMMETRIC NAT
+-------------
+
+Symmetric NAT is a form of firewall NAT in which an UDP packets are only passed
+back to an inside host socket when the return packets originate from the outside
+socket to which the initiating UDP packets were sent. This means that when an
+inside host sends UDP to some outside socket; other hosts cannot piggyback on
+this opening in the firewall to send data to the inside host.
+
+When two inside hosts are both behind symmetric NAT, peer-to-peer packet
+exchange is not possible via n2n. These hosts will require the supernode to
+relay packets.
+
+
+ARP CACHE
+---------
+
+n2n makes use of the host operating system's own ARP cache. Each edge node
+allocates a random MAC address to itself. This MAC is constant for the life of
+the edge process. ARP packets are passed around as broadcast ethernet packets
+over n2n and these packets cause the native ARP cache to be updated.
+
+Edge nodes send gratuitous ARP packets on startup. See GRATUITOUS ARP below.
+
+
+REGISTRATION AND PEER-TO-PEER COMMUNICATION SETUP
+-------------------------------------------------
+
+A and B are edge nodes with public sockets Apub and Bpub; and private network
+addresses A and B respectively. S is the supernode.
+
+A sends {REGISTER,Amac} to S. S registers {Amac->Apub}.
+B sends {REGISTER,Bmac} to S. S registers {Bmac->Bpub}.
+
+Now ping from A to B.
+
+A sends broadcast "arp who-has B" to S. S relays the packet to all known edge
+nodes. B replies "B at Bmac" to supernode which forwards this to A. So now ping
+A->B is known to be ping Amac(A)->Bmac(B). Note: gratuitous arp also requires
+discussion.
+
+In response to receiving the arp reply, Apub sends {REGISTER,Amac} to Bpub. If
+Bpub receives the request it sends back {REGISTER_ACK,Amac} and also sends its
+own {REGISTER,Bmac} request.
+
+In response to receiving the "arp who-has", Bpub sends {REGISTER,Bmac} to Apub.
+
+Now the OS has received the arp reply and sends ICMP to Bmac(B) via the tunnel
+on A. A looks up Bmac in the peers list and encapsulates the packet to Bpub or
+the supernode if the MAC is not found.
+
+We assume that between two edge nodes, if Bpub receives a packet from Apub then
+Apub can receive a packet from Bpub. This is the symmetric NAT case. Note: In
+the symmetric NAT case, the public socket for a MAC address will be different
+for direct contact when compared to information from the supernode.
+
+When two edge nodes are both behind symmetric NAT they cannot establish direct
+communication.
+
+If A receives {REGISTER,Bmac} from B, A adds {Bmac->Bpub} to its peers list
+knowing that Bmac is now reachable via that public socket. Similarly if B
+receives {REGISTER,Amac} from A.
+
+The supernode never forwards REGISTER messages because the public socket seen by
+the supervisor for some edge (eg. A) may be different to the socket seen by
+another edge due to the actions of symmetric NAT (alocating a new public socket
+for the new outbound UDP "connection").
+
+
+EDGE REGISTRATION DESIGN AMMENDMENTS (starting from 2008-04-10)
+------------------------------------
+
+ * Send REGISTER on rx of PACKET or REGISTER only when dest_mac == device MAC
+(do not send REGISTER on Rx of broadcast packets).
+ * After sending REGISTER add the new peer to pending_peers list; but
+ * Don't send REGISTER to a peer in pending_peers list
+ * Remove old entries from pending_peers at regular intervals
+ * On rx of REGISTER_ACK, move peer from pending_peers to known_peers for direct
+comms and set last_seen=now
+ * On rx of any packet set last_seen=now in the known_peers entry (if it
+exists); but do not add a new entry.
+ * If the public socket address for a known_peers entry changes, deleted it and
+restart registration to the new peer.
+ * Peer sockets provided by the supernode are ignored unless no other entry
+exists. Direct peer-to-peer sockets are always given more priority as the
+supernode socket will not be usable for direct contact if the peer is behind
+symmetric NAT.
+
+
+The pending_peers list concept is to prevent massive registration traffic when
+supernode relay is in force - this would occur if REGISTER was sent for every
+incident packet sent via supernode. Periodic REGISTER attempts will still occur;
+not for every received packet. In the case where the peer cannot be contacted
+(eg. both peers behind symmetric NAT), then there will still be periodic
+attempts. Suggest a pending timeout of about 60 sec.
+
+A peer is only considered operational for peer-to-peer sending when a
+REGISTER_ACK is returned. Once operational the peer is kept operational while
+any direct packet communications are occurring. REGISTER is not required to
+keep the path open through any firewalls; just some activity in one direction.
+
+After an idle period; the peer should be deleted from the known_peers list. We
+should not try to re-register when this time expires. If there is no data to
+send then forget the peer. This helps scalability.
+
+If a peer wants to be remembered it can send gratuitous ARP traffic which will
+keep its entry in the known_peers list of any peers which already have the
+entry.
+
+
+
+
+peer = find_by_src_mac( hdr, known_peers ); /* return NULL or entry */
+
+if ( peer )
+{
+ peer_last_seen = time(NULL);
+}
+else
+{
+ if ( ! is_broadcast( hdr ) ) /* ignore broadcasts */
+ {
+ if ( IS_REGISTER_ACK( hdr ) )
+ {
+ /* move from pending to known_peers */
+ set_peer_operational( hdr );
+ }
+ else
+ {
+ /* add to pending and send REGISTER - ignore if in pending. */
+ try_send_register( hdr )
+ }
+ }
+}
+
+
+(Notes):
+
+ * In testing it was noted that if a symmetric NAT firewall shuts down the UDP
+association but the known_peers registration is still active, then the peer
+becomes unreachable until the known_peers registration is deleted. Suggest two
+ways to mitigate this problem:
+ (a) make the known_peers purge timeout a config paramter;
+ (b) send packets direct and via supernode if the registration is older than
+ eg. 60 sec.
+
+
+GRATUITOUS ARP
+--------------
+
+In addition to the ARP who-has mechanism noted above, two edge nodes can become
+aware of one another by gratuitous ARP. A gratuitous ARP packet is a broadcast
+packet sent by a node for no other purpose than to announce its presence and
+identify its MAC and IP address. Gratuitous ARP packets are to keep ARP caches
+up to date so contacting the host will be faster after an long idle time.
+
+
+MAN PAGES
+---------
+
+Look at a non-installed man page like this (linux/UNIX):
+
+nroff -man edge.8 | less
+
+
+PACKET message FORMAT
+---------------------
+
+All message encoding and decoding is contained in wire.c. The PACKET message is
+of main concern as it is the most frequently transferred as it contains
+encapsulated ethernet packets.
+
+Version 2
+
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ ! Version=2 ! TTL ! Flags !
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ 4 ! Community :
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ 8 ! ... Community ... :
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+12 ! ... Community ... :
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+16 ! ... Community ... !
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+20 ! Source MAC Address :
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+24 : ! Destination MAC Address :
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+28 : !
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+32 ! Socket Flags (v=IPv4) ! Destination UDP Port !
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+36 ! Destination IPv4 Address !
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+40 ! Transform ID !
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+44 ! Payload
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+So each n2n PACKET has a 44 byte overhead. For a 1500 byte ethernet packet this
+is roughly 3%.
+
+Socket flags provides support for IPv6. In this case the PACKET message ends as
+follows:
+
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+32 ! Socket Flags (v=IPv6) ! Destination UDP Port !
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+36 ! Destination IPv6 Address :
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+40 : :
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+44 : :
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+48 : !
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+52 ! Transform ID !
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+56 ! Encapsulated ethernet payload
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+
+-------
+
+January 2010 - Richard Andrews
diff --git a/INSTALL b/INSTALL
new file mode 100644
index 0000000..2200032
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,50 @@
+INSTALL
+
+To build the programs:
+
+$ make
+
+To install the programs and man pages:
+
+$ make install
+
+or
+
+$ make PREFIX=/usr/local install
+
+
+RPM Package
+-----------
+
+These steps should work with RPM based Linux distributions since rpmbuild was
+split from the rpm utility (c RedHat 9).
+
+
+To build an RPM the easy way follow these steps.
+
+1. Build SRPM
+
+$ cd n2n
+$ scripts/mk_SRPM.sh
+
+Look for where the src.rpm file was put ( "Wrote:" ).
+
+2. Build binary RPM from SRPM
+
+$ rpm -i path/to/n2n-.src.rpm
+$ rpmbuild -bb n2n.spec
+
+
+All this can be done as non-root user if you have a ~/.rpmmacros file with this
+line in it:
+
+%_topdir /home/username/rpmtopdir
+
+
+To build an RPM the hard way follow these steps.
+
+$ cp -a n2ndir n2n-2.0
+$ tar czf n2n-2.0.tar.gz n2n-2.0
+$ mv n2n-2.0.tar.gz /usr/src/redhat/SOURCES
+$ cp n2ndir/n2n.spec /usr/src/redhat/SPECS
+$ rpmbuild -bb n2n.spec
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..b670978
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,101 @@
+
+N2N_VERSION=2.1.0
+N2N_OSNAME=$(shell uname -p)
+
+########
+
+CC=gcc
+DEBUG?=-g3
+#OPTIMIZATION?=-O2
+WARN?=-Wall -Wshadow -Wpointer-arith -Wmissing-declarations -Wnested-externs
+
+#Ultrasparc64 users experiencing SIGBUS should try the following gcc options
+#(thanks to Robert Gibbon)
+PLATOPTS_SPARC64=-mcpu=ultrasparc -pipe -fomit-frame-pointer -ffast-math -finline-functions -fweb -frename-registers -mapp-regs
+
+N2N_DEFINES=
+N2N_OBJS_OPT=
+LIBS_EDGE_OPT=
+
+N2N_OPTION_AES?="yes"
+#N2N_OPTION_AES=no
+
+ifeq ($(N2N_OPTION_AES), "yes")
+ N2N_DEFINES+="-DN2N_HAVE_AES"
+ LIBS_EDGE_OPT+=-lcrypto
+endif
+
+CFLAGS+=$(DEBUG) $(OPTIMIZATION) $(WARN) $(OPTIONS) $(PLATOPTS) $(N2N_DEFINES)
+
+INSTALL=install
+MKDIR=mkdir -p
+
+INSTALL_PROG=$(INSTALL) -m755
+INSTALL_DOC=$(INSTALL) -m644
+
+
+# DESTDIR set in debian make system
+PREFIX?=$(DESTDIR)/usr
+#BINDIR=$(PREFIX)/bin
+SBINDIR=$(PREFIX)/sbin
+MANDIR?=$(PREFIX)/share/man
+MAN1DIR=$(MANDIR)/man1
+MAN7DIR=$(MANDIR)/man7
+MAN8DIR=$(MANDIR)/man8
+
+N2N_LIB=n2n.a
+N2N_OBJS=n2n.o n2n_keyfile.o wire.o minilzo.o twofish.o \
+ transform_null.o transform_tf.o transform_aes.o \
+ tuntap_freebsd.o tuntap_netbsd.o tuntap_linux.o tuntap_osx.o version.o
+LIBS_EDGE+=$(LIBS_EDGE_OPT)
+LIBS_SN=
+
+#For OpenSolaris (Solaris too?)
+ifeq ($(shell uname), SunOS)
+LIBS_EDGE+=-lsocket -lnsl
+LIBS_SN+=-lsocket -lnsl
+endif
+
+APPS=edge
+APPS+=supernode
+
+DOCS=edge.8.gz supernode.1.gz n2n_v2.7.gz
+
+all: $(APPS) $(DOCS)
+
+edge: edge.c $(N2N_LIB) n2n_wire.h n2n.h Makefile
+ $(CC) $(CFLAGS) edge.c $(N2N_LIB) $(LIBS_EDGE) -o edge
+
+test: test.c $(N2N_LIB) n2n_wire.h n2n.h Makefile
+ $(CC) $(CFLAGS) test.c $(N2N_LIB) $(LIBS_EDGE) -o test
+
+supernode: sn.c $(N2N_LIB) n2n.h Makefile
+ $(CC) $(CFLAGS) sn.c $(N2N_LIB) $(LIBS_SN) -o supernode
+
+benchmark: benchmark.c $(N2N_LIB) n2n_wire.h n2n.h Makefile
+ $(CC) $(CFLAGS) benchmark.c $(N2N_LIB) $(LIBS_SN) -o benchmark
+
+.c.o: n2n.h n2n_keyfile.h n2n_transforms.h n2n_wire.h twofish.h Makefile
+ $(CC) $(CFLAGS) -c $<
+
+%.gz : %
+ gzip -c $< > $@
+
+$(N2N_LIB): $(N2N_OBJS)
+ ar rcs $(N2N_LIB) $(N2N_OBJS)
+# $(RANLIB) $@
+
+version.o: Makefile
+ $(CC) $(CFLAGS) -DN2N_VERSION='"$(N2N_VERSION)"' -DN2N_OSNAME='"$(N2N_OSNAME)"' -c version.c
+
+clean:
+ rm -rf $(N2N_OBJS) $(N2N_LIB) $(APPS) $(DOCS) test *.dSYM *~
+
+install: edge supernode edge.8.gz supernode.1.gz n2n_v2.7.gz
+ echo "MANDIR=$(MANDIR)"
+ $(MKDIR) $(SBINDIR) $(MAN1DIR) $(MAN7DIR) $(MAN8DIR)
+ $(INSTALL_PROG) supernode $(SBINDIR)/
+ $(INSTALL_PROG) edge $(SBINDIR)/
+ $(INSTALL_DOC) edge.8.gz $(MAN8DIR)/
+ $(INSTALL_DOC) supernode.1.gz $(MAN1DIR)/
+ $(INSTALL_DOC) n2n_v2.7.gz $(MAN7DIR)/
diff --git a/NEW_FEATURES.txt b/NEW_FEATURES.txt
new file mode 100644
index 0000000..9efc587
--- /dev/null
+++ b/NEW_FEATURES.txt
@@ -0,0 +1,6 @@
+
+Between 2.0.x and 2.1.x
+
+* Better ming Windows build support.
+* Added -E flag to allow multicast ethernet traffic.
+
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..cdc655a
--- /dev/null
+++ b/README.md
@@ -0,0 +1,112 @@
+
+
+Edge node
+---------
+
+You need to start an edge node on each host you want to connect with the *same*
+community.
+
+0. become root
+
+1. create tun device
+# tunctl -t tun0
+
+3. enable the edge process
+# ./edge -d n2n0 -c mynetwork -k encryptme -u 99 -g 99 -m 3C:A0:12:34:56:78 -a 1.2.3.4 -l a.b.c.d:xyw
+ or
+# N2N_KEY=encryptme ./edge -d n2n0 -c mynetwork -u 99 -g 99 -m 3C:A0:12:34:56:78 -a 1.2.3.4 -l a.b.c.d:xyw
+
+Once you have this worked out, you can add the "-f" option to make edge detach
+and run as a daemon.
+
+Note that -u, -g and -f options are not available for Windows.
+
+Supernode
+--------
+
+You need to start the supernode once
+
+1. ./supernode -l 1234 -v
+
+
+Dropping Root Privileges and SUID-Root Executables (UNIX)
+--------------------------------------------------
+
+The edge node uses superuser privileges to create a TAP network interface
+device. Once this is created root privileges are not required and can constitute
+a security hazard if there is some way for an attacker to take control of an
+edge process while it is running. Edge will drop to a non-privileged user if you
+specify the -u and -g options. These are numeric IDs. Consult
+/etc/passwd.
+
+You may choose to install edge SUID-root to do this:
+
+1. Become root
+2. chown root:root edge
+3. chmod +s edge
+done
+
+Any user can now run edge. You may not want this, but it may be convenient and
+safe if your host has only one login user.
+
+
+Running As a Daemon (UNIX)
+-------------------
+
+Unless given "-f" as a command line option, edge will call daemon(3) after
+successful setup. This causes the process to fork a child which closes stdin,
+stdout and stderr then sets itself as process group leader. When this is done,
+the edge command returns immediately and you will only see the edge process in
+the process listings, eg. from ps or top.
+
+If the edge command returns 0 then the daemon started successfully. If it
+returns non-zero then edge failed to start up for some reason. When edge starts
+running as a daemon, all logging goes to syslog daemon.info facility.
+
+
+IPv6 Support
+------------
+
+n2n supports the carriage of IPv6 packets within the n2n tunnel. N2n does not
+yet use IPv6 for transport between edges and supernodes.
+
+To make IPv6 carriage work you need to manually add IPv6 addresses to the TAP
+interfaces at each end. There is currently no way to specify an IPv6 address on
+the edge command line.
+
+eg. under linux:
+
+on hostA:
+[hostA] # /sbin/ip -6 addr add fc00:abcd:1234::7/48 dev n2n0
+
+on hostB:
+[hostB] # /sbin/ip -6 addr add fc00:abcd:1234::6/48 dev n2n0
+
+You may find it useful to make use of tunctl from the uml-utilities
+package. Tunctl allow you to bring up a TAP interface and configure addressing
+prior to starting edge. It also allows edge to be restarted without the
+interface closing (which would normally affect routing tables).
+
+Once the IPv6 addresses are configured and edge started, IPv6 neighbor discovery
+packets flow (get broadcast) and IPv6 entities self arrange. Test your IPv6
+setup with ping6 - the IPv6 ping command.
+
+
+Performance Notes
+-----------------
+
+The time taken to perform a ping test for various ciphers is given below:
+
+Test: ping -f -l 8 -s 800 -c 10000
+
+AES (-O0) 11820
+TF (-O0) 25761
+
+TF (-O2) 20554
+
+AES (-O3) 12532
+TF (-O3) 14046
+NULL (-O3) 10659
+
+(C) 2007-2010 - Luca Deri , Richard Andrews
+(C) 2016 - ntop
\ No newline at end of file
diff --git a/benchmark.c b/benchmark.c
new file mode 100644
index 0000000..f6802ce
--- /dev/null
+++ b/benchmark.c
@@ -0,0 +1,110 @@
+#include "n2n_wire.h"
+#include "n2n_transforms.h"
+#include "n2n.h"
+
+#include
+#include
+#include
+#include
+
+uint8_t PKT_CONTENT[]={
+ 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,
+ 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,
+ 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,
+ 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,
+ 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,
+ 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,
+ 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,
+ 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,
+ 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,
+ 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,
+ 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,
+ 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,
+ 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,
+ 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,
+ 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,
+ 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 };
+
+/* Prototypes */
+static ssize_t do_encode_packet( uint8_t * pktbuf, size_t bufsize, const n2n_community_t c );
+
+int main( int argc, char * argv[] )
+{
+ uint8_t pktbuf[N2N_PKT_BUF_SIZE];
+ n2n_trans_op_t transop_null;
+
+ n2n_common_t cmn;
+ n2n_PACKET_t pkt;
+ n2n_community_t c;
+
+ struct timeval t1;
+ struct timeval t2;
+
+ size_t i;
+ size_t n;
+ size_t idx;
+ size_t rem;
+ ssize_t nw;
+ ssize_t tdiff;
+
+ transop_null_init( &transop_null );
+ memset(c,0,sizeof(N2N_COMMUNITY_SIZE));
+
+ n=10000;
+ memcpy( c, "abc123def456", 12 );
+
+ gettimeofday( &t1, NULL );
+ for(i=0; i %u nsec each) %u.%06u -> %u.%06u.\n", i, tdiff, (tdiff *1000)/i, (uint32_t)t1.tv_sec, (uint32_t)t1.tv_usec, (uint32_t)t2.tv_sec, (uint32_t)t2.tv_usec );
+
+ return 0;
+}
+
+static ssize_t do_encode_packet( uint8_t * pktbuf, size_t bufsize, const n2n_community_t c )
+{
+ n2n_mac_t destMac={0,1,2,3,4,5};
+ n2n_common_t cmn;
+ n2n_PACKET_t pkt;
+ size_t idx;
+
+
+ memset( &cmn, 0, sizeof(cmn) );
+ cmn.ttl = N2N_DEFAULT_TTL;
+ cmn.pc = n2n_packet;
+ cmn.flags=0; /* no options, not from supernode, no socket */
+ memcpy( cmn.community, c, N2N_COMMUNITY_SIZE );
+
+ memset( &pkt, 0, sizeof(pkt) );
+ memcpy( pkt.srcMac, destMac, N2N_MAC_SIZE);
+ memcpy( pkt.dstMac, destMac, N2N_MAC_SIZE);
+
+ pkt.sock.family=0; /* do not encode sock */
+
+ idx=0;
+ encode_PACKET( pktbuf, &idx, &cmn, &pkt );
+ traceEvent( TRACE_DEBUG, "encoded PACKET header of size=%u", (unsigned int)idx );
+
+ return idx;
+}
diff --git a/debian/README.Debian b/debian/README.Debian
new file mode 100644
index 0000000..700c74e
--- /dev/null
+++ b/debian/README.Debian
@@ -0,0 +1,7 @@
+n2n for Debian
+--------------
+
+This package depends on the kernel having the TUN/TAP driver configured in using
+CONFIG_TUN=yes.
+
+ -- Richard Andrews Thu, 10 Jul 2008 22:38:02 +1000
diff --git a/debian/changelog b/debian/changelog
new file mode 100644
index 0000000..bd31a4f
--- /dev/null
+++ b/debian/changelog
@@ -0,0 +1,27 @@
+n2n (2.1.0-1) unstable; urgency=low
+
+ * Split package in two.
+ * Move manpage for edge to section 8.
+ * Install manpage for n2n_v2 to section 7.
+ * Create init.d files for the daemons.
+
+ -- Kim Hansen Sun, 04 Apr 2010 21:40:46 +0200
+
+n2n (2.0-1) hardy; urgency=low
+
+ * New upstream release
+
+ -- Richard Andrews Tue, 30 Oct 2009 22:26:04 +1100
+
+n2n (1.3-1) hardy; urgency=low
+
+ * New upstream release
+
+ -- Richard Andrews Fri, 30 Jan 2009 23:49:56 +1100
+
+n2n (1.2-1) unstable; urgency=low
+
+ * Initial release
+
+ -- Richard Andrews Thu, 10 Jul 2008 22:38:02 +1000
+
diff --git a/debian/compat b/debian/compat
new file mode 100644
index 0000000..7ed6ff8
--- /dev/null
+++ b/debian/compat
@@ -0,0 +1 @@
+5
diff --git a/debian/control b/debian/control
new file mode 100644
index 0000000..1bdb6fa
--- /dev/null
+++ b/debian/control
@@ -0,0 +1,51 @@
+Source: n2n
+Section: net
+Priority: extra
+Maintainer: Jean-Baptiste Denis
+Build-Depends: cdbs, debhelper (>= 5), libc6-dev (>= 2.0), dpatch, gcc, libssl-dev
+Standards-Version: 3.7.2
+
+Package: n2n
+Architecture: any
+Depends: n2n-edge, n2n-supernode
+Description: dummy package for transition purposes
+ A dummy package for transition purposes that depends on n2n-edge and
+ n2n-supernode
+
+Package: n2n-edge
+Architecture: any
+Suggests: uml-utilities
+Depends: ${shlibs:Depends}, ${misc:Depends}
+Conflicts: n2n (<< 2.1.0-1)
+Replaces: n2n (<< 2.1.0-1)
+Description: a layer-two peer-to-peer virtual private network (VPN)
+ n2n is a layer-two peer-to-peer virtual private network (VPN) which allows
+ users to exploit features typical of P2P applications at network instead of
+ application level. This means that users can gain native IP visibility (e.g.
+ two PCs belonging to the same n2n network can ping each other) and be
+ reachable with the same network IP address regardless of the network where
+ they currently belong. In a nutshell, as OpenVPN moved SSL from application
+ (e.g. used to implement the https protocol) to network protocol, n2n moves
+ P2P from application to network level.
+ .
+ Edge is the edge node daemon for n2n which creates a TAP interface to expose
+ the n2n virtual LAN.
+
+Package: n2n-supernode
+Architecture: any
+Suggests: n2n-edge
+Depends: ${shlibs:Depends}, ${misc:Depends}
+Conflicts: n2n (<< 2.1.0-1)
+Replaces: n2n (<< 2.1.0-1)
+Description: a layer-two peer-to-peer virtual private network (VPN)
+ n2n is a layer-two peer-to-peer virtual private network (VPN) which allows
+ users to exploit features typical of P2P applications at network instead of
+ application level. This means that users can gain native IP visibility (e.g.
+ two PCs belonging to the same n2n network can ping each other) and be
+ reachable with the same network IP address regardless of the network where
+ they currently belong. In a nutshell, as OpenVPN moved SSL from application
+ (e.g. used to implement the https protocol) to network protocol, n2n moves
+ P2P from application to network level.
+ .
+ Supernode is a node introduction registry, broadcast conduit and packet relay
+ node for the n2n system.
diff --git a/debian/copyright b/debian/copyright
new file mode 100644
index 0000000..38346ce
--- /dev/null
+++ b/debian/copyright
@@ -0,0 +1,23 @@
+This package was debianized by Jean-Baptiste Denis on
+Thu, 20 Nov 2008 23:53:02 +1000.
+
+It was downloaded from http://www.ntop.org/n2n/
+
+Upstream Author(s):
+
+ Luca Deri
+ Richard Andrews
+
+Copyright:
+
+ Copyright (C) 2008 Luca Deri
+ Copyright (C) 2008 Richard Andrews
+
+License:
+
+ GPLv3
+
+The Debian packaging is (C) 2008, Richard Andrews ,
+Luca Deri and is licensed under the GPLv3, see
+`/usr/share/common-licenses/GPL-3'.
+
diff --git a/debian/n2n-edge.default b/debian/n2n-edge.default
new file mode 100644
index 0000000..e37d806
--- /dev/null
+++ b/debian/n2n-edge.default
@@ -0,0 +1,21 @@
+# Config file for the n2n edge node daemon.
+
+# Sets the n2n community name. All edges within the same community appear on
+# the same LAN (layer 2 network segment). Community name is 16 bytes in length.
+N2N_COMMUNITY="MyCommunityName"
+
+# Sets the twofish encryption key from ASCII text. All edges communicating must
+# use the same key and community name.
+N2N_KEY="MySecretCode"
+
+# Sets the n2n supernode IP address to register to.
+N2N_SUPERNODE="gw1.example.com"
+
+# Sets the n2n virtual LAN IP address being claimed. This is a private IP
+# address. All IP addresses in an n2n community typical belong to the same /24
+# net‐ work (ie. only the last octet of the IP addresses varies).
+N2N_IP="10.10.10.11"
+
+# Uncomment this to get edge node started.
+#N2N_EDGE_CONFIG_DONE="yes"
+
diff --git a/debian/n2n-edge.docs b/debian/n2n-edge.docs
new file mode 100644
index 0000000..e845566
--- /dev/null
+++ b/debian/n2n-edge.docs
@@ -0,0 +1 @@
+README
diff --git a/debian/n2n-edge.init b/debian/n2n-edge.init
new file mode 100755
index 0000000..5fd9f72
--- /dev/null
+++ b/debian/n2n-edge.init
@@ -0,0 +1,129 @@
+#! /bin/bash
+### BEGIN INIT INFO
+# Provides: n2n-edge
+# Required-Start: $remote_fs $syslog
+# Required-Stop: $remote_fs $syslog
+# Default-Start: 2 3 4 5
+# Default-Stop: 0 1 6
+# Short-Description: n2n-edge
+# Description: Start n2n edge node daemon
+### END INIT INFO
+
+# Init script for n2n edge node
+# Copyright (C) 2010 Kim Hansen
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+
+# Do NOT "set -e"
+
+# PATH should only include /usr/* if it runs after the mountnfs.sh script
+PATH=/sbin:/usr/sbin:/bin:/usr/bin
+DESC="n2n edge"
+NAME=n2n-edge
+DAEMON=/usr/sbin/edge
+SCRIPTNAME=/etc/init.d/$NAME
+
+# Exit if the package is not installed
+[ -x "$DAEMON" ] || exit 0
+
+# Read configuration variable file if it is present
+[ -r /etc/default/$NAME ] && . /etc/default/$NAME
+
+# Check config
+if [ -z "$N2N_EDGE_CONFIG_DONE" ]
+then
+ echo "Warning: n2n-edge not configured, edit config file in /etc/default/$NAME." 1>&2
+ exit 0
+fi
+
+# Load the VERBOSE setting and other rcS variables
+. /lib/init/vars.sh
+
+# Define LSB log_* functions.
+# Depend on lsb-base (>= 3.0-6) to ensure that this file is present.
+. /lib/lsb/init-functions
+
+#
+# Function that starts the daemon/service
+#
+do_start()
+{
+ # Return
+ # 0 if daemon has been started
+ # 1 if daemon was already running
+ # 2 if daemon could not be started
+ start-stop-daemon --start --quiet --user nobody --exec $DAEMON --test \
+ || return 1
+ export N2N_KEY
+ start-stop-daemon --start --quiet --user nobody --exec $DAEMON -- \
+ -a $N2N_IP -c $N2N_COMMUNITY -l $N2N_SUPERNODE:7654 -u $(id -u nobody) -g $(id -g nobody) \
+ $DAEMON_ARGS \
+ || return 2
+}
+
+#
+# Function that stops the daemon/service
+#
+do_stop()
+{
+ # Return
+ # 0 if daemon has been stopped
+ # 1 if daemon was already stopped
+ # 2 if daemon could not be stopped
+ # other if a failure occurred
+ start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --user nobody --exec $DAEMON
+}
+
+case "$1" in
+ start)
+ [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME"
+ do_start
+ case "$?" in
+ 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
+ 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
+ esac
+ ;;
+ stop)
+ [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME"
+ do_stop
+ case "$?" in
+ 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
+ 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
+ esac
+ ;;
+ restart|force-reload)
+ log_daemon_msg "Restarting $DESC" "$NAME"
+ do_stop
+ case "$?" in
+ 0|1)
+ do_start
+ case "$?" in
+ 0) log_end_msg 0 ;;
+ 1) log_end_msg 1 ;; # Old process is still running
+ *) log_end_msg 1 ;; # Failed to start
+ esac
+ ;;
+ *)
+ # Failed to stop
+ log_end_msg 1
+ ;;
+ esac
+ ;;
+ *)
+ echo "Usage: $SCRIPTNAME {start|stop|restart|force-reload}" >&2
+ exit 3
+ ;;
+esac
+
+true # Set exit status to 0 (succes)
diff --git a/debian/n2n-edge.install b/debian/n2n-edge.install
new file mode 100644
index 0000000..2d0bd7c
--- /dev/null
+++ b/debian/n2n-edge.install
@@ -0,0 +1 @@
+edge /usr/sbin
diff --git a/debian/n2n-edge.manpages b/debian/n2n-edge.manpages
new file mode 100644
index 0000000..2fa385b
--- /dev/null
+++ b/debian/n2n-edge.manpages
@@ -0,0 +1,2 @@
+edge.8
+n2n_v2.7
diff --git a/debian/n2n-supernode.init b/debian/n2n-supernode.init
new file mode 100755
index 0000000..7efc7d8
--- /dev/null
+++ b/debian/n2n-supernode.init
@@ -0,0 +1,121 @@
+#! /bin/sh
+### BEGIN INIT INFO
+# Provides: n2n-supernode
+# Required-Start: $remote_fs $syslog
+# Required-Stop: $remote_fs $syslog
+# Default-Start: 2 3 4 5
+# Default-Stop: 0 1 6
+# Short-Description: n2n-supernode
+# Description: Start n2n supernode
+### END INIT INFO
+
+# Init script for n2n supernode
+# Copyright (C) 2010 Kim Hansen
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+
+# Do NOT "set -e"
+
+# PATH should only include /usr/* if it runs after the mountnfs.sh script
+PATH=/sbin:/usr/sbin:/bin:/usr/bin
+DESC="n2n supernode"
+NAME=n2n-supernode
+DAEMON=/usr/sbin/supernode
+DAEMON_ARGS=""
+SCRIPTNAME=/etc/init.d/$NAME
+
+# Exit if the package is not installed
+[ -x "$DAEMON" ] || exit 0
+
+# Read configuration variable file if it is present
+[ -r /etc/default/$NAME ] && . /etc/default/$NAME
+
+# Load the VERBOSE setting and other rcS variables
+. /lib/init/vars.sh
+
+# Define LSB log_* functions.
+# Depend on lsb-base (>= 3.0-6) to ensure that this file is present.
+. /lib/lsb/init-functions
+
+#
+# Function that starts the daemon/service
+#
+do_start()
+{
+ # Return
+ # 0 if daemon has been started
+ # 1 if daemon was already running
+ # 2 if daemon could not be started
+ start-stop-daemon --start --quiet --user nobody --exec $DAEMON --test \
+ || return 1
+ start-stop-daemon --start --quiet --user nobody --chuid nobody --exec $DAEMON -- \
+ $DAEMON_ARGS \
+ || return 2
+}
+
+#
+# Function that stops the daemon/service
+#
+do_stop()
+{
+ # Return
+ # 0 if daemon has been stopped
+ # 1 if daemon was already stopped
+ # 2 if daemon could not be stopped
+ # other if a failure occurred
+ start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --user nobody --exec $DAEMON
+}
+
+case "$1" in
+ start)
+ [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME"
+ do_start
+ case "$?" in
+ 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
+ 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
+ esac
+ ;;
+ stop)
+ [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME"
+ do_stop
+ case "$?" in
+ 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
+ 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
+ esac
+ ;;
+ restart|force-reload)
+ log_daemon_msg "Restarting $DESC" "$NAME"
+ do_stop
+ case "$?" in
+ 0|1)
+ do_start
+ case "$?" in
+ 0) log_end_msg 0 ;;
+ 1) log_end_msg 1 ;; # Old process is still running
+ *) log_end_msg 1 ;; # Failed to start
+ esac
+ ;;
+ *)
+ # Failed to stop
+ log_end_msg 1
+ ;;
+ esac
+ ;;
+ *)
+ echo "Usage: $SCRIPTNAME {start|stop|restart|force-reload}" >&2
+ exit 3
+ ;;
+esac
+
+true # Set exit status to 0 (succes)
diff --git a/debian/n2n-supernode.install b/debian/n2n-supernode.install
new file mode 100644
index 0000000..28fa224
--- /dev/null
+++ b/debian/n2n-supernode.install
@@ -0,0 +1 @@
+supernode /usr/sbin
diff --git a/debian/n2n-supernode.manpages b/debian/n2n-supernode.manpages
new file mode 100644
index 0000000..6ebfb37
--- /dev/null
+++ b/debian/n2n-supernode.manpages
@@ -0,0 +1 @@
+supernode.1
diff --git a/debian/rules b/debian/rules
new file mode 100755
index 0000000..0bbc9b8
--- /dev/null
+++ b/debian/rules
@@ -0,0 +1,5 @@
+#!/usr/bin/make -f
+
+include /usr/share/cdbs/1/rules/debhelper.mk
+include /usr/share/cdbs/1/class/makefile.mk
+
diff --git a/edge.8 b/edge.8
new file mode 100644
index 0000000..5157653
--- /dev/null
+++ b/edge.8
@@ -0,0 +1,208 @@
+.TH edge 8 "17 Mar 2010" "n2n-2.1" "SUPERUSER COMMANDS"
+.SH NAME
+edge \- n2n edge node daemon
+.SH SYNOPSIS
+.B edge
+[\-d ] \-a \-c {\-k |\-K }
+[\-s ] \-l
+[\-p ] [\-u ] [\-g ] [-f] [\-m ] [\-r] [\-v]
+.SH DESCRIPTION
+N2N is a peer-to-peer VPN system. Edge is the edge node daemon for n2n which
+creates a TAP interface to expose the n2n virtual LAN. On startup n2n creates
+the TAP interface and configures it then registers with the supernode so it can
+begin to find other nodes in the community.
+.PP
+.SH OPTIONS
+.TP
+\-d
+sets the TAP device name as seen in ifconfig. Only available on Linux.
+.TP
+\-a {|static:|dhcp:0.0.0.0}
+sets the n2n virtual LAN IP address being claimed. This is a private IP
+address. All IP addresses in an n2n community typical belong to the same /24
+network (ie. only the last octet of the IP addresses varies). If DHCP is used to
+assign interface addresses then specify the address as
+.B -a dhcp:0.0.0.0
+.TP
+\-b
+cause edge to perform hostname resolution for the supernode address each time
+the supernode is periodically contacted. This can cause reliability problems
+because all packet processing stops while the supernode address is resolved
+which might take 15 seconds.
+.TP
+\-c
+sets the n2n community name. All edges within the same community appear on the
+same LAN (layer 2 network segment). Community name is 16 bytes in length. A name
+smaller than this is padded with 0x00 bytes and a name longer than this is
+truncated to take the first 16 bytes.
+.TP
+\-h
+write usage then exit.
+.TP
+\-k
+sets the twofish encryption key from ASCII text (see also N2N_KEY in
+ENVIRONMENT). All edges communicating must use the same key and community
+name. If neither -k nor -K is used to specify a key source then edge uses
+cleartext mode (no encryption). The -k and -K options are mutually exclusive.
+.TP
+\-K
+Reads a key-schedule file and populates the internal transform
+operations with the data found there. This mechanism allows keys to roll at
+pre-determined times for a group of hosts. Accurate time synchronisation is not
+required as older keys can be decoded for some time after expiry. If neither -k
+nor -K is used to specify a key source then edge uses cleartext mode (no
+encryption). The -k and -K options are mutually exclusive.
+.TP
+\-l :
+sets the n2n supernode IP address and port to register to. Up to 2 supernodes
+can be specified by two invocations of -l :. eg.
+.B edge -l 12.34.56.78:7654 -l 98.76.54.32:7654
+.
+.TP
+\-p
+binds edge to the given UDP port. Useful for keeping the same external socket
+across restarts of edge. This allows peer edges which know the edge socket to
+continue p2p operation without going back to the supernode.
+.TP
+\-t
+binds the edge management system to the given UDP port. Default 5644. Use this
+if you need to run multiple instance of edge; or something is bound to that
+port.
+.TP
+\-u
+causes the edge process to drop to the given user ID when privileges are no
+longer required (UNIX).
+.TP
+\-g
+causes the edge process to drop to the given group ID when privileges are no
+longer required (UNIX).
+.TP
+\-f
+disables daemon mode (UNIX) and causes edge to run in the foreground.
+.TP
+\-m
+start the TAP interface with the given MAC address. This is highly recommended
+as it means the same address will be used if edge stops and restarts. If this is
+not done, the ARP caches of all peers will be wrong and packets will not flow to
+this edge until the next ARP refresh.
+.TP
+\-M
+set the MTU of the edge interface in bytes. MTU is the largest packet fragment
+size allowed to be moved throught the interface. The default is 1400.
+.TP
+\-s
+set the netmask of edge interface in IPv4 dotted decimal notation. The default
+is 255.255.255.0 (ie. /24).
+.TP
+\-r
+enable IP packet forwarding/routing through the n2n virtual LAN. Without this
+option, IP packets arriving over n2n are dropped if not for the -a (or
+DHCP assigned) IP address of the edge interface.
+.TP
+\-E
+accept packets destined for multicast ethernet MAC addresses. These addresses
+are used in multicast ethernet and IPv6 neighbour discovery. If this option is
+not present these multicast packets are discarded as most users do not need or
+understand them.
+.TP
+\-v
+more verbose logging (may be specified several times for more verbosity).
+.SH ENVIRONMENT
+.TP
+.B N2N_KEY
+set the encryption key so it is not visible on the command line
+.SH EXAMPLES
+.TP
+.B edge \-d n2n0 \-c mynetwork \-k encryptme \-u 99 \-g 99 \-m DE:AD:BE:EF:01:23 \-a 192.168.254.7 \-p 50001 \-l 123.121.120.119:7654
+
+Start edge with TAP device n2n0 on community "mynetwork" with community
+supernode at 123.121.120.119 UDP port 7654 and bind the locally used UDP port to
+50001. Use "encryptme" as the single permanent shared encryption key. Assign MAC
+address DE:AD:BE:EF:01:23 to the n2n interface and drop to user=99 and group=99
+after the TAP device is successfull configured.
+.PP
+Add the -f option to stop edge running as a daemon.
+.PP
+Somewhere else setup another edge with similar parameters, eg.
+
+.B edge \-d n2n0 \-c mynetwork \-k encryptme \-u 99 \-g 99 \-m DE:AD:BE:EF:01:21 \-a 192.168.254.5 \-p 50001 \-l 123.121.120.119:7654
+.PP
+Now you can ping from 192.168.254.5 to 192.168.254.7.
+.PP
+The MAC address (-m ) and virtual IP address (-a ) must be different
+on all edges in the same community.
+
+.SH KEY SCHEDULE FILES
+(See
+.B n2n_v2(7)
+for more details).
+
+The -K option reads a key schedule file.
+
+.B edge \-d n2n0 \-c mynetwork \-K /path/to/file \-u 99 \-g 99 \-m DE:AD:BE:EF:01:21 \-a 192.168.254.5 \-p 50001 \-l 123.121.120.119:7654
+.PP
+
+The key schedule file consists of line, one per key in the schedule. The purpose
+of key schedules is to encourage regular changing of the encryption keys used by
+a community. The file structure also allows for full binary keys to be specified
+as compared to the ASCII keys allowed by the single key injection. Each key line
+consists of the following:
+
+.B
+
+ and are ASCII decimal values of the UNIX times during which the
+key is valid. is the index of the transform that applies
+to. is some text which is parsed by the transform module to derive the
+key for that line.
+
+Supported values are:
+.TP
+2 = TwoFish
+ has the form _. eg.
+
+.B 1252327945 1252328305 2 602_3d7c7769b34b2a4812f8c0e9d87ce9
+
+This specifies security association number 602 and a 16-octet key of numeric
+value 0x3d7c7769b34b2a4812f8c0e9d87ce9. is a 32-bit unsigned integer which
+is used to identify the encryption key to the receiver. The SA number is sent
+unencrypted so the receiver may find the correct key from the key
+schedule. is up to 16 octets although shorter keys are allowed.
+
+.TP
+3 = AES-CBC
+ has the form _. Same rules as TwoFish.
+
+.SH CLEARTEXT MODE
+If neither
+.B -k
+nor
+.B -K
+is specified then edge uses cleartext mode. In cleartext mode there is no
+transform of the packet data it is simply encrypted. This is useful for
+debugging n2n as packet contents can be seen clearly.
+
+To prevent accidental exposure of data, edge only enters cleartext mode when no
+keying parameters are specified. In the case where keying parameters are
+specified but no valid keys can be determined, edge exits with an error at
+startup. If all keys become invalid while running, edge continues to encode
+using the last key that was valid.
+
+.SH MANAGEMENT INTERFACE
+Edge provides a very simple management system on UDP port 5644. Send a newline
+to receive a status output. Send 'reload' to cause re-read of the
+keyfile. Send 'stop' to cause edge to exit cleanly.
+
+.SH EXIT STATUS
+edge is a daemon and any exit is an error.
+.SH AUTHORS
+.TP
+Richard Andrews
+andrews (at) ntop.org - n2n-1 maintainer and main author of n2n-2
+.TP
+Luca Deri
+deri (at) ntop.org - original author of n2n
+.TP
+Don Bindner
+(--) - significant contributions to n2n-1
+.SH SEE ALSO
+ifconfig(8) supernode(1) tunctl(8) n2n_v2(7)
diff --git a/edge.c b/edge.c
new file mode 100644
index 0000000..b2407b9
--- /dev/null
+++ b/edge.c
@@ -0,0 +1,2412 @@
+/**
+ * (C) 2007-09 - Luca Deri
+ * Richard Andrews
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not see see
+ *
+ * Code contributions courtesy of:
+ * Don Bindner
+ * Sylwester Sosnowski
+ * Wilfried "Wonka" Klaebe
+ * Lukasz Taczuk
+ *
+ */
+
+#include "n2n.h"
+#include "n2n_transforms.h"
+#include
+#include
+#include "minilzo.h"
+
+#if defined(DEBUG)
+#define SOCKET_TIMEOUT_INTERVAL_SECS 5
+#define REGISTER_SUPER_INTERVAL_DFL 20 /* sec */
+#else /* #if defined(DEBUG) */
+#define SOCKET_TIMEOUT_INTERVAL_SECS 10
+#define REGISTER_SUPER_INTERVAL_DFL 60 /* sec */
+#endif /* #if defined(DEBUG) */
+
+#define REGISTER_SUPER_INTERVAL_MIN 20 /* sec */
+#define REGISTER_SUPER_INTERVAL_MAX 3600 /* sec */
+
+#define IFACE_UPDATE_INTERVAL (30) /* sec. How long it usually takes to get an IP lease. */
+#define TRANSOP_TICK_INTERVAL (10) /* sec */
+
+/** maximum length of command line arguments */
+#define MAX_CMDLINE_BUFFER_LENGTH 4096
+
+/** maximum length of a line in the configuration file */
+#define MAX_CONFFILE_LINE_LENGTH 1024
+
+#define N2N_PATHNAME_MAXLEN 256
+#define N2N_MAX_TRANSFORMS 16
+#define N2N_EDGE_MGMT_PORT 5644
+
+/** Positions in the transop array where various transforms are stored.
+ *
+ * Used by transop_enum_to_index(). See also the transform enumerations in
+ * n2n_transforms.h */
+#define N2N_TRANSOP_NULL_IDX 0
+#define N2N_TRANSOP_TF_IDX 1
+#define N2N_TRANSOP_AESCBC_IDX 2
+/* etc. */
+
+
+
+/* Work-memory needed for compression. Allocate memory in units
+ * of `lzo_align_t' (instead of `char') to make sure it is properly aligned.
+ */
+
+/* #define HEAP_ALLOC(var,size) \ */
+/* lzo_align_t __LZO_MMODEL var [ ((size) + (sizeof(lzo_align_t) - 1)) / sizeof(lzo_align_t) ] */
+
+/* static HEAP_ALLOC(wrkmem,LZO1X_1_MEM_COMPRESS); */
+
+/* ******************************************************* */
+
+#define N2N_EDGE_SN_HOST_SIZE 48
+
+typedef char n2n_sn_name_t[N2N_EDGE_SN_HOST_SIZE];
+
+#define N2N_EDGE_NUM_SUPERNODES 2
+#define N2N_EDGE_SUP_ATTEMPTS 3 /* Number of failed attmpts before moving on to next supernode. */
+
+
+/** Main structure type for edge. */
+struct n2n_edge
+{
+ int daemon; /**< Non-zero if edge should detach and run in the background. */
+ uint8_t re_resolve_supernode_ip;
+
+ n2n_sock_t supernode;
+
+ size_t sn_idx; /**< Currently active supernode. */
+ size_t sn_num; /**< Number of supernode addresses defined. */
+ n2n_sn_name_t sn_ip_array[N2N_EDGE_NUM_SUPERNODES];
+ int sn_wait; /**< Whether we are waiting for a supernode response. */
+
+ n2n_community_t community_name; /**< The community. 16 full octets. */
+ char keyschedule[N2N_PATHNAME_MAXLEN];
+ int null_transop; /**< Only allowed if no key sources defined. */
+
+ int udp_sock;
+ int udp_mgmt_sock; /**< socket for status info. */
+
+ tuntap_dev device; /**< All about the TUNTAP device */
+ int dyn_ip_mode; /**< Interface IP address is dynamically allocated, eg. DHCP. */
+ int allow_routing; /**< Accept packet no to interface address. */
+ int drop_multicast; /**< Multicast ethernet addresses. */
+
+ n2n_trans_op_t transop[N2N_MAX_TRANSFORMS]; /* one for each transform at fixed positions */
+ size_t tx_transop_idx; /**< The transop to use when encoding. */
+
+ struct peer_info * known_peers; /**< Edges we are connected to. */
+ struct peer_info * pending_peers; /**< Edges we have tried to register with. */
+ time_t last_register_req; /**< Check if time to re-register with super*/
+ size_t register_lifetime; /**< Time distance after last_register_req at which to re-register. */
+ time_t last_p2p; /**< Last time p2p traffic was received. */
+ time_t last_sup; /**< Last time a packet arrived from supernode. */
+ size_t sup_attempts; /**< Number of remaining attempts to this supernode. */
+ n2n_cookie_t last_cookie; /**< Cookie sent in last REGISTER_SUPER. */
+
+ time_t start_time; /**< For calculating uptime */
+
+ /* Statistics */
+ size_t tx_p2p;
+ size_t rx_p2p;
+ size_t tx_sup;
+ size_t rx_sup;
+};
+
+/** Return the IP address of the current supernode in the ring. */
+static const char * supernode_ip( const n2n_edge_t * eee )
+{
+ return (eee->sn_ip_array)[eee->sn_idx];
+}
+
+
+static void supernode2addr(n2n_sock_t * sn, const n2n_sn_name_t addr);
+
+static void send_packet2net(n2n_edge_t * eee,
+ uint8_t *decrypted_msg, size_t len);
+
+
+/* ************************************** */
+
+/* parse the configuration file */
+static int readConfFile(const char * filename, char * const linebuffer) {
+ struct stat stats;
+ FILE * fd;
+ char * buffer = NULL;
+
+ buffer = (char *)malloc(MAX_CONFFILE_LINE_LENGTH);
+ if (!buffer) {
+ traceEvent( TRACE_ERROR, "Unable to allocate memory");
+ return -1;
+ }
+
+ if (stat(filename, &stats)) {
+ if (errno == ENOENT)
+ traceEvent(TRACE_ERROR, "parameter file %s not found/unable to access\n", filename);
+ else
+ traceEvent(TRACE_ERROR, "cannot stat file %s, errno=%d\n",filename, errno);
+ free(buffer);
+ return -1;
+ }
+
+ fd = fopen(filename, "rb");
+ if (!fd) {
+ traceEvent(TRACE_ERROR, "Unable to open parameter file '%s' (%d)...\n",filename,errno);
+ free(buffer);
+ return -1;
+ }
+ while(fgets(buffer, MAX_CONFFILE_LINE_LENGTH,fd)) {
+ char * p = NULL;
+
+ /* strip out comments */
+ p = strchr(buffer, '#');
+ if (p) *p ='\0';
+
+ /* remove \n */
+ p = strchr(buffer, '\n');
+ if (p) *p ='\0';
+
+ /* strip out heading spaces */
+ p = buffer;
+ while(*p == ' ' && *p != '\0') ++p;
+ if (p != buffer) strncpy(buffer,p,strlen(p)+1);
+
+ /* strip out trailing spaces */
+ while(strlen(buffer) && buffer[strlen(buffer)-1]==' ')
+ buffer[strlen(buffer)-1]= '\0';
+
+ /* check for nested @file option */
+ if (strchr(buffer, '@')) {
+ traceEvent(TRACE_ERROR, "@file in file nesting is not supported\n");
+ free(buffer);
+ return -1;
+ }
+ if ((strlen(linebuffer)+strlen(buffer)+2)< MAX_CMDLINE_BUFFER_LENGTH) {
+ strncat(linebuffer, " ", 1);
+ strncat(linebuffer, buffer, strlen(buffer));
+ } else {
+ traceEvent(TRACE_ERROR, "too many argument");
+ free(buffer);
+ return -1;
+ }
+ }
+
+ free(buffer);
+ fclose(fd);
+
+ return 0;
+}
+
+/* Create the argv vector */
+static char ** buildargv(int * effectiveargc, char * const linebuffer) {
+ const int INITIAL_MAXARGC = 16; /* Number of args + NULL in initial argv */
+ int maxargc;
+ int argc=0;
+ char ** argv;
+ char * buffer, * buff;
+
+ *effectiveargc = 0;
+ buffer = (char *)calloc(1, strlen(linebuffer)+2);
+ if (!buffer) {
+ traceEvent( TRACE_ERROR, "Unable to allocate memory");
+ return NULL;
+ }
+ strncpy(buffer, linebuffer,strlen(linebuffer));
+
+ maxargc = INITIAL_MAXARGC;
+ argv = (char **)malloc(maxargc * sizeof(char*));
+ if (argv == NULL) {
+ traceEvent( TRACE_ERROR, "Unable to allocate memory");
+ return NULL;
+ }
+ buff = buffer;
+ while(buff) {
+ char * p = strchr(buff,' ');
+ if (p) {
+ *p='\0';
+ argv[argc++] = strdup(buff);
+ while(*++p == ' ' && *p != '\0');
+ buff=p;
+ if (argc >= maxargc) {
+ maxargc *= 2;
+ argv = (char **)realloc(argv, maxargc * sizeof(char*));
+ if (argv == NULL) {
+ traceEvent(TRACE_ERROR, "Unable to re-allocate memory");
+ free(buffer);
+ return NULL;
+ }
+ }
+ } else {
+ argv[argc++] = strdup(buff);
+ break;
+ }
+ }
+ free(buffer);
+ *effectiveargc = argc;
+ return argv;
+}
+
+
+
+/* ************************************** */
+
+
+/** Initialise an edge to defaults.
+ *
+ * This also initialises the NULL transform operation opstruct.
+ */
+static int edge_init(n2n_edge_t * eee)
+{
+#ifdef WIN32
+ initWin32();
+#endif
+ memset(eee, 0, sizeof(n2n_edge_t));
+ eee->start_time = time(NULL);
+
+ transop_null_init( &(eee->transop[N2N_TRANSOP_NULL_IDX]) );
+ transop_twofish_init( &(eee->transop[N2N_TRANSOP_TF_IDX] ) );
+ transop_aes_init( &(eee->transop[N2N_TRANSOP_AESCBC_IDX] ) );
+
+ eee->tx_transop_idx = N2N_TRANSOP_NULL_IDX; /* No guarantee the others have been setup */
+
+ eee->daemon = 1; /* By default run in daemon mode. */
+ eee->re_resolve_supernode_ip = 0;
+ /* keyschedule set to NULLs by memset */
+ /* community_name set to NULLs by memset */
+ eee->null_transop = 0;
+ eee->udp_sock = -1;
+ eee->udp_mgmt_sock = -1;
+ eee->dyn_ip_mode = 0;
+ eee->allow_routing = 0;
+ eee->drop_multicast = 1;
+ eee->known_peers = NULL;
+ eee->pending_peers = NULL;
+ eee->last_register_req = 0;
+ eee->register_lifetime = REGISTER_SUPER_INTERVAL_DFL;
+ eee->last_p2p = 0;
+ eee->last_sup = 0;
+ eee->sup_attempts = N2N_EDGE_SUP_ATTEMPTS;
+
+ if(lzo_init() != LZO_E_OK)
+ {
+ traceEvent(TRACE_ERROR, "LZO compression error");
+ return(-1);
+ }
+
+ return(0);
+}
+
+
+
+/* Called in main() after options are parsed. */
+static int edge_init_twofish( n2n_edge_t * eee, uint8_t *encrypt_pwd, uint32_t encrypt_pwd_len )
+{
+ return transop_twofish_setup( &(eee->transop[N2N_TRANSOP_TF_IDX]), 0, encrypt_pwd, encrypt_pwd_len );
+}
+
+
+/** Find the transop op-struct for the transform enumeration required.
+ *
+ * @return - index into the transop array, or -1 on failure.
+ */
+static int transop_enum_to_index( n2n_transform_t id )
+{
+ switch (id)
+ {
+ case N2N_TRANSFORM_ID_TWOFISH:
+ return N2N_TRANSOP_TF_IDX;
+ break;
+ case N2N_TRANSFORM_ID_NULL:
+ return N2N_TRANSOP_NULL_IDX;
+ break;
+ case N2N_TRANSFORM_ID_AESCBC:
+ return N2N_TRANSOP_AESCBC_IDX;
+ break;
+ default:
+ return -1;
+ }
+}
+
+
+/** Called periodically to roll keys and do any periodic maintenance in the
+ * tranform operations state machines. */
+static int n2n_tick_transop( n2n_edge_t * eee, time_t now )
+{
+ n2n_tostat_t tst;
+ size_t trop = eee->tx_transop_idx;
+
+ /* Tests are done in order that most preferred transform is last and causes
+ * tx_transop_idx to be left at most preferred valid transform. */
+ tst = (eee->transop[N2N_TRANSOP_NULL_IDX].tick)( &(eee->transop[N2N_TRANSOP_NULL_IDX]), now );
+ tst = (eee->transop[N2N_TRANSOP_AESCBC_IDX].tick)( &(eee->transop[N2N_TRANSOP_AESCBC_IDX]), now );
+ if ( tst.can_tx )
+ {
+ traceEvent( TRACE_DEBUG, "can_tx AESCBC (idx=%u)", (unsigned int)N2N_TRANSOP_AESCBC_IDX );
+ trop = N2N_TRANSOP_AESCBC_IDX;
+ }
+
+ tst = (eee->transop[N2N_TRANSOP_TF_IDX].tick)( &(eee->transop[N2N_TRANSOP_TF_IDX]), now );
+ if ( tst.can_tx )
+ {
+ traceEvent( TRACE_DEBUG, "can_tx TF (idx=%u)", (unsigned int)N2N_TRANSOP_TF_IDX );
+ trop = N2N_TRANSOP_TF_IDX;
+ }
+
+ if ( trop != eee->tx_transop_idx )
+ {
+ eee->tx_transop_idx = trop;
+ traceEvent( TRACE_NORMAL, "Chose new tx_transop_idx=%u", (unsigned int)(eee->tx_transop_idx) );
+ }
+
+ return 0;
+}
+
+
+
+/** Read in a key-schedule file, parse the lines and pass each line to the
+ * appropriate trans_op for parsing of key-data and adding key-schedule
+ * entries. The lookup table of time->trans_op is constructed such that
+ * encoding can be passed to the correct trans_op. The trans_op internal table
+ * will then determine the best SA for that trans_op from the key schedule to
+ * use for encoding. */
+static int edge_init_keyschedule( n2n_edge_t * eee )
+{
+
+#define N2N_NUM_CIPHERSPECS 32
+
+ int retval = -1;
+ ssize_t numSpecs=0;
+ n2n_cipherspec_t specs[N2N_NUM_CIPHERSPECS];
+ size_t i;
+ time_t now = time(NULL);
+
+ numSpecs = n2n_read_keyfile( specs, N2N_NUM_CIPHERSPECS, eee->keyschedule );
+
+ if ( numSpecs > 0 )
+ {
+ traceEvent( TRACE_NORMAL, "keyfile = %s read -> %d specs.\n", optarg, (signed int)numSpecs);
+
+ for ( i=0; i < (size_t)numSpecs; ++i )
+ {
+ int idx;
+
+ idx = transop_enum_to_index( specs[i].t );
+
+ switch (idx)
+ {
+ case N2N_TRANSOP_TF_IDX:
+ case N2N_TRANSOP_AESCBC_IDX:
+ {
+ retval = (eee->transop[idx].addspec)( &(eee->transop[idx]),
+ &(specs[i]) );
+ break;
+ }
+ default:
+ retval = -1;
+ }
+
+ if (0 != retval)
+ {
+ traceEvent( TRACE_ERROR, "keyschedule failed to add spec[%u] to transop[%d].\n",
+ (unsigned int)i, idx);
+
+ return retval;
+ }
+ }
+
+ n2n_tick_transop( eee, now );
+ }
+ else
+ {
+ traceEvent( TRACE_ERROR, "Failed to process '%s'", eee->keyschedule );
+ }
+
+ return retval;
+}
+
+
+/** Deinitialise the edge and deallocate any owned memory. */
+static void edge_deinit(n2n_edge_t * eee)
+{
+ if ( eee->udp_sock >=0 )
+ {
+ closesocket( eee->udp_sock );
+ }
+
+ if ( eee->udp_mgmt_sock >= 0 )
+ {
+ closesocket(eee->udp_mgmt_sock);
+ }
+
+ clear_peer_list( &(eee->pending_peers) );
+ clear_peer_list( &(eee->known_peers) );
+
+ (eee->transop[N2N_TRANSOP_TF_IDX].deinit)(&eee->transop[N2N_TRANSOP_TF_IDX]);
+ (eee->transop[N2N_TRANSOP_NULL_IDX].deinit)(&eee->transop[N2N_TRANSOP_NULL_IDX]);
+}
+
+static void readFromIPSocket( n2n_edge_t * eee );
+
+static void readFromMgmtSocket( n2n_edge_t * eee, int * keep_running );
+
+static void help() {
+ print_n2n_version();
+
+ printf("edge "
+#if defined(N2N_CAN_NAME_IFACE)
+ "-d "
+#endif /* #if defined(N2N_CAN_NAME_IFACE) */
+ "-a [static:|dhcp:] "
+ "-c "
+ "[-k | -K ] "
+ "[-s ] "
+#if defined(N2N_HAVE_SETUID)
+ "[-u -g ]"
+#endif /* #ifndef N2N_HAVE_SETUID */
+
+#if defined(N2N_HAVE_DAEMON)
+ "[-f]"
+#endif /* #if defined(N2N_HAVE_DAEMON) */
+ "[-m ]"
+ "\n"
+ "-l "
+ "[-p ] [-M ] "
+ "[-r] [-E] [-v] [-t ] [-b] [-h]\n\n");
+
+#ifdef __linux__
+ printf("-d | tun device name\n");
+#endif
+
+ printf("-a | Set interface address. For DHCP use '-r -a dhcp:0.0.0.0'\n");
+ printf("-c | n2n community name the edge belongs to.\n");
+ printf("-k | Encryption key (ASCII) - also N2N_KEY=. Not with -K.\n");
+ printf("-K | Specify a key schedule file to load. Not with -k.\n");
+ printf("-s | Edge interface netmask in dotted decimal notation (255.255.255.0).\n");
+ printf("-l | Supernode IP:port\n");
+ printf("-b | Periodically resolve supernode IP\n");
+ printf(" : (when supernodes are running on dynamic IPs)\n");
+ printf("-p | Fixed local UDP port.\n");
+#ifndef WIN32
+ printf("-u | User ID (numeric) to use when privileges are dropped.\n");
+ printf("-g | Group ID (numeric) to use when privileges are dropped.\n");
+#endif /* ifndef WIN32 */
+#ifdef N2N_HAVE_DAEMON
+ printf("-f | Do not fork and run as a daemon; rather run in foreground.\n");
+#endif /* #ifdef N2N_HAVE_DAEMON */
+ printf("-m | Fix MAC address for the TAP interface (otherwise it may be random)\n"
+ " : eg. -m 01:02:03:04:05:06\n");
+ printf("-M | Specify n2n MTU of edge interface (default %d).\n", DEFAULT_MTU);
+ printf("-r | Enable packet forwarding through n2n community.\n");
+ printf("-E | Accept multicast MAC addresses (default=drop).\n");
+ printf("-v | Make more verbose. Repeat as required.\n");
+ printf("-t | Management UDP Port (for multiple edges on a machine).\n");
+
+ printf("\nEnvironment variables:\n");
+ printf(" N2N_KEY | Encryption key (ASCII). Not with -K or -k.\n" );
+
+ exit(0);
+}
+
+
+/** Send a datagram to a socket defined by a n2n_sock_t */
+static ssize_t sendto_sock( int fd, const void * buf, size_t len, const n2n_sock_t * dest )
+{
+ struct sockaddr_in peer_addr;
+ ssize_t sent;
+
+ fill_sockaddr( (struct sockaddr *) &peer_addr,
+ sizeof(peer_addr),
+ dest );
+
+ sent = sendto( fd, buf, len, 0/*flags*/,
+ (struct sockaddr *)&peer_addr, sizeof(struct sockaddr_in) );
+ if ( sent < 0 )
+ {
+ char * c = strerror(errno);
+ traceEvent( TRACE_ERROR, "sendto failed (%d) %s", errno, c );
+ }
+ else
+ {
+ traceEvent( TRACE_DEBUG, "sendto sent=%d to ", (signed int)sent );
+ }
+
+ return sent;
+}
+
+
+/** Send a REGISTER packet to another edge. */
+static void send_register( n2n_edge_t * eee,
+ const n2n_sock_t * remote_peer)
+{
+ uint8_t pktbuf[N2N_PKT_BUF_SIZE];
+ size_t idx;
+ ssize_t sent;
+ n2n_common_t cmn;
+ n2n_REGISTER_t reg;
+ n2n_sock_str_t sockbuf;
+
+ memset(&cmn, 0, sizeof(cmn) );
+ memset(®, 0, sizeof(reg) );
+ cmn.ttl=N2N_DEFAULT_TTL;
+ cmn.pc = n2n_register;
+ cmn.flags = 0;
+ memcpy( cmn.community, eee->community_name, N2N_COMMUNITY_SIZE );
+
+ idx=0;
+ encode_uint32( reg.cookie, &idx, 123456789 );
+ idx=0;
+ encode_mac( reg.srcMac, &idx, eee->device.mac_addr );
+
+ idx=0;
+ encode_REGISTER( pktbuf, &idx, &cmn, ® );
+
+ traceEvent( TRACE_INFO, "send REGISTER %s",
+ sock_to_cstr( sockbuf, remote_peer ) );
+
+
+ sent = sendto_sock( eee->udp_sock, pktbuf, idx, remote_peer );
+
+}
+
+
+/** Send a REGISTER_SUPER packet to the current supernode. */
+static void send_register_super( n2n_edge_t * eee,
+ const n2n_sock_t * supernode)
+{
+ uint8_t pktbuf[N2N_PKT_BUF_SIZE];
+ size_t idx;
+ ssize_t sent;
+ n2n_common_t cmn;
+ n2n_REGISTER_SUPER_t reg;
+ n2n_sock_str_t sockbuf;
+
+ memset(&cmn, 0, sizeof(cmn) );
+ memset(®, 0, sizeof(reg) );
+ cmn.ttl=N2N_DEFAULT_TTL;
+ cmn.pc = n2n_register_super;
+ cmn.flags = 0;
+ memcpy( cmn.community, eee->community_name, N2N_COMMUNITY_SIZE );
+
+ for( idx=0; idx < N2N_COOKIE_SIZE; ++idx )
+ {
+ eee->last_cookie[idx] = rand() % 0xff;
+ }
+
+ memcpy( reg.cookie, eee->last_cookie, N2N_COOKIE_SIZE );
+ reg.auth.scheme=0; /* No auth yet */
+
+ idx=0;
+ encode_mac( reg.edgeMac, &idx, eee->device.mac_addr );
+
+ idx=0;
+ encode_REGISTER_SUPER( pktbuf, &idx, &cmn, ® );
+
+ traceEvent( TRACE_INFO, "send REGISTER_SUPER to %s",
+ sock_to_cstr( sockbuf, supernode ) );
+
+
+ sent = sendto_sock( eee->udp_sock, pktbuf, idx, supernode );
+
+}
+
+
+/** Send a REGISTER_ACK packet to a peer edge. */
+static void send_register_ack( n2n_edge_t * eee,
+ const n2n_sock_t * remote_peer,
+ const n2n_REGISTER_t * reg )
+{
+ uint8_t pktbuf[N2N_PKT_BUF_SIZE];
+ size_t idx;
+ ssize_t sent;
+ n2n_common_t cmn;
+ n2n_REGISTER_ACK_t ack;
+ n2n_sock_str_t sockbuf;
+
+ memset(&cmn, 0, sizeof(cmn) );
+ memset(&ack, 0, sizeof(reg) );
+ cmn.ttl=N2N_DEFAULT_TTL;
+ cmn.pc = n2n_register_ack;
+ cmn.flags = 0;
+ memcpy( cmn.community, eee->community_name, N2N_COMMUNITY_SIZE );
+
+ memset( &ack, 0, sizeof(ack) );
+ memcpy( ack.cookie, reg->cookie, N2N_COOKIE_SIZE );
+ memcpy( ack.srcMac, eee->device.mac_addr, N2N_MAC_SIZE );
+ memcpy( ack.dstMac, reg->srcMac, N2N_MAC_SIZE );
+
+ idx=0;
+ encode_REGISTER_ACK( pktbuf, &idx, &cmn, &ack );
+
+ traceEvent( TRACE_INFO, "send REGISTER_ACK %s",
+ sock_to_cstr( sockbuf, remote_peer ) );
+
+
+ sent = sendto_sock( eee->udp_sock, pktbuf, idx, remote_peer );
+}
+
+
+/** NOT IMPLEMENTED
+ *
+ * This would send a DEREGISTER packet to a peer edge or supernode to indicate
+ * the edge is going away.
+ */
+static void send_deregister(n2n_edge_t * eee,
+ n2n_sock_t * remote_peer)
+{
+ /* Marshall and send message */
+}
+
+
+static int is_empty_ip_address( const n2n_sock_t * sock );
+static void update_peer_address(n2n_edge_t * eee,
+ uint8_t from_supernode,
+ const n2n_mac_t mac,
+ const n2n_sock_t * peer,
+ time_t when);
+void check_peer( n2n_edge_t * eee,
+ uint8_t from_supernode,
+ const n2n_mac_t mac,
+ const n2n_sock_t * peer );
+void try_send_register( n2n_edge_t * eee,
+ uint8_t from_supernode,
+ const n2n_mac_t mac,
+ const n2n_sock_t * peer );
+void set_peer_operational( n2n_edge_t * eee,
+ const n2n_mac_t mac,
+ const n2n_sock_t * peer );
+
+
+
+/** Start the registration process.
+ *
+ * If the peer is already in pending_peers, ignore the request.
+ * If not in pending_peers, add it and send a REGISTER.
+ *
+ * If hdr is for a direct peer-to-peer packet, try to register back to sender
+ * even if the MAC is in pending_peers. This is because an incident direct
+ * packet indicates that peer-to-peer exchange should work so more aggressive
+ * registration can be permitted (once per incoming packet) as this should only
+ * last for a small number of packets..
+ *
+ * Called from the main loop when Rx a packet for our device mac.
+ */
+void try_send_register( n2n_edge_t * eee,
+ uint8_t from_supernode,
+ const n2n_mac_t mac,
+ const n2n_sock_t * peer )
+{
+ /* REVISIT: purge of pending_peers not yet done. */
+ struct peer_info * scan = find_peer_by_mac( eee->pending_peers, mac );
+ macstr_t mac_buf;
+ n2n_sock_str_t sockbuf;
+
+ if ( NULL == scan )
+ {
+ scan = calloc( 1, sizeof( struct peer_info ) );
+
+ memcpy(scan->mac_addr, mac, N2N_MAC_SIZE);
+ scan->sock = *peer;
+ scan->last_seen = time(NULL); /* Don't change this it marks the pending peer for removal. */
+
+ peer_list_add( &(eee->pending_peers), scan );
+
+ traceEvent( TRACE_DEBUG, "=== new pending %s -> %s",
+ macaddr_str( mac_buf, scan->mac_addr ),
+ sock_to_cstr( sockbuf, &(scan->sock) ) );
+
+ traceEvent( TRACE_INFO, "Pending peers list size=%u",
+ (unsigned int)peer_list_size( eee->pending_peers ) );
+
+ /* trace Sending REGISTER */
+
+ send_register(eee, &(scan->sock) );
+
+ /* pending_peers now owns scan. */
+ }
+ else
+ {
+ }
+}
+
+
+/** Update the last_seen time for this peer, or get registered. */
+void check_peer( n2n_edge_t * eee,
+ uint8_t from_supernode,
+ const n2n_mac_t mac,
+ const n2n_sock_t * peer )
+{
+ struct peer_info * scan = find_peer_by_mac( eee->known_peers, mac );
+
+ if ( NULL == scan )
+ {
+ /* Not in known_peers - start the REGISTER process. */
+ try_send_register( eee, from_supernode, mac, peer );
+ }
+ else
+ {
+ /* Already in known_peers. */
+ update_peer_address( eee, from_supernode, mac, peer, time(NULL) );
+ }
+}
+
+
+/* Move the peer from the pending_peers list to the known_peers lists.
+ *
+ * peer must be a pointer to an element of the pending_peers list.
+ *
+ * Called by main loop when Rx a REGISTER_ACK.
+ */
+void set_peer_operational( n2n_edge_t * eee,
+ const n2n_mac_t mac,
+ const n2n_sock_t * peer )
+{
+ struct peer_info * prev = NULL;
+ struct peer_info * scan;
+ macstr_t mac_buf;
+ n2n_sock_str_t sockbuf;
+
+ traceEvent( TRACE_INFO, "set_peer_operational: %s -> %s",
+ macaddr_str( mac_buf, mac),
+ sock_to_cstr( sockbuf, peer ) );
+
+ scan=eee->pending_peers;
+
+ while ( NULL != scan )
+ {
+ if ( 0 == memcmp( scan->mac_addr, mac, N2N_MAC_SIZE ) )
+ {
+ break; /* found. */
+ }
+
+ prev = scan;
+ scan = scan->next;
+ }
+
+ if ( scan )
+ {
+
+
+ /* Remove scan from pending_peers. */
+ if ( prev )
+ {
+ prev->next = scan->next;
+ }
+ else
+ {
+ eee->pending_peers = scan->next;
+ }
+
+ /* Add scan to known_peers. */
+ scan->next = eee->known_peers;
+ eee->known_peers = scan;
+
+ scan->sock = *peer;
+
+ traceEvent( TRACE_DEBUG, "=== new peer %s -> %s",
+ macaddr_str( mac_buf, scan->mac_addr),
+ sock_to_cstr( sockbuf, &(scan->sock) ) );
+
+ traceEvent( TRACE_INFO, "Pending peers list size=%u",
+ (unsigned int)peer_list_size( eee->pending_peers ) );
+
+ traceEvent( TRACE_INFO, "Operational peers list size=%u",
+ (unsigned int)peer_list_size( eee->known_peers ) );
+
+
+ scan->last_seen = time(NULL);
+ }
+ else
+ {
+ traceEvent( TRACE_DEBUG, "Failed to find sender in pending_peers." );
+ }
+}
+
+
+n2n_mac_t broadcast_mac = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+
+static int is_empty_ip_address( const n2n_sock_t * sock )
+{
+ const uint8_t * ptr=NULL;
+ size_t len=0;
+ size_t i;
+
+ if ( AF_INET6 == sock->family )
+ {
+ ptr = sock->addr.v6;
+ len = 16;
+ }
+ else
+ {
+ ptr = sock->addr.v4;
+ len = 4;
+ }
+
+ for (i=0; iknown_peers;
+ struct peer_info *prev = NULL; /* use to remove bad registrations. */
+ n2n_sock_str_t sockbuf1;
+ n2n_sock_str_t sockbuf2; /* don't clobber sockbuf1 if writing two addresses to trace */
+ macstr_t mac_buf;
+
+ if ( is_empty_ip_address( peer ) )
+ {
+ /* Not to be registered. */
+ return;
+ }
+
+ if ( 0 == memcmp( mac, broadcast_mac, N2N_MAC_SIZE ) )
+ {
+ /* Not to be registered. */
+ return;
+ }
+
+
+ while(scan != NULL)
+ {
+ if(memcmp(mac, scan->mac_addr, N2N_MAC_SIZE) == 0)
+ {
+ break;
+ }
+
+ prev = scan;
+ scan = scan->next;
+ }
+
+ if ( NULL == scan )
+ {
+ /* Not in known_peers. */
+ return;
+ }
+
+ if ( 0 != sock_equal( &(scan->sock), peer))
+ {
+ if ( 0 == from_supernode )
+ {
+ traceEvent( TRACE_NORMAL, "Peer changed %s: %s -> %s",
+ macaddr_str( mac_buf, scan->mac_addr ),
+ sock_to_cstr(sockbuf1, &(scan->sock)),
+ sock_to_cstr(sockbuf2, peer) );
+
+ /* The peer has changed public socket. It can no longer be assumed to be reachable. */
+ /* Remove the peer. */
+ if ( NULL == prev )
+ {
+ /* scan was head of list */
+ eee->known_peers = scan->next;
+ }
+ else
+ {
+ prev->next = scan->next;
+ }
+ free(scan);
+
+ try_send_register( eee, from_supernode, mac, peer );
+ }
+ else
+ {
+ /* Don't worry about what the supernode reports, it could be seeing a different socket. */
+ }
+ }
+ else
+ {
+ /* Found and unchanged. */
+ scan->last_seen = when;
+ }
+}
+
+
+
+#if defined(DUMMY_ID_00001) /* Disabled waiting for config option to enable it */
+
+
+
+static char gratuitous_arp[] = {
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* Dest mac */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Src mac */
+ 0x08, 0x06, /* ARP */
+ 0x00, 0x01, /* Ethernet */
+ 0x08, 0x00, /* IP */
+ 0x06, /* Hw Size */
+ 0x04, /* Protocol Size */
+ 0x00, 0x01, /* ARP Request */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Src mac */
+ 0x00, 0x00, 0x00, 0x00, /* Src IP */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Target mac */
+ 0x00, 0x00, 0x00, 0x00 /* Target IP */
+};
+
+
+/** Build a gratuitous ARP packet for a /24 layer 3 (IP) network. */
+static int build_gratuitous_arp(char *buffer, uint16_t buffer_len) {
+ if(buffer_len < sizeof(gratuitous_arp)) return(-1);
+
+ memcpy(buffer, gratuitous_arp, sizeof(gratuitous_arp));
+ memcpy(&buffer[6], device.mac_addr, 6);
+ memcpy(&buffer[22], device.mac_addr, 6);
+ memcpy(&buffer[28], &device.ip_addr, 4);
+
+ /* REVISIT: BbMaj7 - use a real netmask here. This is valid only by accident
+ * for /24 IPv4 networks. */
+ buffer[31] = 0xFF; /* Use a faked broadcast address */
+ memcpy(&buffer[38], &device.ip_addr, 4);
+ return(sizeof(gratuitous_arp));
+}
+
+/** Called from update_supernode_reg to periodically send gratuitous ARP
+ * broadcasts. */
+static void send_grat_arps(n2n_edge_t * eee,) {
+ char buffer[48];
+ size_t len;
+
+ traceEvent(TRACE_NORMAL, "Sending gratuitous ARP...");
+ len = build_gratuitous_arp(buffer, sizeof(buffer));
+ send_packet2net(eee, buffer, len);
+ send_packet2net(eee, buffer, len); /* Two is better than one :-) */
+}
+#endif /* #if defined(DUMMY_ID_00001) */
+
+
+
+
+/** @brief Check to see if we should re-register with the supernode.
+ *
+ * This is frequently called by the main loop.
+ */
+static void update_supernode_reg( n2n_edge_t * eee, time_t nowTime )
+{
+ if ( eee->sn_wait && ( nowTime > (eee->last_register_req + (eee->register_lifetime/10) ) ) )
+ {
+ /* fall through */
+ traceEvent( TRACE_DEBUG, "update_supernode_reg: doing fast retry." );
+ }
+ else if ( nowTime < (eee->last_register_req + eee->register_lifetime))
+ {
+ return; /* Too early */
+ }
+
+ if ( 0 == eee->sup_attempts )
+ {
+ /* Give up on that supernode and try the next one. */
+ ++(eee->sn_idx);
+
+ if (eee->sn_idx >= eee->sn_num)
+ {
+ /* Got to end of list, go back to the start. Also works for list of one entry. */
+ eee->sn_idx=0;
+ }
+
+ traceEvent(TRACE_WARNING, "Supernode not responding - moving to %u of %u",
+ (unsigned int)eee->sn_idx, (unsigned int)eee->sn_num );
+
+ eee->sup_attempts = N2N_EDGE_SUP_ATTEMPTS;
+ }
+ else
+ {
+ --(eee->sup_attempts);
+ }
+
+ if(eee->re_resolve_supernode_ip || (eee->sn_num > 1) )
+ {
+ supernode2addr(&(eee->supernode), eee->sn_ip_array[eee->sn_idx] );
+ }
+
+ traceEvent(TRACE_DEBUG, "Registering with supernode (%s) (attempts left %u)",
+ supernode_ip(eee), (unsigned int)eee->sup_attempts);
+
+ send_register_super( eee, &(eee->supernode) );
+
+ eee->sn_wait=1;
+
+ /* REVISIT: turn-on gratuitous ARP with config option. */
+ /* send_grat_arps(sock_fd, is_udp_sock); */
+
+ eee->last_register_req = nowTime;
+}
+
+
+
+/* @return 1 if destination is a peer, 0 if destination is supernode */
+static int find_peer_destination(n2n_edge_t * eee,
+ n2n_mac_t mac_address,
+ n2n_sock_t * destination)
+{
+ const struct peer_info *scan = eee->known_peers;
+ macstr_t mac_buf;
+ n2n_sock_str_t sockbuf;
+ int retval=0;
+
+ traceEvent(TRACE_DEBUG, "Searching destination peer for MAC %02X:%02X:%02X:%02X:%02X:%02X",
+ mac_address[0] & 0xFF, mac_address[1] & 0xFF, mac_address[2] & 0xFF,
+ mac_address[3] & 0xFF, mac_address[4] & 0xFF, mac_address[5] & 0xFF);
+
+ while(scan != NULL) {
+ traceEvent(TRACE_DEBUG, "Evaluating peer [MAC=%02X:%02X:%02X:%02X:%02X:%02X]",
+ scan->mac_addr[0] & 0xFF, scan->mac_addr[1] & 0xFF, scan->mac_addr[2] & 0xFF,
+ scan->mac_addr[3] & 0xFF, scan->mac_addr[4] & 0xFF, scan->mac_addr[5] & 0xFF
+ );
+
+ if((scan->last_seen > 0) &&
+ (memcmp(mac_address, scan->mac_addr, N2N_MAC_SIZE) == 0))
+ {
+ memcpy(destination, &scan->sock, sizeof(n2n_sock_t));
+ retval=1;
+ break;
+ }
+ scan = scan->next;
+ }
+
+ if ( 0 == retval )
+ {
+ memcpy(destination, &(eee->supernode), sizeof(struct sockaddr_in));
+ }
+
+ traceEvent(TRACE_DEBUG, "find_peer_address (%s) -> [%s]",
+ macaddr_str( mac_buf, mac_address ),
+ sock_to_cstr( sockbuf, destination ) );
+
+ return retval;
+}
+
+
+
+
+/* *********************************************** */
+
+static const struct option long_options[] = {
+ { "community", required_argument, NULL, 'c' },
+ { "supernode-list", required_argument, NULL, 'l' },
+ { "tun-device", required_argument, NULL, 'd' },
+ { "euid", required_argument, NULL, 'u' },
+ { "egid", required_argument, NULL, 'g' },
+ { "help" , no_argument, NULL, 'h' },
+ { "verbose", no_argument, NULL, 'v' },
+ { NULL, 0, NULL, 0 }
+};
+
+/* ***************************************************** */
+
+
+/** Send an ecapsulated ethernet PACKET to a destination edge or broadcast MAC
+ * address. */
+static int send_PACKET( n2n_edge_t * eee,
+ n2n_mac_t dstMac,
+ const uint8_t * pktbuf,
+ size_t pktlen )
+{
+ int dest;
+ ssize_t s;
+ n2n_sock_str_t sockbuf;
+ n2n_sock_t destination;
+
+ /* hexdump( pktbuf, pktlen ); */
+
+ dest = find_peer_destination(eee, dstMac, &destination);
+
+ if ( dest )
+ {
+ ++(eee->tx_p2p);
+ }
+ else
+ {
+ ++(eee->tx_sup);
+ }
+
+ traceEvent( TRACE_INFO, "send_PACKET to %s", sock_to_cstr( sockbuf, &destination ) );
+
+ s = sendto_sock( eee->udp_sock, pktbuf, pktlen, &destination );
+
+ return 0;
+}
+
+
+/* Choose the transop for Tx. This should be based on the newest valid
+ * cipherspec in the key schedule.
+ *
+ * Never fall back to NULL tranform unless no key sources were specified. It is
+ * better to render edge inoperative than to expose user data in the clear. In
+ * the case where all SAs are expired an arbitrary transform will be chosen for
+ * Tx. It will fail having no valid SAs but one must be selected.
+ */
+static size_t edge_choose_tx_transop( const n2n_edge_t * eee )
+{
+ if ( eee->null_transop)
+ {
+ return N2N_TRANSOP_NULL_IDX;
+ }
+
+ return eee->tx_transop_idx;
+}
+
+
+/** A layer-2 packet was received at the tunnel and needs to be sent via UDP. */
+static void send_packet2net(n2n_edge_t * eee,
+ uint8_t *tap_pkt, size_t len)
+{
+ ipstr_t ip_buf;
+ n2n_mac_t destMac;
+
+ n2n_common_t cmn;
+ n2n_PACKET_t pkt;
+
+ uint8_t pktbuf[N2N_PKT_BUF_SIZE];
+ size_t idx=0;
+ size_t tx_transop_idx=0;
+
+ ether_hdr_t eh;
+
+ /* tap_pkt is not aligned so we have to copy to aligned memory */
+ memcpy( &eh, tap_pkt, sizeof(ether_hdr_t) );
+
+ /* Discard IP packets that are not originated by this hosts */
+ if(!(eee->allow_routing)) {
+ if(ntohs(eh.type) == 0x0800) {
+ /* This is an IP packet from the local source address - not forwarded. */
+#define ETH_FRAMESIZE 14
+#define IP4_SRCOFFSET 12
+ uint32_t *dst = (uint32_t*)&tap_pkt[ETH_FRAMESIZE + IP4_SRCOFFSET];
+
+ /* Note: all elements of the_ip are in network order */
+ if( *dst != eee->device.ip_addr) {
+ /* This is a packet that needs to be routed */
+ traceEvent(TRACE_INFO, "Discarding routed packet [%s]",
+ intoa(ntohl(*dst), ip_buf, sizeof(ip_buf)));
+ return;
+ } else {
+ /* This packet is originated by us */
+ /* traceEvent(TRACE_INFO, "Sending non-routed packet"); */
+ }
+ }
+ }
+
+ /* Optionally compress then apply transforms, eg encryption. */
+
+ /* Once processed, send to destination in PACKET */
+
+ memcpy( destMac, tap_pkt, N2N_MAC_SIZE ); /* dest MAC is first in ethernet header */
+
+ memset( &cmn, 0, sizeof(cmn) );
+ cmn.ttl = N2N_DEFAULT_TTL;
+ cmn.pc = n2n_packet;
+ cmn.flags=0; /* no options, not from supernode, no socket */
+ memcpy( cmn.community, eee->community_name, N2N_COMMUNITY_SIZE );
+
+ memset( &pkt, 0, sizeof(pkt) );
+ memcpy( pkt.srcMac, eee->device.mac_addr, N2N_MAC_SIZE);
+ memcpy( pkt.dstMac, destMac, N2N_MAC_SIZE);
+
+ tx_transop_idx = edge_choose_tx_transop( eee );
+
+ pkt.sock.family=0; /* do not encode sock */
+ pkt.transform = eee->transop[tx_transop_idx].transform_id;
+
+ idx=0;
+ encode_PACKET( pktbuf, &idx, &cmn, &pkt );
+ traceEvent( TRACE_DEBUG, "encoded PACKET header of size=%u transform %u (idx=%u)",
+ (unsigned int)idx, (unsigned int)pkt.transform, (unsigned int)tx_transop_idx );
+
+ idx += eee->transop[tx_transop_idx].fwd( &(eee->transop[tx_transop_idx]),
+ pktbuf+idx, N2N_PKT_BUF_SIZE-idx,
+ tap_pkt, len );
+ ++(eee->transop[tx_transop_idx].tx_cnt); /* stats */
+
+ send_PACKET( eee, destMac, pktbuf, idx ); /* to peer or supernode */
+}
+
+
+/** Destination MAC 33:33:0:00:00:00 - 33:33:FF:FF:FF:FF is reserved for IPv6
+ * neighbour discovery.
+ */
+static int is_ip6_discovery( const void * buf, size_t bufsize )
+{
+ int retval = 0;
+
+ if ( bufsize >= sizeof(ether_hdr_t) )
+ {
+ /* copy to aligned memory */
+ ether_hdr_t eh;
+ memcpy( &eh, buf, sizeof(ether_hdr_t) );
+
+ if ( (0x33 == eh.dhost[0]) &&
+ (0x33 == eh.dhost[1]) )
+ {
+ retval = 1; /* This is an IPv6 multicast packet [RFC2464]. */
+ }
+ }
+ return retval;
+}
+
+/** Destination 01:00:5E:00:00:00 - 01:00:5E:7F:FF:FF is multicast ethernet.
+ */
+static int is_ethMulticast( const void * buf, size_t bufsize )
+{
+ int retval = 0;
+
+ /* Match 01:00:5E:00:00:00 - 01:00:5E:7F:FF:FF */
+ if ( bufsize >= sizeof(ether_hdr_t) )
+ {
+ /* copy to aligned memory */
+ ether_hdr_t eh;
+ memcpy( &eh, buf, sizeof(ether_hdr_t) );
+
+ if ( (0x01 == eh.dhost[0]) &&
+ (0x00 == eh.dhost[1]) &&
+ (0x5E == eh.dhost[2]) &&
+ (0 == (0x80 & eh.dhost[3])) )
+ {
+ retval = 1; /* This is an ethernet multicast packet [RFC1112]. */
+ }
+ }
+ return retval;
+}
+
+
+
+/** Read a single packet from the TAP interface, process it and write out the
+ * corresponding packet to the cooked socket.
+ */
+static void readFromTAPSocket( n2n_edge_t * eee )
+{
+ /* tun -> remote */
+ uint8_t eth_pkt[N2N_PKT_BUF_SIZE];
+ macstr_t mac_buf;
+ ssize_t len;
+
+ len = tuntap_read( &(eee->device), eth_pkt, N2N_PKT_BUF_SIZE );
+
+ if( (len <= 0) || (len > N2N_PKT_BUF_SIZE) )
+ {
+ traceEvent(TRACE_WARNING, "read()=%d [%d/%s]",
+ (signed int)len, errno, strerror(errno));
+ }
+ else
+ {
+ const uint8_t * mac = eth_pkt;
+ traceEvent(TRACE_INFO, "### Rx TAP packet (%4d) for %s",
+ (signed int)len, macaddr_str(mac_buf, mac) );
+
+ if ( eee->drop_multicast &&
+ ( is_ip6_discovery( eth_pkt, len ) ||
+ is_ethMulticast( eth_pkt, len)
+ )
+ )
+ {
+ traceEvent(TRACE_DEBUG, "Dropping multicast");
+ }
+ else
+ {
+ send_packet2net(eee, eth_pkt, len);
+ }
+ }
+}
+
+
+
+/** A PACKET has arrived containing an encapsulated ethernet datagram - usually
+ * encrypted. */
+static int handle_PACKET( n2n_edge_t * eee,
+ const n2n_common_t * cmn,
+ const n2n_PACKET_t * pkt,
+ const n2n_sock_t * orig_sender,
+ uint8_t * payload,
+ size_t psize )
+{
+ ssize_t data_sent_len;
+ uint8_t from_supernode;
+ uint8_t * eth_payload=NULL;
+ int retval = -1;
+ time_t now;
+
+ now = time(NULL);
+
+ traceEvent( TRACE_DEBUG, "handle_PACKET size %u transform %u",
+ (unsigned int)psize, (unsigned int)pkt->transform );
+ /* hexdump( payload, psize ); */
+
+ from_supernode= cmn->flags & N2N_FLAGS_FROM_SUPERNODE;
+
+ if ( from_supernode )
+ {
+ ++(eee->rx_sup);
+ eee->last_sup=now;
+ }
+ else
+ {
+ ++(eee->rx_p2p);
+ eee->last_p2p=now;
+ }
+
+ /* Update the sender in peer table entry */
+ check_peer( eee, from_supernode, pkt->srcMac, orig_sender );
+
+ /* Handle transform. */
+ {
+ uint8_t decodebuf[N2N_PKT_BUF_SIZE];
+ size_t eth_size;
+ size_t rx_transop_idx=0;
+
+ rx_transop_idx = transop_enum_to_index(pkt->transform);
+
+ if ( rx_transop_idx >=0 )
+ {
+ eth_payload = decodebuf;
+ eth_size = eee->transop[rx_transop_idx].rev( &(eee->transop[rx_transop_idx]),
+ eth_payload, N2N_PKT_BUF_SIZE,
+ payload, psize );
+ ++(eee->transop[rx_transop_idx].rx_cnt); /* stats */
+
+ /* Write ethernet packet to tap device. */
+ traceEvent( TRACE_INFO, "sending to TAP %u", (unsigned int)eth_size );
+ data_sent_len = tuntap_write(&(eee->device), eth_payload, eth_size);
+
+ if (data_sent_len == eth_size)
+ {
+ retval = 0;
+ }
+ }
+ else
+ {
+ traceEvent( TRACE_ERROR, "handle_PACKET dropped unknown transform enum %u",
+ (unsigned int)pkt->transform );
+ }
+ }
+
+ return retval;
+}
+
+
+/** Read a datagram from the management UDP socket and take appropriate
+ * action. */
+static void readFromMgmtSocket( n2n_edge_t * eee, int * keep_running )
+{
+ uint8_t udp_buf[N2N_PKT_BUF_SIZE]; /* Compete UDP packet */
+ ssize_t recvlen;
+ ssize_t sendlen;
+ struct sockaddr_in sender_sock;
+ socklen_t i;
+ size_t msg_len;
+ time_t now;
+
+ now = time(NULL);
+ i = sizeof(sender_sock);
+ recvlen=recvfrom(eee->udp_mgmt_sock, udp_buf, N2N_PKT_BUF_SIZE, 0/*flags*/,
+ (struct sockaddr *)&sender_sock, (socklen_t*)&i);
+
+ if ( recvlen < 0 )
+ {
+ traceEvent(TRACE_ERROR, "mgmt recvfrom failed with %s", strerror(errno) );
+
+ return; /* failed to receive data from UDP */
+ }
+
+ if ( recvlen >= 4 )
+ {
+ if ( 0 == memcmp( udp_buf, "stop", 4 ) )
+ {
+ traceEvent( TRACE_ERROR, "stop command received." );
+ *keep_running = 0;
+ return;
+ }
+
+ if ( 0 == memcmp( udp_buf, "help", 4 ) )
+ {
+ msg_len=0;
+ ++traceLevel;
+
+ msg_len += snprintf( (char *)(udp_buf+msg_len), (N2N_PKT_BUF_SIZE-msg_len),
+ "Help for edge management console:\n"
+ " stop Gracefully exit edge\n"
+ " help This help message\n"
+ " +verb Increase verbosity of logging\n"
+ " -verb Decrease verbosity of logging\n"
+ " reload Re-read the keyschedule\n"
+ " Display statistics\n\n");
+
+ sendto( eee->udp_mgmt_sock, udp_buf, msg_len, 0/*flags*/,
+ (struct sockaddr *)&sender_sock, sizeof(struct sockaddr_in) );
+
+ return;
+ }
+
+ }
+
+ if ( recvlen >= 5 )
+ {
+ if ( 0 == memcmp( udp_buf, "+verb", 5 ) )
+ {
+ msg_len=0;
+ ++traceLevel;
+
+ traceEvent( TRACE_ERROR, "+verb traceLevel=%u", (unsigned int)traceLevel );
+ msg_len += snprintf( (char *)(udp_buf+msg_len), (N2N_PKT_BUF_SIZE-msg_len),
+ "> +OK traceLevel=%u\n", (unsigned int)traceLevel );
+
+ sendto( eee->udp_mgmt_sock, udp_buf, msg_len, 0/*flags*/,
+ (struct sockaddr *)&sender_sock, sizeof(struct sockaddr_in) );
+
+ return;
+ }
+
+ if ( 0 == memcmp( udp_buf, "-verb", 5 ) )
+ {
+ msg_len=0;
+
+ if ( traceLevel > 0 )
+ {
+ --traceLevel;
+ msg_len += snprintf( (char *)(udp_buf+msg_len), (N2N_PKT_BUF_SIZE-msg_len),
+ "> -OK traceLevel=%u\n", traceLevel );
+ }
+ else
+ {
+ msg_len += snprintf( (char *)(udp_buf+msg_len), (N2N_PKT_BUF_SIZE-msg_len),
+ "> -NOK traceLevel=%u\n", traceLevel );
+ }
+
+ traceEvent( TRACE_ERROR, "-verb traceLevel=%u", (unsigned int)traceLevel );
+
+ sendto( eee->udp_mgmt_sock, udp_buf, msg_len, 0/*flags*/,
+ (struct sockaddr *)&sender_sock, sizeof(struct sockaddr_in) );
+ return;
+ }
+ }
+
+ if ( recvlen >= 6 )
+ {
+ if ( 0 == memcmp( udp_buf, "reload", 6 ) )
+ {
+ if ( strlen( eee->keyschedule ) > 0 )
+ {
+ if ( edge_init_keyschedule(eee) == 0 )
+ {
+ msg_len=0;
+ msg_len += snprintf( (char *)(udp_buf+msg_len), (N2N_PKT_BUF_SIZE-msg_len),
+ "> OK\n" );
+ sendto( eee->udp_mgmt_sock, udp_buf, msg_len, 0/*flags*/,
+ (struct sockaddr *)&sender_sock, sizeof(struct sockaddr_in) );
+ }
+ return;
+ }
+ }
+ }
+
+ traceEvent(TRACE_DEBUG, "mgmt status rq" );
+
+ msg_len=0;
+ msg_len += snprintf( (char *)(udp_buf+msg_len), (N2N_PKT_BUF_SIZE-msg_len),
+ "Statistics for edge\n" );
+
+ msg_len += snprintf( (char *)(udp_buf+msg_len), (N2N_PKT_BUF_SIZE-msg_len),
+ "uptime %lu\n",
+ time(NULL) - eee->start_time );
+
+ msg_len += snprintf( (char *)(udp_buf+msg_len), (N2N_PKT_BUF_SIZE-msg_len),
+ "paths super:%u,%u p2p:%u,%u\n",
+ (unsigned int)eee->tx_sup,
+ (unsigned int)eee->rx_sup,
+ (unsigned int)eee->tx_p2p,
+ (unsigned int)eee->rx_p2p );
+
+ msg_len += snprintf( (char *)(udp_buf+msg_len), (N2N_PKT_BUF_SIZE-msg_len),
+ "trans:null |%6u|%6u|\n"
+ "trans:tf |%6u|%6u|\n"
+ "trans:aes |%6u|%6u|\n",
+ (unsigned int)eee->transop[N2N_TRANSOP_NULL_IDX].tx_cnt,
+ (unsigned int)eee->transop[N2N_TRANSOP_NULL_IDX].rx_cnt,
+ (unsigned int)eee->transop[N2N_TRANSOP_TF_IDX].tx_cnt,
+ (unsigned int)eee->transop[N2N_TRANSOP_TF_IDX].rx_cnt,
+ (unsigned int)eee->transop[N2N_TRANSOP_AESCBC_IDX].tx_cnt,
+ (unsigned int)eee->transop[N2N_TRANSOP_AESCBC_IDX].rx_cnt );
+
+ msg_len += snprintf( (char *)(udp_buf+msg_len), (N2N_PKT_BUF_SIZE-msg_len),
+ "peers pend:%u full:%u\n",
+ (unsigned int)peer_list_size( eee->pending_peers ),
+ (unsigned int)peer_list_size( eee->known_peers ) );
+
+ msg_len += snprintf( (char *)(udp_buf+msg_len), (N2N_PKT_BUF_SIZE-msg_len),
+ "last super:%lu(%ld sec ago) p2p:%lu(%ld sec ago)\n",
+ eee->last_sup, (now-eee->last_sup), eee->last_p2p, (now-eee->last_p2p) );
+
+ traceEvent(TRACE_DEBUG, "mgmt status sending: %s", udp_buf );
+
+
+ sendlen = sendto( eee->udp_mgmt_sock, udp_buf, msg_len, 0/*flags*/,
+ (struct sockaddr *)&sender_sock, sizeof(struct sockaddr_in) );
+
+}
+
+
+/** Read a datagram from the main UDP socket to the internet. */
+static void readFromIPSocket( n2n_edge_t * eee )
+{
+ n2n_common_t cmn; /* common fields in the packet header */
+
+ n2n_sock_str_t sockbuf1;
+ n2n_sock_str_t sockbuf2; /* don't clobber sockbuf1 if writing two addresses to trace */
+ macstr_t mac_buf1;
+ macstr_t mac_buf2;
+
+ uint8_t udp_buf[N2N_PKT_BUF_SIZE]; /* Compete UDP packet */
+ ssize_t recvlen;
+ size_t rem;
+ size_t idx;
+ size_t msg_type;
+ uint8_t from_supernode;
+ struct sockaddr_in sender_sock;
+ n2n_sock_t sender;
+ n2n_sock_t * orig_sender=NULL;
+ time_t now=0;
+
+ size_t i;
+
+ i = sizeof(sender_sock);
+ recvlen=recvfrom(eee->udp_sock, udp_buf, N2N_PKT_BUF_SIZE, 0/*flags*/,
+ (struct sockaddr *)&sender_sock, (socklen_t*)&i);
+
+ if ( recvlen < 0 )
+ {
+ traceEvent(TRACE_ERROR, "recvfrom failed with %s", strerror(errno) );
+
+ return; /* failed to receive data from UDP */
+ }
+
+ /* REVISIT: when UDP/IPv6 is supported we will need a flag to indicate which
+ * IP transport version the packet arrived on. May need to UDP sockets. */
+ sender.family = AF_INET; /* udp_sock was opened PF_INET v4 */
+ sender.port = ntohs(sender_sock.sin_port);
+ memcpy( &(sender.addr.v4), &(sender_sock.sin_addr.s_addr), IPV4_SIZE );
+
+ /* The packet may not have an orig_sender socket spec. So default to last
+ * hop as sender. */
+ orig_sender=&sender;
+
+ traceEvent(TRACE_INFO, "### Rx N2N UDP (%d) from %s",
+ (signed int)recvlen, sock_to_cstr(sockbuf1, &sender) );
+
+ /* hexdump( udp_buf, recvlen ); */
+
+ rem = recvlen; /* Counts down bytes of packet to protect against buffer overruns. */
+ idx = 0; /* marches through packet header as parts are decoded. */
+ if ( decode_common(&cmn, udp_buf, &rem, &idx) < 0 )
+ {
+ traceEvent( TRACE_ERROR, "Failed to decode common section in N2N_UDP" );
+ return; /* failed to decode packet */
+ }
+
+ now = time(NULL);
+
+ msg_type = cmn.pc; /* packet code */
+ from_supernode= cmn.flags & N2N_FLAGS_FROM_SUPERNODE;
+
+ if( 0 == memcmp(cmn.community, eee->community_name, N2N_COMMUNITY_SIZE) )
+ {
+ if( msg_type == MSG_TYPE_PACKET)
+ {
+ /* process PACKET - most frequent so first in list. */
+ n2n_PACKET_t pkt;
+
+ decode_PACKET( &pkt, &cmn, udp_buf, &rem, &idx );
+
+ if ( pkt.sock.family )
+ {
+ orig_sender = &(pkt.sock);
+ }
+
+ traceEvent(TRACE_INFO, "Rx PACKET from %s (%s)",
+ sock_to_cstr(sockbuf1, &sender),
+ sock_to_cstr(sockbuf2, orig_sender) );
+
+ handle_PACKET( eee, &cmn, &pkt, orig_sender, udp_buf+idx, recvlen-idx );
+ }
+ else if(msg_type == MSG_TYPE_REGISTER)
+ {
+ /* Another edge is registering with us */
+ n2n_REGISTER_t reg;
+
+ decode_REGISTER( ®, &cmn, udp_buf, &rem, &idx );
+
+ if ( reg.sock.family )
+ {
+ orig_sender = &(reg.sock);
+ }
+
+ traceEvent(TRACE_INFO, "Rx REGISTER src=%s dst=%s from peer %s (%s)",
+ macaddr_str( mac_buf1, reg.srcMac ),
+ macaddr_str( mac_buf2, reg.dstMac ),
+ sock_to_cstr(sockbuf1, &sender),
+ sock_to_cstr(sockbuf2, orig_sender) );
+
+ if ( 0 == memcmp(reg.dstMac, (eee->device.mac_addr), 6) )
+ {
+ check_peer( eee, from_supernode, reg.srcMac, orig_sender );
+ }
+
+ send_register_ack(eee, orig_sender, ®);
+ }
+ else if(msg_type == MSG_TYPE_REGISTER_ACK)
+ {
+ /* Peer edge is acknowledging our register request */
+ n2n_REGISTER_ACK_t ra;
+
+ decode_REGISTER_ACK( &ra, &cmn, udp_buf, &rem, &idx );
+
+ if ( ra.sock.family )
+ {
+ orig_sender = &(ra.sock);
+ }
+
+ traceEvent(TRACE_INFO, "Rx REGISTER_ACK src=%s dst=%s from peer %s (%s)",
+ macaddr_str( mac_buf1, ra.srcMac ),
+ macaddr_str( mac_buf2, ra.dstMac ),
+ sock_to_cstr(sockbuf1, &sender),
+ sock_to_cstr(sockbuf2, orig_sender) );
+
+ /* Move from pending_peers to known_peers; ignore if not in pending. */
+ set_peer_operational( eee, ra.srcMac, &sender );
+ }
+ else if(msg_type == MSG_TYPE_REGISTER_SUPER_ACK)
+ {
+ n2n_REGISTER_SUPER_ACK_t ra;
+
+ if ( eee->sn_wait )
+ {
+ decode_REGISTER_SUPER_ACK( &ra, &cmn, udp_buf, &rem, &idx );
+
+ if ( ra.sock.family )
+ {
+ orig_sender = &(ra.sock);
+ }
+
+ traceEvent(TRACE_NORMAL, "Rx REGISTER_SUPER_ACK myMAC=%s [%s] (external %s). Attempts %u",
+ macaddr_str( mac_buf1, ra.edgeMac ),
+ sock_to_cstr(sockbuf1, &sender),
+ sock_to_cstr(sockbuf2, orig_sender),
+ (unsigned int)eee->sup_attempts );
+
+ if ( 0 == memcmp( ra.cookie, eee->last_cookie, N2N_COOKIE_SIZE ) )
+ {
+ if ( ra.num_sn > 0 )
+ {
+ traceEvent(TRACE_NORMAL, "Rx REGISTER_SUPER_ACK backup supernode at %s",
+ sock_to_cstr(sockbuf1, &(ra.sn_bak) ) );
+ }
+
+ eee->last_sup = now;
+ eee->sn_wait=0;
+ eee->sup_attempts = N2N_EDGE_SUP_ATTEMPTS; /* refresh because we got a response */
+
+ /* REVISIT: store sn_back */
+ eee->register_lifetime = ra.lifetime;
+ eee->register_lifetime = MAX( eee->register_lifetime, REGISTER_SUPER_INTERVAL_MIN );
+ eee->register_lifetime = MIN( eee->register_lifetime, REGISTER_SUPER_INTERVAL_MAX );
+ }
+ else
+ {
+ traceEvent( TRACE_WARNING, "Rx REGISTER_SUPER_ACK with wrong or old cookie." );
+ }
+ }
+ else
+ {
+ traceEvent( TRACE_WARNING, "Rx REGISTER_SUPER_ACK with no outstanding REGISTER_SUPER." );
+ }
+ }
+ else
+ {
+ /* Not a known message type */
+ traceEvent(TRACE_WARNING, "Unable to handle packet type %d: ignored", (signed int)msg_type);
+ return;
+ }
+ } /* if (community match) */
+ else
+ {
+ traceEvent(TRACE_WARNING, "Received packet with invalid community");
+ }
+
+}
+
+/* ***************************************************** */
+
+
+#ifdef WIN32
+static DWORD tunReadThread(LPVOID lpArg )
+{
+ n2n_edge_t *eee = (n2n_edge_t*)lpArg;
+
+ while(1)
+ {
+ readFromTAPSocket(eee);
+ }
+
+ return((DWORD)NULL);
+}
+
+
+/** Start a second thread in Windows because TUNTAP interfaces do not expose
+ * file descriptors. */
+static void startTunReadThread(n2n_edge_t *eee)
+{
+ HANDLE hThread;
+ DWORD dwThreadId;
+
+ hThread = CreateThread(NULL, /* security attributes */
+ 0, /* use default stack size */
+ (LPTHREAD_START_ROUTINE)tunReadThread, /* thread function */
+ (void*)eee, /* argument to thread function */
+ 0, /* thread creation flags */
+ &dwThreadId); /* thread id out */
+}
+#endif
+
+/* ***************************************************** */
+
+/** Resolve the supernode IP address.
+ *
+ * REVISIT: This is a really bad idea. The edge will block completely while the
+ * hostname resolution is performed. This could take 15 seconds.
+ */
+static void supernode2addr(n2n_sock_t * sn, const n2n_sn_name_t addrIn)
+{
+ n2n_sn_name_t addr;
+ const char *supernode_host;
+
+ memcpy( addr, addrIn, N2N_EDGE_SN_HOST_SIZE );
+
+ supernode_host = strtok(addr, ":");
+
+ if(supernode_host)
+ {
+ in_addr_t sn_addr;
+ char *supernode_port = strtok(NULL, ":");
+ const struct addrinfo aihints = {0, PF_INET, 0, 0, 0, NULL, NULL, NULL};
+ struct addrinfo * ainfo = NULL;
+ int nameerr;
+
+ if ( supernode_port )
+ sn->port = atoi(supernode_port);
+ else
+ traceEvent(TRACE_WARNING, "Bad supernode parameter (-l ) %s %s:%s",
+ addr, supernode_host, supernode_port);
+
+ nameerr = getaddrinfo( supernode_host, NULL, &aihints, &ainfo );
+
+ if( 0 == nameerr )
+ {
+ struct sockaddr_in * saddr;
+
+ /* ainfo s the head of a linked list if non-NULL. */
+ if ( ainfo && (PF_INET == ainfo->ai_family) )
+ {
+ /* It is definitely and IPv4 address -> sockaddr_in */
+ saddr = (struct sockaddr_in *)ainfo->ai_addr;
+
+ memcpy( sn->addr.v4, &(saddr->sin_addr.s_addr), IPV4_SIZE );
+ sn->family=AF_INET;
+ }
+ else
+ {
+ /* Should only return IPv4 addresses due to aihints. */
+ traceEvent(TRACE_WARNING, "Failed to resolve supernode IPv4 address for %s", supernode_host);
+ }
+
+ freeaddrinfo(ainfo); /* free everything allocated by getaddrinfo(). */
+ ainfo = NULL;
+ } else {
+ traceEvent(TRACE_WARNING, "Failed to resolve supernode host %s, assuming numeric", supernode_host);
+ sn_addr = inet_addr(supernode_host); /* uint32_t */
+ memcpy( sn->addr.v4, &(sn_addr), IPV4_SIZE );
+ sn->family=AF_INET;
+ }
+
+ } else
+ traceEvent(TRACE_WARNING, "Wrong supernode parameter (-l )");
+}
+
+/* ***************************************************** */
+
+
+/** Find the address and IP mode for the tuntap device.
+ *
+ * s is one of these forms:
+ *
+ * := | A.B.C.D
+ *
+ * | static: | dhcp:
+ *
+ * If the mode is present (colon required) then fill ip_mode with that value
+ * otherwise do not change ip_mode. Fill ip_mode with everything after the
+ * colon if it is present; or s if colon is not present.
+ *
+ * ip_add and ip_mode are NULL terminated if modified.
+ *
+ * return 0 on success and -1 on error
+ */
+static int scan_address( char * ip_addr, size_t addr_size,
+ char * ip_mode, size_t mode_size,
+ const char * s )
+{
+ int retval = -1;
+ char * p;
+
+ if ( ( NULL == s ) || ( NULL == ip_addr) )
+ {
+ return -1;
+ }
+
+ memset(ip_addr, 0, addr_size);
+
+ p = strpbrk(s, ":");
+
+ if ( p )
+ {
+ /* colon is present */
+ if ( ip_mode )
+ {
+ size_t end=0;
+
+ memset(ip_mode, 0, mode_size);
+ end = MIN( p-s, (ssize_t)(mode_size-1) ); /* ensure NULL term */
+ strncpy( ip_mode, s, end );
+ strncpy( ip_addr, p+1, addr_size-1 ); /* ensure NULL term */
+ retval = 0;
+ }
+ }
+ else
+ {
+ /* colon is not present */
+ strncpy( ip_addr, s, addr_size );
+ }
+
+ return retval;
+}
+
+static int run_loop(n2n_edge_t * eee );
+
+#define N2N_NETMASK_STR_SIZE 16 /* dotted decimal 12 numbers + 3 dots */
+#define N2N_MACNAMSIZ 18 /* AA:BB:CC:DD:EE:FF + NULL*/
+#define N2N_IF_MODE_SIZE 16 /* static | dhcp */
+
+/** Entry point to program from kernel. */
+int main(int argc, char* argv[])
+{
+ int opt;
+ int local_port = 0 /* any port */;
+ int mgmt_port = N2N_EDGE_MGMT_PORT; /* 5644 by default */
+ char tuntap_dev_name[N2N_IFNAMSIZ] = "edge0";
+ char ip_mode[N2N_IF_MODE_SIZE]="static";
+ char ip_addr[N2N_NETMASK_STR_SIZE] = "";
+ char netmask[N2N_NETMASK_STR_SIZE]="255.255.255.0";
+ int mtu = DEFAULT_MTU;
+ int got_s = 0;
+
+#ifndef WIN32
+ uid_t userid=0; /* root is the only guaranteed ID */
+ gid_t groupid=0; /* root is the only guaranteed ID */
+#endif
+
+ char device_mac[N2N_MACNAMSIZ]="";
+ char * encrypt_key=NULL;
+
+ int i, effectiveargc=0;
+ char ** effectiveargv=NULL;
+ char * linebuffer = NULL;
+
+ n2n_edge_t eee; /* single instance for this program */
+
+ if (-1 == edge_init(&eee) )
+ {
+ traceEvent( TRACE_ERROR, "Failed in edge_init" );
+ exit(1);
+ }
+
+ if( getenv( "N2N_KEY" ))
+ {
+ encrypt_key = strdup( getenv( "N2N_KEY" ));
+ }
+
+#ifdef WIN32
+ tuntap_dev_name[0] = '\0';
+#endif
+ memset(&(eee.supernode), 0, sizeof(eee.supernode));
+ eee.supernode.family = AF_INET;
+
+ linebuffer = (char *)malloc(MAX_CMDLINE_BUFFER_LENGTH);
+ if (!linebuffer)
+ {
+ traceEvent( TRACE_ERROR, "Unable to allocate memory");
+ exit(1);
+ }
+ snprintf(linebuffer, MAX_CMDLINE_BUFFER_LENGTH, "%s",argv[0]);
+
+#ifdef WIN32
+ for(i=0; i < (int)strlen(linebuffer); i++)
+ if(linebuffer[i] == '\\') linebuffer[i] = '/';
+#endif
+
+ for(i=1;i 0 )
+ {
+ fprintf(stderr, "Error: -K and -k options are mutually exclusive.\n");
+ exit(1);
+ } else {
+ traceEvent(TRACE_DEBUG, "encrypt_key = '%s'\n", encrypt_key);
+ encrypt_key = strdup(optarg);
+ }
+ break;
+ }
+ case 'r': /* enable packet routing across n2n endpoints */
+ {
+ eee.allow_routing = 1;
+ break;
+ }
+
+ case 'l': /* supernode-list */
+ {
+ if ( eee.sn_num < N2N_EDGE_NUM_SUPERNODES )
+ {
+ strncpy( (eee.sn_ip_array[eee.sn_num]), optarg, N2N_EDGE_SN_HOST_SIZE);
+ traceEvent(TRACE_DEBUG, "Adding supernode[%u] = %s\n", (unsigned int)eee.sn_num, (eee.sn_ip_array[eee.sn_num]) );
+ ++eee.sn_num;
+ }
+ else
+ {
+ fprintf(stderr, "Too many supernodes!\n" );
+ exit(1);
+ }
+ break;
+ }
+
+#if defined(N2N_CAN_NAME_IFACE)
+ case 'd': /* TUNTAP name */
+ {
+ strncpy(tuntap_dev_name, optarg, N2N_IFNAMSIZ);
+ break;
+ }
+#endif
+
+ case 'b':
+ {
+ eee.re_resolve_supernode_ip = 1;
+ break;
+ }
+
+ case 'p':
+ {
+ local_port = atoi(optarg);
+ break;
+ }
+
+ case 't':
+ {
+ mgmt_port = atoi(optarg);
+ break;
+ }
+
+ case 's': /* Subnet Mask */
+ {
+ if (0 != got_s)
+ {
+ traceEvent(TRACE_WARNING, "Multiple subnet masks supplied.");
+ }
+ strncpy(netmask, optarg, N2N_NETMASK_STR_SIZE);
+ got_s = 1;
+ break;
+ }
+
+ case 'h': /* help */
+ {
+ help();
+ break;
+ }
+
+ case 'v': /* verbose */
+ {
+ ++traceLevel; /* do 2 -v flags to increase verbosity to DEBUG level*/
+ break;
+ }
+
+ } /* end switch */
+ }
+
+
+#ifdef N2N_HAVE_DAEMON
+ if ( eee.daemon )
+ {
+ useSyslog=1; /* traceEvent output now goes to syslog. */
+ if ( -1 == daemon( 0, 0 ) )
+ {
+ traceEvent( TRACE_ERROR, "Failed to become daemon." );
+ exit(-5);
+ }
+ }
+#endif /* #ifdef N2N_HAVE_DAEMON */
+
+
+ traceEvent( TRACE_NORMAL, "Starting n2n edge %s %s", n2n_sw_version, n2n_sw_buildDate );
+
+
+ for (i=0; i< N2N_EDGE_NUM_SUPERNODES; ++i )
+ {
+ traceEvent( TRACE_NORMAL, "supernode %u => %s\n", i, (eee.sn_ip_array[i]) );
+ }
+
+ supernode2addr( &(eee.supernode), eee.sn_ip_array[eee.sn_idx] );
+
+
+ for ( i=0; i 0)
+ traceEvent(TRACE_NORMAL, "Binding to local port %d", (signed int)local_port);
+
+ if ( encrypt_key ) {
+ if(edge_init_twofish( &eee, (uint8_t *)(encrypt_key), strlen(encrypt_key) ) < 0) {
+ fprintf(stderr, "Error: twofish setup failed.\n" );
+ return(-1);
+ }
+ } else if ( strlen(eee.keyschedule) > 0 ) {
+ if (edge_init_keyschedule( &eee ) != 0 ) {
+ fprintf(stderr, "Error: keyschedule setup failed.\n" );
+ return(-1);
+ }
+
+ }
+ /* else run in NULL mode */
+
+
+ eee.udp_sock = open_socket(local_port, 1 /*bind ANY*/ );
+ if(eee.udp_sock < 0)
+ {
+ traceEvent( TRACE_ERROR, "Failed to bind main UDP port %u", (signed int)local_port );
+ return(-1);
+ }
+
+ eee.udp_mgmt_sock = open_socket(mgmt_port, 0 /* bind LOOPBACK*/ );
+
+ if(eee.udp_mgmt_sock < 0)
+ {
+ traceEvent( TRACE_ERROR, "Failed to bind management UDP port %u", (unsigned int)N2N_EDGE_MGMT_PORT );
+ return(-1);
+ }
+
+
+ traceEvent(TRACE_NORMAL, "edge started");
+
+ update_supernode_reg(&eee, time(NULL) );
+
+ return run_loop(&eee);
+}
+
+static int run_loop(n2n_edge_t * eee )
+{
+ int keep_running=1;
+ size_t numPurged;
+ time_t lastIfaceCheck=0;
+ time_t lastTransop=0;
+
+
+#ifdef WIN32
+ startTunReadThread(eee);
+#endif
+
+ /* Main loop
+ *
+ * select() is used to wait for input on either the TAP fd or the UDP/TCP
+ * socket. When input is present the data is read and processed by either
+ * readFromIPSocket() or readFromTAPSocket()
+ */
+
+ while(keep_running)
+ {
+ int rc, max_sock = 0;
+ fd_set socket_mask;
+ struct timeval wait_time;
+ time_t nowTime;
+
+ FD_ZERO(&socket_mask);
+ FD_SET(eee->udp_sock, &socket_mask);
+ FD_SET(eee->udp_mgmt_sock, &socket_mask);
+ max_sock = max( eee->udp_sock, eee->udp_mgmt_sock );
+#ifndef WIN32
+ FD_SET(eee->device.fd, &socket_mask);
+ max_sock = max( max_sock, eee->device.fd );
+#endif
+
+ wait_time.tv_sec = SOCKET_TIMEOUT_INTERVAL_SECS; wait_time.tv_usec = 0;
+
+ rc = select(max_sock+1, &socket_mask, NULL, NULL, &wait_time);
+ nowTime=time(NULL);
+
+ /* Make sure ciphers are updated before the packet is treated. */
+ if ( ( nowTime - lastTransop ) > TRANSOP_TICK_INTERVAL )
+ {
+ lastTransop = nowTime;
+
+ n2n_tick_transop( eee, nowTime );
+ }
+
+ if(rc > 0)
+ {
+ /* Any or all of the FDs could have input; check them all. */
+
+ if(FD_ISSET(eee->udp_sock, &socket_mask))
+ {
+ /* Read a cooked socket from the internet socket. Writes on the TAP
+ * socket. */
+ readFromIPSocket(eee);
+ }
+
+ if(FD_ISSET(eee->udp_mgmt_sock, &socket_mask))
+ {
+ /* Read a cooked socket from the internet socket. Writes on the TAP
+ * socket. */
+ readFromMgmtSocket(eee, &keep_running);
+ }
+
+#ifndef WIN32
+ if(FD_ISSET(eee->device.fd, &socket_mask))
+ {
+ /* Read an ethernet frame from the TAP socket. Write on the IP
+ * socket. */
+ readFromTAPSocket(eee);
+ }
+#endif
+ }
+
+ /* Finished processing select data. */
+
+
+ update_supernode_reg(eee, nowTime);
+
+ numPurged = purge_expired_registrations( &(eee->known_peers) );
+ numPurged += purge_expired_registrations( &(eee->pending_peers) );
+ if ( numPurged > 0 )
+ {
+ traceEvent( TRACE_NORMAL, "Peer removed: pending=%u, operational=%u",
+ (unsigned int)peer_list_size( eee->pending_peers ),
+ (unsigned int)peer_list_size( eee->known_peers ) );
+ }
+
+ if ( eee->dyn_ip_mode &&
+ (( nowTime - lastIfaceCheck ) > IFACE_UPDATE_INTERVAL ) )
+ {
+ traceEvent(TRACE_NORMAL, "Re-checking dynamic IP address.");
+ tuntap_get_address( &(eee->device) );
+ lastIfaceCheck = nowTime;
+ }
+
+ } /* while */
+
+ send_deregister( eee, &(eee->supernode));
+
+ closesocket(eee->udp_sock);
+ tuntap_close(&(eee->device));
+
+ edge_deinit( eee );
+
+ return(0);
+}
+
+
diff --git a/gen_keyfile.py b/gen_keyfile.py
new file mode 100755
index 0000000..b6dc3e6
--- /dev/null
+++ b/gen_keyfile.py
@@ -0,0 +1,44 @@
+#!/usr/bin/env python
+
+# (c) 2009 Richard Andrews
+
+# Program to generate a n2n_edge key schedule file for twofish keys
+# Each key line consists of the following element
+#
+#
+# where , are UNIX time_t values of key valid period
+# is the transform ID (=2 for twofish)
+# is twofish-specific data as follows
+# _
+
+import os
+import sys
+import time
+import random
+
+NUM_KEYS=30
+KEY_LIFE=300
+KEY_LEN=16
+
+now=time.time()
+start_sa=random.randint( 0, 0xffffffff )
+
+random.seed(now) # note now is a floating point time value
+
+def rand_key():
+ key=str()
+ for i in range(0,KEY_LEN):
+ key += "%02x"%( random.randint( 0, 255) )
+
+ return key
+
+for i in range(0,NUM_KEYS):
+ from_time = now + (KEY_LIFE * (i-1) )
+ until_time = now + (KEY_LIFE * (i+1) )
+ key = rand_key()
+ sa_idx = start_sa + i
+ transform_id = random.randint( 2, 3 )
+
+ sys.stdout.write("%d %d %d %d_%s\n"%(from_time, until_time, transform_id,sa_idx, key) )
+
+
diff --git a/lzoconf.h b/lzoconf.h
new file mode 100644
index 0000000..cc437f1
--- /dev/null
+++ b/lzoconf.h
@@ -0,0 +1,417 @@
+/* lzoconf.h -- configuration for the LZO real-time data compression library
+
+ This file is part of the LZO real-time data compression library.
+
+ Copyright (C) 2008 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2007 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2006 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2005 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2004 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2003 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2002 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2001 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2000 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 1997 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 1996 Markus Franz Xaver Johannes Oberhumer
+ All Rights Reserved.
+
+ The LZO library 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.
+
+ The LZO library 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 the LZO library; see the file COPYING.
+ If not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ Markus F.X.J. Oberhumer
+
+ http://www.oberhumer.com/opensource/lzo/
+ */
+
+
+#ifndef __LZOCONF_H_INCLUDED
+#define __LZOCONF_H_INCLUDED
+
+#define LZO_VERSION 0x2030
+#define LZO_VERSION_STRING "2.03"
+#define LZO_VERSION_DATE "Apr 30 2008"
+
+/* internal Autoconf configuration file - only used when building LZO */
+#if defined(LZO_HAVE_CONFIG_H)
+# include
+#endif
+#include
+#include
+
+
+/***********************************************************************
+// LZO requires a conforming
+************************************************************************/
+
+#if !defined(CHAR_BIT) || (CHAR_BIT != 8)
+# error "invalid CHAR_BIT"
+#endif
+#if !defined(UCHAR_MAX) || !defined(UINT_MAX) || !defined(ULONG_MAX)
+# error "check your compiler installation"
+#endif
+#if (USHRT_MAX < 1) || (UINT_MAX < 1) || (ULONG_MAX < 1)
+# error "your limits.h macros are broken"
+#endif
+
+/* get OS and architecture defines */
+#ifndef __LZODEFS_H_INCLUDED
+#include "lzodefs.h"
+#endif
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/***********************************************************************
+// some core defines
+************************************************************************/
+
+#if !defined(LZO_UINT32_C)
+# if (UINT_MAX < LZO_0xffffffffL)
+# define LZO_UINT32_C(c) c ## UL
+# else
+# define LZO_UINT32_C(c) ((c) + 0U)
+# endif
+#endif
+
+/* memory checkers */
+#if !defined(__LZO_CHECKER)
+# if defined(__BOUNDS_CHECKING_ON)
+# define __LZO_CHECKER 1
+# elif defined(__CHECKER__)
+# define __LZO_CHECKER 1
+# elif defined(__INSURE__)
+# define __LZO_CHECKER 1
+# elif defined(__PURIFY__)
+# define __LZO_CHECKER 1
+# endif
+#endif
+
+
+/***********************************************************************
+// integral and pointer types
+************************************************************************/
+
+/* lzo_uint should match size_t */
+#if !defined(LZO_UINT_MAX)
+# if defined(LZO_ABI_LLP64) /* WIN64 */
+# if defined(LZO_OS_WIN64)
+ typedef unsigned __int64 lzo_uint;
+ typedef __int64 lzo_int;
+# else
+ typedef unsigned long long lzo_uint;
+ typedef long long lzo_int;
+# endif
+# define LZO_UINT_MAX 0xffffffffffffffffull
+# define LZO_INT_MAX 9223372036854775807LL
+# define LZO_INT_MIN (-1LL - LZO_INT_MAX)
+# elif defined(LZO_ABI_IP32L64) /* MIPS R5900 */
+ typedef unsigned int lzo_uint;
+ typedef int lzo_int;
+# define LZO_UINT_MAX UINT_MAX
+# define LZO_INT_MAX INT_MAX
+# define LZO_INT_MIN INT_MIN
+# elif (ULONG_MAX >= LZO_0xffffffffL)
+ typedef unsigned long lzo_uint;
+ typedef long lzo_int;
+# define LZO_UINT_MAX ULONG_MAX
+# define LZO_INT_MAX LONG_MAX
+# define LZO_INT_MIN LONG_MIN
+# else
+# error "lzo_uint"
+# endif
+#endif
+
+/* Integral types with 32 bits or more. */
+#if !defined(LZO_UINT32_MAX)
+# if (UINT_MAX >= LZO_0xffffffffL)
+ typedef unsigned int lzo_uint32;
+ typedef int lzo_int32;
+# define LZO_UINT32_MAX UINT_MAX
+# define LZO_INT32_MAX INT_MAX
+# define LZO_INT32_MIN INT_MIN
+# elif (ULONG_MAX >= LZO_0xffffffffL)
+ typedef unsigned long lzo_uint32;
+ typedef long lzo_int32;
+# define LZO_UINT32_MAX ULONG_MAX
+# define LZO_INT32_MAX LONG_MAX
+# define LZO_INT32_MIN LONG_MIN
+# else
+# error "lzo_uint32"
+# endif
+#endif
+
+/* The larger type of lzo_uint and lzo_uint32. */
+#if (LZO_UINT_MAX >= LZO_UINT32_MAX)
+# define lzo_xint lzo_uint
+#else
+# define lzo_xint lzo_uint32
+#endif
+
+/* Memory model that allows to access memory at offsets of lzo_uint. */
+#if !defined(__LZO_MMODEL)
+# if (LZO_UINT_MAX <= UINT_MAX)
+# define __LZO_MMODEL
+# elif defined(LZO_HAVE_MM_HUGE_PTR)
+# define __LZO_MMODEL_HUGE 1
+# define __LZO_MMODEL __huge
+# else
+# define __LZO_MMODEL
+# endif
+#endif
+
+/* no typedef here because of const-pointer issues */
+#define lzo_bytep unsigned char __LZO_MMODEL *
+#define lzo_charp char __LZO_MMODEL *
+#define lzo_voidp void __LZO_MMODEL *
+#define lzo_shortp short __LZO_MMODEL *
+#define lzo_ushortp unsigned short __LZO_MMODEL *
+#define lzo_uint32p lzo_uint32 __LZO_MMODEL *
+#define lzo_int32p lzo_int32 __LZO_MMODEL *
+#define lzo_uintp lzo_uint __LZO_MMODEL *
+#define lzo_intp lzo_int __LZO_MMODEL *
+#define lzo_xintp lzo_xint __LZO_MMODEL *
+#define lzo_voidpp lzo_voidp __LZO_MMODEL *
+#define lzo_bytepp lzo_bytep __LZO_MMODEL *
+/* deprecated - use `lzo_bytep' instead of `lzo_byte *' */
+#define lzo_byte unsigned char __LZO_MMODEL
+
+typedef int lzo_bool;
+
+
+/***********************************************************************
+// function types
+************************************************************************/
+
+/* name mangling */
+#if !defined(__LZO_EXTERN_C)
+# ifdef __cplusplus
+# define __LZO_EXTERN_C extern "C"
+# else
+# define __LZO_EXTERN_C extern
+# endif
+#endif
+
+/* calling convention */
+#if !defined(__LZO_CDECL)
+# define __LZO_CDECL __lzo_cdecl
+#endif
+
+/* DLL export information */
+#if !defined(__LZO_EXPORT1)
+# define __LZO_EXPORT1
+#endif
+#if !defined(__LZO_EXPORT2)
+# define __LZO_EXPORT2
+#endif
+
+/* __cdecl calling convention for public C and assembly functions */
+#if !defined(LZO_PUBLIC)
+# define LZO_PUBLIC(_rettype) __LZO_EXPORT1 _rettype __LZO_EXPORT2 __LZO_CDECL
+#endif
+#if !defined(LZO_EXTERN)
+# define LZO_EXTERN(_rettype) __LZO_EXTERN_C LZO_PUBLIC(_rettype)
+#endif
+#if !defined(LZO_PRIVATE)
+# define LZO_PRIVATE(_rettype) static _rettype __LZO_CDECL
+#endif
+
+/* function types */
+typedef int
+(__LZO_CDECL *lzo_compress_t) ( const lzo_bytep src, lzo_uint src_len,
+ lzo_bytep dst, lzo_uintp dst_len,
+ lzo_voidp wrkmem );
+
+typedef int
+(__LZO_CDECL *lzo_decompress_t) ( const lzo_bytep src, lzo_uint src_len,
+ lzo_bytep dst, lzo_uintp dst_len,
+ lzo_voidp wrkmem );
+
+typedef int
+(__LZO_CDECL *lzo_optimize_t) ( lzo_bytep src, lzo_uint src_len,
+ lzo_bytep dst, lzo_uintp dst_len,
+ lzo_voidp wrkmem );
+
+typedef int
+(__LZO_CDECL *lzo_compress_dict_t)(const lzo_bytep src, lzo_uint src_len,
+ lzo_bytep dst, lzo_uintp dst_len,
+ lzo_voidp wrkmem,
+ const lzo_bytep dict, lzo_uint dict_len );
+
+typedef int
+(__LZO_CDECL *lzo_decompress_dict_t)(const lzo_bytep src, lzo_uint src_len,
+ lzo_bytep dst, lzo_uintp dst_len,
+ lzo_voidp wrkmem,
+ const lzo_bytep dict, lzo_uint dict_len );
+
+
+/* Callback interface. Currently only the progress indicator ("nprogress")
+ * is used, but this may change in a future release. */
+
+struct lzo_callback_t;
+typedef struct lzo_callback_t lzo_callback_t;
+#define lzo_callback_p lzo_callback_t __LZO_MMODEL *
+
+/* malloc & free function types */
+typedef lzo_voidp (__LZO_CDECL *lzo_alloc_func_t)
+ (lzo_callback_p self, lzo_uint items, lzo_uint size);
+typedef void (__LZO_CDECL *lzo_free_func_t)
+ (lzo_callback_p self, lzo_voidp ptr);
+
+/* a progress indicator callback function */
+typedef void (__LZO_CDECL *lzo_progress_func_t)
+ (lzo_callback_p, lzo_uint, lzo_uint, int);
+
+struct lzo_callback_t
+{
+ /* custom allocators (set to 0 to disable) */
+ lzo_alloc_func_t nalloc; /* [not used right now] */
+ lzo_free_func_t nfree; /* [not used right now] */
+
+ /* a progress indicator callback function (set to 0 to disable) */
+ lzo_progress_func_t nprogress;
+
+ /* NOTE: the first parameter "self" of the nalloc/nfree/nprogress
+ * callbacks points back to this struct, so you are free to store
+ * some extra info in the following variables. */
+ lzo_voidp user1;
+ lzo_xint user2;
+ lzo_xint user3;
+};
+
+
+/***********************************************************************
+// error codes and prototypes
+************************************************************************/
+
+/* Error codes for the compression/decompression functions. Negative
+ * values are errors, positive values will be used for special but
+ * normal events.
+ */
+#define LZO_E_OK 0
+#define LZO_E_ERROR (-1)
+#define LZO_E_OUT_OF_MEMORY (-2) /* [not used right now] */
+#define LZO_E_NOT_COMPRESSIBLE (-3) /* [not used right now] */
+#define LZO_E_INPUT_OVERRUN (-4)
+#define LZO_E_OUTPUT_OVERRUN (-5)
+#define LZO_E_LOOKBEHIND_OVERRUN (-6)
+#define LZO_E_EOF_NOT_FOUND (-7)
+#define LZO_E_INPUT_NOT_CONSUMED (-8)
+#define LZO_E_NOT_YET_IMPLEMENTED (-9) /* [not used right now] */
+
+
+#ifndef lzo_sizeof_dict_t
+# define lzo_sizeof_dict_t ((unsigned)sizeof(lzo_bytep))
+#endif
+
+/* lzo_init() should be the first function you call.
+ * Check the return code !
+ *
+ * lzo_init() is a macro to allow checking that the library and the
+ * compiler's view of various types are consistent.
+ */
+#define lzo_init() __lzo_init_v2(LZO_VERSION,(int)sizeof(short),(int)sizeof(int),\
+ (int)sizeof(long),(int)sizeof(lzo_uint32),(int)sizeof(lzo_uint),\
+ (int)lzo_sizeof_dict_t,(int)sizeof(char *),(int)sizeof(lzo_voidp),\
+ (int)sizeof(lzo_callback_t))
+LZO_EXTERN(int) __lzo_init_v2(unsigned,int,int,int,int,int,int,int,int,int);
+
+/* version functions (useful for shared libraries) */
+LZO_EXTERN(unsigned) lzo_version(void);
+LZO_EXTERN(const char *) lzo_version_string(void);
+LZO_EXTERN(const char *) lzo_version_date(void);
+LZO_EXTERN(const lzo_charp) _lzo_version_string(void);
+LZO_EXTERN(const lzo_charp) _lzo_version_date(void);
+
+/* string functions */
+LZO_EXTERN(int)
+lzo_memcmp(const lzo_voidp _s1, const lzo_voidp _s2, lzo_uint _len);
+LZO_EXTERN(lzo_voidp)
+lzo_memcpy(lzo_voidp _dest, const lzo_voidp _src, lzo_uint _len);
+LZO_EXTERN(lzo_voidp)
+lzo_memmove(lzo_voidp _dest, const lzo_voidp _src, lzo_uint _len);
+LZO_EXTERN(lzo_voidp)
+lzo_memset(lzo_voidp _s, int _c, lzo_uint _len);
+
+/* checksum functions */
+LZO_EXTERN(lzo_uint32)
+lzo_adler32(lzo_uint32 _adler, const lzo_bytep _buf, lzo_uint _len);
+LZO_EXTERN(lzo_uint32)
+lzo_crc32(lzo_uint32 _c, const lzo_bytep _buf, lzo_uint _len);
+LZO_EXTERN(const lzo_uint32p)
+lzo_get_crc32_table(void);
+
+/* misc. */
+LZO_EXTERN(int) _lzo_config_check(void);
+typedef union { lzo_bytep p; lzo_uint u; } __lzo_pu_u;
+typedef union { lzo_bytep p; lzo_uint32 u32; } __lzo_pu32_u;
+typedef union { void *vp; lzo_bytep bp; lzo_uint32 u32; long l; } lzo_align_t;
+
+/* align a char pointer on a boundary that is a multiple of `size' */
+LZO_EXTERN(unsigned) __lzo_align_gap(const lzo_voidp _ptr, lzo_uint _size);
+#define LZO_PTR_ALIGN_UP(_ptr,_size) \
+ ((_ptr) + (lzo_uint) __lzo_align_gap((const lzo_voidp)(_ptr),(lzo_uint)(_size)))
+
+
+/***********************************************************************
+// deprecated macros - only for backward compatibility with LZO v1.xx
+************************************************************************/
+
+#if defined(LZO_CFG_COMPAT)
+
+#define __LZOCONF_H 1
+
+#if defined(LZO_ARCH_I086)
+# define __LZO_i386 1
+#elif defined(LZO_ARCH_I386)
+# define __LZO_i386 1
+#endif
+
+#if defined(LZO_OS_DOS16)
+# define __LZO_DOS 1
+# define __LZO_DOS16 1
+#elif defined(LZO_OS_DOS32)
+# define __LZO_DOS 1
+#elif defined(LZO_OS_WIN16)
+# define __LZO_WIN 1
+# define __LZO_WIN16 1
+#elif defined(LZO_OS_WIN32)
+# define __LZO_WIN 1
+#endif
+
+#define __LZO_CMODEL
+#define __LZO_DMODEL
+#define __LZO_ENTRY __LZO_CDECL
+#define LZO_EXTERN_CDECL LZO_EXTERN
+#define LZO_ALIGN LZO_PTR_ALIGN_UP
+
+#define lzo_compress_asm_t lzo_compress_t
+#define lzo_decompress_asm_t lzo_decompress_t
+
+#endif /* LZO_CFG_COMPAT */
+
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* already included */
+
+
+/* vim:set ts=4 et: */
diff --git a/lzodefs.h b/lzodefs.h
new file mode 100644
index 0000000..1805637
--- /dev/null
+++ b/lzodefs.h
@@ -0,0 +1,1807 @@
+/* lzodefs.h -- architecture, OS and compiler specific defines
+
+ This file is part of the LZO real-time data compression library.
+
+ Copyright (C) 2008 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2007 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2006 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2005 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2004 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2003 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2002 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2001 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2000 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 1997 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 1996 Markus Franz Xaver Johannes Oberhumer
+ All Rights Reserved.
+
+ The LZO library 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.
+
+ The LZO library 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 the LZO library; see the file COPYING.
+ If not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ Markus F.X.J. Oberhumer
+
+ http://www.oberhumer.com/opensource/lzo/
+ */
+
+
+#ifndef __LZODEFS_H_INCLUDED
+#define __LZODEFS_H_INCLUDED 1
+
+#if defined(__CYGWIN32__) && !defined(__CYGWIN__)
+# define __CYGWIN__ __CYGWIN32__
+#endif
+#if defined(__IBMCPP__) && !defined(__IBMC__)
+# define __IBMC__ __IBMCPP__
+#endif
+#if defined(__ICL) && defined(_WIN32) && !defined(__INTEL_COMPILER)
+# define __INTEL_COMPILER __ICL
+#endif
+#if 1 && defined(__INTERIX) && defined(__GNUC__) && !defined(_ALL_SOURCE)
+# define _ALL_SOURCE 1
+#endif
+#if defined(__mips__) && defined(__R5900__)
+# if !defined(__LONG_MAX__)
+# define __LONG_MAX__ 9223372036854775807L
+# endif
+#endif
+#if defined(__INTEL_COMPILER) && defined(__linux__)
+# pragma warning(disable: 193)
+#endif
+#if defined(__KEIL__) && defined(__C166__)
+# pragma warning disable = 322
+#elif 0 && defined(__C251__)
+# pragma warning disable = 322
+#endif
+#if defined(_MSC_VER) && !defined(__INTEL_COMPILER) && !defined(__MWERKS__)
+# if (_MSC_VER >= 1300)
+# pragma warning(disable: 4668)
+# endif
+#endif
+#if 0 && defined(__WATCOMC__)
+# if (__WATCOMC__ >= 1050) && (__WATCOMC__ < 1060)
+# pragma warning 203 9
+# endif
+#endif
+#if defined(__BORLANDC__) && defined(__MSDOS__) && !defined(__FLAT__)
+# pragma option -h
+#endif
+#if 0
+#define LZO_0xffffL 0xfffful
+#define LZO_0xffffffffL 0xfffffffful
+#else
+#define LZO_0xffffL 65535ul
+#define LZO_0xffffffffL 4294967295ul
+#endif
+#if (LZO_0xffffL == LZO_0xffffffffL)
+# error "your preprocessor is broken 1"
+#endif
+#if (16ul * 16384ul != 262144ul)
+# error "your preprocessor is broken 2"
+#endif
+#if 0
+#if (32767 >= 4294967295ul)
+# error "your preprocessor is broken 3"
+#endif
+#if (65535u >= 4294967295ul)
+# error "your preprocessor is broken 4"
+#endif
+#endif
+#if (UINT_MAX == LZO_0xffffL)
+#if defined(__ZTC__) && defined(__I86__) && !defined(__OS2__)
+# if !defined(MSDOS)
+# define MSDOS 1
+# endif
+# if !defined(_MSDOS)
+# define _MSDOS 1
+# endif
+#elif 0 && defined(__VERSION) && defined(MB_LEN_MAX)
+# if (__VERSION == 520) && (MB_LEN_MAX == 1)
+# if !defined(__AZTEC_C__)
+# define __AZTEC_C__ __VERSION
+# endif
+# if !defined(__DOS__)
+# define __DOS__ 1
+# endif
+# endif
+#endif
+#endif
+#if defined(_MSC_VER) && defined(M_I86HM) && (UINT_MAX == LZO_0xffffL)
+# define ptrdiff_t long
+# define _PTRDIFF_T_DEFINED
+#endif
+#if (UINT_MAX == LZO_0xffffL)
+# undef __LZO_RENAME_A
+# undef __LZO_RENAME_B
+# if defined(__AZTEC_C__) && defined(__DOS__)
+# define __LZO_RENAME_A 1
+# elif defined(_MSC_VER) && defined(MSDOS)
+# if (_MSC_VER < 600)
+# define __LZO_RENAME_A 1
+# elif (_MSC_VER < 700)
+# define __LZO_RENAME_B 1
+# endif
+# elif defined(__TSC__) && defined(__OS2__)
+# define __LZO_RENAME_A 1
+# elif defined(__MSDOS__) && defined(__TURBOC__) && (__TURBOC__ < 0x0410)
+# define __LZO_RENAME_A 1
+# elif defined(__PACIFIC__) && defined(DOS)
+# if !defined(__far)
+# define __far far
+# endif
+# if !defined(__near)
+# define __near near
+# endif
+# endif
+# if defined(__LZO_RENAME_A)
+# if !defined(__cdecl)
+# define __cdecl cdecl
+# endif
+# if !defined(__far)
+# define __far far
+# endif
+# if !defined(__huge)
+# define __huge huge
+# endif
+# if !defined(__near)
+# define __near near
+# endif
+# if !defined(__pascal)
+# define __pascal pascal
+# endif
+# if !defined(__huge)
+# define __huge huge
+# endif
+# elif defined(__LZO_RENAME_B)
+# if !defined(__cdecl)
+# define __cdecl _cdecl
+# endif
+# if !defined(__far)
+# define __far _far
+# endif
+# if !defined(__huge)
+# define __huge _huge
+# endif
+# if !defined(__near)
+# define __near _near
+# endif
+# if !defined(__pascal)
+# define __pascal _pascal
+# endif
+# elif (defined(__PUREC__) || defined(__TURBOC__)) && defined(__TOS__)
+# if !defined(__cdecl)
+# define __cdecl cdecl
+# endif
+# if !defined(__pascal)
+# define __pascal pascal
+# endif
+# endif
+# undef __LZO_RENAME_A
+# undef __LZO_RENAME_B
+#endif
+#if (UINT_MAX == LZO_0xffffL)
+#if defined(__AZTEC_C__) && defined(__DOS__)
+# define LZO_BROKEN_CDECL_ALT_SYNTAX 1
+#elif defined(_MSC_VER) && defined(MSDOS)
+# if (_MSC_VER < 600)
+# define LZO_BROKEN_INTEGRAL_CONSTANTS 1
+# endif
+# if (_MSC_VER < 700)
+# define LZO_BROKEN_INTEGRAL_PROMOTION 1
+# define LZO_BROKEN_SIZEOF 1
+# endif
+#elif defined(__PACIFIC__) && defined(DOS)
+# define LZO_BROKEN_INTEGRAL_CONSTANTS 1
+#elif defined(__TURBOC__) && defined(__MSDOS__)
+# if (__TURBOC__ < 0x0150)
+# define LZO_BROKEN_CDECL_ALT_SYNTAX 1
+# define LZO_BROKEN_INTEGRAL_CONSTANTS 1
+# define LZO_BROKEN_INTEGRAL_PROMOTION 1
+# endif
+# if (__TURBOC__ < 0x0200)
+# define LZO_BROKEN_SIZEOF 1
+# endif
+# if (__TURBOC__ < 0x0400) && defined(__cplusplus)
+# define LZO_BROKEN_CDECL_ALT_SYNTAX 1
+# endif
+#elif (defined(__PUREC__) || defined(__TURBOC__)) && defined(__TOS__)
+# define LZO_BROKEN_CDECL_ALT_SYNTAX 1
+# define LZO_BROKEN_SIZEOF 1
+#endif
+#endif
+#if defined(__WATCOMC__) && (__WATCOMC__ < 900)
+# define LZO_BROKEN_INTEGRAL_CONSTANTS 1
+#endif
+#if defined(_CRAY) && defined(_CRAY1)
+# define LZO_BROKEN_SIGNED_RIGHT_SHIFT 1
+#endif
+#define LZO_PP_STRINGIZE(x) #x
+#define LZO_PP_MACRO_EXPAND(x) LZO_PP_STRINGIZE(x)
+#define LZO_PP_CONCAT2(a,b) a ## b
+#define LZO_PP_CONCAT3(a,b,c) a ## b ## c
+#define LZO_PP_CONCAT4(a,b,c,d) a ## b ## c ## d
+#define LZO_PP_CONCAT5(a,b,c,d,e) a ## b ## c ## d ## e
+#define LZO_PP_ECONCAT2(a,b) LZO_PP_CONCAT2(a,b)
+#define LZO_PP_ECONCAT3(a,b,c) LZO_PP_CONCAT3(a,b,c)
+#define LZO_PP_ECONCAT4(a,b,c,d) LZO_PP_CONCAT4(a,b,c,d)
+#define LZO_PP_ECONCAT5(a,b,c,d,e) LZO_PP_CONCAT5(a,b,c,d,e)
+#if 1
+#define LZO_CPP_STRINGIZE(x) #x
+#define LZO_CPP_MACRO_EXPAND(x) LZO_CPP_STRINGIZE(x)
+#define LZO_CPP_CONCAT2(a,b) a ## b
+#define LZO_CPP_CONCAT3(a,b,c) a ## b ## c
+#define LZO_CPP_CONCAT4(a,b,c,d) a ## b ## c ## d
+#define LZO_CPP_CONCAT5(a,b,c,d,e) a ## b ## c ## d ## e
+#define LZO_CPP_ECONCAT2(a,b) LZO_CPP_CONCAT2(a,b)
+#define LZO_CPP_ECONCAT3(a,b,c) LZO_CPP_CONCAT3(a,b,c)
+#define LZO_CPP_ECONCAT4(a,b,c,d) LZO_CPP_CONCAT4(a,b,c,d)
+#define LZO_CPP_ECONCAT5(a,b,c,d,e) LZO_CPP_CONCAT5(a,b,c,d,e)
+#endif
+#define __LZO_MASK_GEN(o,b) (((((o) << ((b)-1)) - (o)) << 1) + (o))
+#if 1 && defined(__cplusplus)
+# if !defined(__STDC_CONSTANT_MACROS)
+# define __STDC_CONSTANT_MACROS 1
+# endif
+# if !defined(__STDC_LIMIT_MACROS)
+# define __STDC_LIMIT_MACROS 1
+# endif
+#endif
+#if defined(__cplusplus)
+# define LZO_EXTERN_C extern "C"
+#else
+# define LZO_EXTERN_C extern
+#endif
+#if !defined(__LZO_OS_OVERRIDE)
+#if defined(LZO_OS_FREESTANDING)
+# define LZO_INFO_OS "freestanding"
+#elif defined(LZO_OS_EMBEDDED)
+# define LZO_INFO_OS "embedded"
+#elif 1 && defined(__IAR_SYSTEMS_ICC__)
+# define LZO_OS_EMBEDDED 1
+# define LZO_INFO_OS "embedded"
+#elif defined(__CYGWIN__) && defined(__GNUC__)
+# define LZO_OS_CYGWIN 1
+# define LZO_INFO_OS "cygwin"
+#elif defined(__EMX__) && defined(__GNUC__)
+# define LZO_OS_EMX 1
+# define LZO_INFO_OS "emx"
+#elif defined(__BEOS__)
+# define LZO_OS_BEOS 1
+# define LZO_INFO_OS "beos"
+#elif defined(__Lynx__)
+# define LZO_OS_LYNXOS 1
+# define LZO_INFO_OS "lynxos"
+#elif defined(__OS400__)
+# define LZO_OS_OS400 1
+# define LZO_INFO_OS "os400"
+#elif defined(__QNX__)
+# define LZO_OS_QNX 1
+# define LZO_INFO_OS "qnx"
+#elif defined(__BORLANDC__) && defined(__DPMI32__) && (__BORLANDC__ >= 0x0460)
+# define LZO_OS_DOS32 1
+# define LZO_INFO_OS "dos32"
+#elif defined(__BORLANDC__) && defined(__DPMI16__)
+# define LZO_OS_DOS16 1
+# define LZO_INFO_OS "dos16"
+#elif defined(__ZTC__) && defined(DOS386)
+# define LZO_OS_DOS32 1
+# define LZO_INFO_OS "dos32"
+#elif defined(__OS2__) || defined(__OS2V2__)
+# if (UINT_MAX == LZO_0xffffL)
+# define LZO_OS_OS216 1
+# define LZO_INFO_OS "os216"
+# elif (UINT_MAX == LZO_0xffffffffL)
+# define LZO_OS_OS2 1
+# define LZO_INFO_OS "os2"
+# else
+# error "check your limits.h header"
+# endif
+#elif defined(__WIN64__) || defined(_WIN64) || defined(WIN64)
+# define LZO_OS_WIN64 1
+# define LZO_INFO_OS "win64"
+#elif defined(__WIN32__) || defined(_WIN32) || defined(WIN32) || defined(__WINDOWS_386__)
+# define LZO_OS_WIN32 1
+# define LZO_INFO_OS "win32"
+#elif defined(__MWERKS__) && defined(__INTEL__)
+# define LZO_OS_WIN32 1
+# define LZO_INFO_OS "win32"
+#elif defined(__WINDOWS__) || defined(_WINDOWS) || defined(_Windows)
+# if (UINT_MAX == LZO_0xffffL)
+# define LZO_OS_WIN16 1
+# define LZO_INFO_OS "win16"
+# elif (UINT_MAX == LZO_0xffffffffL)
+# define LZO_OS_WIN32 1
+# define LZO_INFO_OS "win32"
+# else
+# error "check your limits.h header"
+# endif
+#elif defined(__DOS__) || defined(__MSDOS__) || defined(_MSDOS) || defined(MSDOS) || (defined(__PACIFIC__) && defined(DOS))
+# if (UINT_MAX == LZO_0xffffL)
+# define LZO_OS_DOS16 1
+# define LZO_INFO_OS "dos16"
+# elif (UINT_MAX == LZO_0xffffffffL)
+# define LZO_OS_DOS32 1
+# define LZO_INFO_OS "dos32"
+# else
+# error "check your limits.h header"
+# endif
+#elif defined(__WATCOMC__)
+# if defined(__NT__) && (UINT_MAX == LZO_0xffffL)
+# define LZO_OS_DOS16 1
+# define LZO_INFO_OS "dos16"
+# elif defined(__NT__) && (__WATCOMC__ < 1100)
+# define LZO_OS_WIN32 1
+# define LZO_INFO_OS "win32"
+# elif defined(__linux__) || defined(__LINUX__)
+# define LZO_OS_POSIX 1
+# define LZO_INFO_OS "posix"
+# else
+# error "please specify a target using the -bt compiler option"
+# endif
+#elif defined(__palmos__)
+# define LZO_OS_PALMOS 1
+# define LZO_INFO_OS "palmos"
+#elif defined(__TOS__) || defined(__atarist__)
+# define LZO_OS_TOS 1
+# define LZO_INFO_OS "tos"
+#elif defined(macintosh) && !defined(__ppc__)
+# define LZO_OS_MACCLASSIC 1
+# define LZO_INFO_OS "macclassic"
+#elif defined(__VMS)
+# define LZO_OS_VMS 1
+# define LZO_INFO_OS "vms"
+#elif ((defined(__mips__) && defined(__R5900__)) || defined(__MIPS_PSX2__))
+# define LZO_OS_CONSOLE 1
+# define LZO_OS_CONSOLE_PS2 1
+# define LZO_INFO_OS "console"
+# define LZO_INFO_OS_CONSOLE "ps2"
+#elif (defined(__mips__) && defined(__psp__))
+# define LZO_OS_CONSOLE 1
+# define LZO_OS_CONSOLE_PSP 1
+# define LZO_INFO_OS "console"
+# define LZO_INFO_OS_CONSOLE "psp"
+#else
+# define LZO_OS_POSIX 1
+# define LZO_INFO_OS "posix"
+#endif
+#if (LZO_OS_POSIX)
+# if defined(_AIX) || defined(__AIX__) || defined(__aix__)
+# define LZO_OS_POSIX_AIX 1
+# define LZO_INFO_OS_POSIX "aix"
+# elif defined(__FreeBSD__)
+# define LZO_OS_POSIX_FREEBSD 1
+# define LZO_INFO_OS_POSIX "freebsd"
+# elif defined(__hpux__) || defined(__hpux)
+# define LZO_OS_POSIX_HPUX 1
+# define LZO_INFO_OS_POSIX "hpux"
+# elif defined(__INTERIX)
+# define LZO_OS_POSIX_INTERIX 1
+# define LZO_INFO_OS_POSIX "interix"
+# elif defined(__IRIX__) || defined(__irix__)
+# define LZO_OS_POSIX_IRIX 1
+# define LZO_INFO_OS_POSIX "irix"
+# elif defined(__linux__) || defined(__linux) || defined(__LINUX__)
+# define LZO_OS_POSIX_LINUX 1
+# define LZO_INFO_OS_POSIX "linux"
+# elif defined(__APPLE__) || defined(__MACOS__)
+# define LZO_OS_POSIX_MACOSX 1
+# define LZO_INFO_OS_POSIX "macosx"
+# elif defined(__minix__) || defined(__minix)
+# define LZO_OS_POSIX_MINIX 1
+# define LZO_INFO_OS_POSIX "minix"
+# elif defined(__NetBSD__)
+# define LZO_OS_POSIX_NETBSD 1
+# define LZO_INFO_OS_POSIX "netbsd"
+# elif defined(__OpenBSD__)
+# define LZO_OS_POSIX_OPENBSD 1
+# define LZO_INFO_OS_POSIX "openbsd"
+# elif defined(__osf__)
+# define LZO_OS_POSIX_OSF 1
+# define LZO_INFO_OS_POSIX "osf"
+# elif defined(__solaris__) || defined(__sun)
+# if defined(__SVR4) || defined(__svr4__)
+# define LZO_OS_POSIX_SOLARIS 1
+# define LZO_INFO_OS_POSIX "solaris"
+# else
+# define LZO_OS_POSIX_SUNOS 1
+# define LZO_INFO_OS_POSIX "sunos"
+# endif
+# elif defined(__ultrix__) || defined(__ultrix)
+# define LZO_OS_POSIX_ULTRIX 1
+# define LZO_INFO_OS_POSIX "ultrix"
+# elif defined(_UNICOS)
+# define LZO_OS_POSIX_UNICOS 1
+# define LZO_INFO_OS_POSIX "unicos"
+# else
+# define LZO_OS_POSIX_UNKNOWN 1
+# define LZO_INFO_OS_POSIX "unknown"
+# endif
+#endif
+#endif
+#if (LZO_OS_DOS16 || LZO_OS_OS216 || LZO_OS_WIN16)
+# if (UINT_MAX != LZO_0xffffL)
+# error "this should not happen"
+# endif
+# if (ULONG_MAX != LZO_0xffffffffL)
+# error "this should not happen"
+# endif
+#endif
+#if (LZO_OS_DOS32 || LZO_OS_OS2 || LZO_OS_WIN32 || LZO_OS_WIN64)
+# if (UINT_MAX != LZO_0xffffffffL)
+# error "this should not happen"
+# endif
+# if (ULONG_MAX != LZO_0xffffffffL)
+# error "this should not happen"
+# endif
+#endif
+#if defined(CIL) && defined(_GNUCC) && defined(__GNUC__)
+# define LZO_CC_CILLY 1
+# define LZO_INFO_CC "Cilly"
+# if defined(__CILLY__)
+# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__CILLY__)
+# else
+# define LZO_INFO_CCVER "unknown"
+# endif
+#elif 0 && defined(SDCC) && defined(__VERSION__) && !defined(__GNUC__)
+# define LZO_CC_SDCC 1
+# define LZO_INFO_CC "sdcc"
+# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(SDCC)
+#elif defined(__PATHSCALE__) && defined(__PATHCC_PATCHLEVEL__)
+# define LZO_CC_PATHSCALE (__PATHCC__ * 0x10000L + __PATHCC_MINOR__ * 0x100 + __PATHCC_PATCHLEVEL__)
+# define LZO_INFO_CC "Pathscale C"
+# define LZO_INFO_CCVER __PATHSCALE__
+#elif defined(__INTEL_COMPILER)
+# define LZO_CC_INTELC 1
+# define LZO_INFO_CC "Intel C"
+# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__INTEL_COMPILER)
+# if defined(_WIN32) || defined(_WIN64)
+# define LZO_CC_SYNTAX_MSC 1
+# else
+# define LZO_CC_SYNTAX_GNUC 1
+# endif
+#elif defined(__POCC__) && defined(_WIN32)
+# define LZO_CC_PELLESC 1
+# define LZO_INFO_CC "Pelles C"
+# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__POCC__)
+#elif defined(__llvm__) && defined(__GNUC__) && defined(__VERSION__)
+# if defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__)
+# define LZO_CC_LLVM (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100 + __GNUC_PATCHLEVEL__)
+# else
+# define LZO_CC_LLVM (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100)
+# endif
+# define LZO_INFO_CC "llvm-gcc"
+# define LZO_INFO_CCVER __VERSION__
+#elif defined(__GNUC__) && defined(__VERSION__)
+# if defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__)
+# define LZO_CC_GNUC (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100 + __GNUC_PATCHLEVEL__)
+# elif defined(__GNUC_MINOR__)
+# define LZO_CC_GNUC (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100)
+# else
+# define LZO_CC_GNUC (__GNUC__ * 0x10000L)
+# endif
+# define LZO_INFO_CC "gcc"
+# define LZO_INFO_CCVER __VERSION__
+#elif defined(__ACK__) && defined(_ACK)
+# define LZO_CC_ACK 1
+# define LZO_INFO_CC "Amsterdam Compiler Kit C"
+# define LZO_INFO_CCVER "unknown"
+#elif defined(__AZTEC_C__)
+# define LZO_CC_AZTECC 1
+# define LZO_INFO_CC "Aztec C"
+# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__AZTEC_C__)
+#elif defined(__BORLANDC__)
+# define LZO_CC_BORLANDC 1
+# define LZO_INFO_CC "Borland C"
+# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__BORLANDC__)
+#elif defined(_CRAYC) && defined(_RELEASE)
+# define LZO_CC_CRAYC 1
+# define LZO_INFO_CC "Cray C"
+# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(_RELEASE)
+#elif defined(__DMC__) && defined(__SC__)
+# define LZO_CC_DMC 1
+# define LZO_INFO_CC "Digital Mars C"
+# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__DMC__)
+#elif defined(__DECC)
+# define LZO_CC_DECC 1
+# define LZO_INFO_CC "DEC C"
+# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__DECC)
+#elif defined(__HIGHC__)
+# define LZO_CC_HIGHC 1
+# define LZO_INFO_CC "MetaWare High C"
+# define LZO_INFO_CCVER "unknown"
+#elif defined(__IAR_SYSTEMS_ICC__)
+# define LZO_CC_IARC 1
+# define LZO_INFO_CC "IAR C"
+# if defined(__VER__)
+# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__VER__)
+# else
+# define LZO_INFO_CCVER "unknown"
+# endif
+#elif defined(__IBMC__)
+# define LZO_CC_IBMC 1
+# define LZO_INFO_CC "IBM C"
+# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__IBMC__)
+#elif defined(__KEIL__) && defined(__C166__)
+# define LZO_CC_KEILC 1
+# define LZO_INFO_CC "Keil C"
+# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__C166__)
+#elif defined(__LCC__) && defined(_WIN32) && defined(__LCCOPTIMLEVEL)
+# define LZO_CC_LCCWIN32 1
+# define LZO_INFO_CC "lcc-win32"
+# define LZO_INFO_CCVER "unknown"
+#elif defined(__LCC__)
+# define LZO_CC_LCC 1
+# define LZO_INFO_CC "lcc"
+# if defined(__LCC_VERSION__)
+# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__LCC_VERSION__)
+# else
+# define LZO_INFO_CCVER "unknown"
+# endif
+#elif defined(_MSC_VER)
+# define LZO_CC_MSC 1
+# define LZO_INFO_CC "Microsoft C"
+# if defined(_MSC_FULL_VER)
+# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(_MSC_VER) "." LZO_PP_MACRO_EXPAND(_MSC_FULL_VER)
+# else
+# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(_MSC_VER)
+# endif
+#elif defined(__MWERKS__)
+# define LZO_CC_MWERKS 1
+# define LZO_INFO_CC "Metrowerks C"
+# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__MWERKS__)
+#elif (defined(__NDPC__) || defined(__NDPX__)) && defined(__i386)
+# define LZO_CC_NDPC 1
+# define LZO_INFO_CC "Microway NDP C"
+# define LZO_INFO_CCVER "unknown"
+#elif defined(__PACIFIC__)
+# define LZO_CC_PACIFICC 1
+# define LZO_INFO_CC "Pacific C"
+# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__PACIFIC__)
+#elif defined(__PGI) && (defined(__linux__) || defined(__WIN32__))
+# define LZO_CC_PGI 1
+# define LZO_INFO_CC "Portland Group PGI C"
+# define LZO_INFO_CCVER "unknown"
+#elif defined(__PUREC__) && defined(__TOS__)
+# define LZO_CC_PUREC 1
+# define LZO_INFO_CC "Pure C"
+# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__PUREC__)
+#elif defined(__SC__) && defined(__ZTC__)
+# define LZO_CC_SYMANTECC 1
+# define LZO_INFO_CC "Symantec C"
+# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__SC__)
+#elif defined(__SUNPRO_C)
+# define LZO_INFO_CC "SunPro C"
+# if ((__SUNPRO_C)+0 > 0)
+# define LZO_CC_SUNPROC __SUNPRO_C
+# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__SUNPRO_C)
+# else
+# define LZO_CC_SUNPROC 1
+# define LZO_INFO_CCVER "unknown"
+# endif
+#elif defined(__SUNPRO_CC)
+# define LZO_INFO_CC "SunPro C"
+# if ((__SUNPRO_CC)+0 > 0)
+# define LZO_CC_SUNPROC __SUNPRO_CC
+# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__SUNPRO_CC)
+# else
+# define LZO_CC_SUNPROC 1
+# define LZO_INFO_CCVER "unknown"
+# endif
+#elif defined(__TINYC__)
+# define LZO_CC_TINYC 1
+# define LZO_INFO_CC "Tiny C"
+# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__TINYC__)
+#elif defined(__TSC__)
+# define LZO_CC_TOPSPEEDC 1
+# define LZO_INFO_CC "TopSpeed C"
+# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__TSC__)
+#elif defined(__WATCOMC__)
+# define LZO_CC_WATCOMC 1
+# define LZO_INFO_CC "Watcom C"
+# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__WATCOMC__)
+#elif defined(__TURBOC__)
+# define LZO_CC_TURBOC 1
+# define LZO_INFO_CC "Turbo C"
+# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__TURBOC__)
+#elif defined(__ZTC__)
+# define LZO_CC_ZORTECHC 1
+# define LZO_INFO_CC "Zortech C"
+# if (__ZTC__ == 0x310)
+# define LZO_INFO_CCVER "0x310"
+# else
+# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__ZTC__)
+# endif
+#else
+# define LZO_CC_UNKNOWN 1
+# define LZO_INFO_CC "unknown"
+# define LZO_INFO_CCVER "unknown"
+#endif
+#if 0 && (LZO_CC_MSC && (_MSC_VER >= 1200)) && !defined(_MSC_FULL_VER)
+# error "LZO_CC_MSC: _MSC_FULL_VER is not defined"
+#endif
+#if !defined(__LZO_ARCH_OVERRIDE) && !defined(LZO_ARCH_GENERIC) && defined(_CRAY)
+# if (UINT_MAX > LZO_0xffffffffL) && defined(_CRAY)
+# if defined(_CRAYMPP) || defined(_CRAYT3D) || defined(_CRAYT3E)
+# define LZO_ARCH_CRAY_MPP 1
+# elif defined(_CRAY1)
+# define LZO_ARCH_CRAY_PVP 1
+# endif
+# endif
+#endif
+#if !defined(__LZO_ARCH_OVERRIDE)
+#if defined(LZO_ARCH_GENERIC)
+# define LZO_INFO_ARCH "generic"
+#elif (LZO_OS_DOS16 || LZO_OS_OS216 || LZO_OS_WIN16)
+# define LZO_ARCH_I086 1
+# define LZO_ARCH_IA16 1
+# define LZO_INFO_ARCH "i086"
+#elif defined(__alpha__) || defined(__alpha) || defined(_M_ALPHA)
+# define LZO_ARCH_ALPHA 1
+# define LZO_INFO_ARCH "alpha"
+#elif (LZO_ARCH_CRAY_MPP) && (defined(_CRAYT3D) || defined(_CRAYT3E))
+# define LZO_ARCH_ALPHA 1
+# define LZO_INFO_ARCH "alpha"
+#elif defined(__amd64__) || defined(__x86_64__) || defined(_M_AMD64)
+# define LZO_ARCH_AMD64 1
+# define LZO_INFO_ARCH "amd64"
+#elif defined(__thumb__) || (defined(_M_ARM) && defined(_M_THUMB))
+# define LZO_ARCH_ARM 1
+# define LZO_ARCH_ARM_THUMB 1
+# define LZO_INFO_ARCH "arm_thumb"
+#elif defined(__IAR_SYSTEMS_ICC__) && defined(__ICCARM__)
+# define LZO_ARCH_ARM 1
+# if defined(__CPU_MODE__) && ((__CPU_MODE__)+0 == 1)
+# define LZO_ARCH_ARM_THUMB 1
+# define LZO_INFO_ARCH "arm_thumb"
+# elif defined(__CPU_MODE__) && ((__CPU_MODE__)+0 == 2)
+# define LZO_INFO_ARCH "arm"
+# else
+# define LZO_INFO_ARCH "arm"
+# endif
+#elif defined(__arm__) || defined(_M_ARM)
+# define LZO_ARCH_ARM 1
+# define LZO_INFO_ARCH "arm"
+#elif (UINT_MAX <= LZO_0xffffL) && defined(__AVR__)
+# define LZO_ARCH_AVR 1
+# define LZO_INFO_ARCH "avr"
+#elif defined(__bfin__)
+# define LZO_ARCH_BLACKFIN 1
+# define LZO_INFO_ARCH "blackfin"
+#elif (UINT_MAX == LZO_0xffffL) && defined(__C166__)
+# define LZO_ARCH_C166 1
+# define LZO_INFO_ARCH "c166"
+#elif defined(__cris__)
+# define LZO_ARCH_CRIS 1
+# define LZO_INFO_ARCH "cris"
+#elif defined(__IAR_SYSTEMS_ICC__) && defined(__ICCEZ80__)
+# define LZO_ARCH_EZ80 1
+# define LZO_INFO_ARCH "ez80"
+#elif defined(__H8300__) || defined(__H8300H__) || defined(__H8300S__) || defined(__H8300SX__)
+# define LZO_ARCH_H8300 1
+# define LZO_INFO_ARCH "h8300"
+#elif defined(__hppa__) || defined(__hppa)
+# define LZO_ARCH_HPPA 1
+# define LZO_INFO_ARCH "hppa"
+#elif defined(__386__) || defined(__i386__) || defined(__i386) || defined(_M_IX86) || defined(_M_I386)
+# define LZO_ARCH_I386 1
+# define LZO_ARCH_IA32 1
+# define LZO_INFO_ARCH "i386"
+#elif (LZO_CC_ZORTECHC && defined(__I86__))
+# define LZO_ARCH_I386 1
+# define LZO_ARCH_IA32 1
+# define LZO_INFO_ARCH "i386"
+#elif (LZO_OS_DOS32 && LZO_CC_HIGHC) && defined(_I386)
+# define LZO_ARCH_I386 1
+# define LZO_ARCH_IA32 1
+# define LZO_INFO_ARCH "i386"
+#elif defined(__ia64__) || defined(__ia64) || defined(_M_IA64)
+# define LZO_ARCH_IA64 1
+# define LZO_INFO_ARCH "ia64"
+#elif (UINT_MAX == LZO_0xffffL) && defined(__m32c__)
+# define LZO_ARCH_M16C 1
+# define LZO_INFO_ARCH "m16c"
+#elif defined(__IAR_SYSTEMS_ICC__) && defined(__ICCM16C__)
+# define LZO_ARCH_M16C 1
+# define LZO_INFO_ARCH "m16c"
+#elif defined(__m32r__)
+# define LZO_ARCH_M32R 1
+# define LZO_INFO_ARCH "m32r"
+#elif (LZO_OS_TOS) || defined(__m68k__) || defined(__m68000__) || defined(__mc68000__) || defined(__mc68020__) || defined(_M_M68K)
+# define LZO_ARCH_M68K 1
+# define LZO_INFO_ARCH "m68k"
+#elif (UINT_MAX == LZO_0xffffL) && defined(__C251__)
+# define LZO_ARCH_MCS251 1
+# define LZO_INFO_ARCH "mcs251"
+#elif (UINT_MAX == LZO_0xffffL) && defined(__C51__)
+# define LZO_ARCH_MCS51 1
+# define LZO_INFO_ARCH "mcs51"
+#elif defined(__IAR_SYSTEMS_ICC__) && defined(__ICC8051__)
+# define LZO_ARCH_MCS51 1
+# define LZO_INFO_ARCH "mcs51"
+#elif defined(__mips__) || defined(__mips) || defined(_MIPS_ARCH) || defined(_M_MRX000)
+# define LZO_ARCH_MIPS 1
+# define LZO_INFO_ARCH "mips"
+#elif (UINT_MAX == LZO_0xffffL) && defined(__MSP430__)
+# define LZO_ARCH_MSP430 1
+# define LZO_INFO_ARCH "msp430"
+#elif defined(__IAR_SYSTEMS_ICC__) && defined(__ICC430__)
+# define LZO_ARCH_MSP430 1
+# define LZO_INFO_ARCH "msp430"
+#elif defined(__powerpc__) || defined(__powerpc) || defined(__ppc__) || defined(__PPC__) || defined(_M_PPC) || defined(_ARCH_PPC) || defined(_ARCH_PWR)
+# define LZO_ARCH_POWERPC 1
+# define LZO_INFO_ARCH "powerpc"
+#elif defined(__s390__) || defined(__s390) || defined(__s390x__) || defined(__s390x)
+# define LZO_ARCH_S390 1
+# define LZO_INFO_ARCH "s390"
+#elif defined(__sh__) || defined(_M_SH)
+# define LZO_ARCH_SH 1
+# define LZO_INFO_ARCH "sh"
+#elif defined(__sparc__) || defined(__sparc) || defined(__sparcv8)
+# define LZO_ARCH_SPARC 1
+# define LZO_INFO_ARCH "sparc"
+#elif defined(__SPU__)
+# define LZO_ARCH_SPU 1
+# define LZO_INFO_ARCH "spu"
+#elif (UINT_MAX == LZO_0xffffL) && defined(__z80)
+# define LZO_ARCH_Z80 1
+# define LZO_INFO_ARCH "z80"
+#elif (LZO_ARCH_CRAY_PVP)
+# if defined(_CRAYSV1)
+# define LZO_ARCH_CRAY_SV1 1
+# define LZO_INFO_ARCH "cray_sv1"
+# elif (_ADDR64)
+# define LZO_ARCH_CRAY_T90 1
+# define LZO_INFO_ARCH "cray_t90"
+# elif (_ADDR32)
+# define LZO_ARCH_CRAY_YMP 1
+# define LZO_INFO_ARCH "cray_ymp"
+# else
+# define LZO_ARCH_CRAY_XMP 1
+# define LZO_INFO_ARCH "cray_xmp"
+# endif
+#else
+# define LZO_ARCH_UNKNOWN 1
+# define LZO_INFO_ARCH "unknown"
+#endif
+#endif
+#if 1 && (LZO_ARCH_UNKNOWN) && (LZO_OS_DOS32 || LZO_OS_OS2)
+# error "FIXME - missing define for CPU architecture"
+#endif
+#if 1 && (LZO_ARCH_UNKNOWN) && (LZO_OS_WIN32)
+# error "FIXME - missing WIN32 define for CPU architecture"
+#endif
+#if 1 && (LZO_ARCH_UNKNOWN) && (LZO_OS_WIN64)
+# error "FIXME - missing WIN64 define for CPU architecture"
+#endif
+#if (LZO_OS_OS216 || LZO_OS_WIN16)
+# define LZO_ARCH_I086PM 1
+# define LZO_ARCH_IA16PM 1
+#elif 1 && (LZO_OS_DOS16 && defined(BLX286))
+# define LZO_ARCH_I086PM 1
+# define LZO_ARCH_IA16PM 1
+#elif 1 && (LZO_OS_DOS16 && defined(DOSX286))
+# define LZO_ARCH_I086PM 1
+# define LZO_ARCH_IA16PM 1
+#elif 1 && (LZO_OS_DOS16 && LZO_CC_BORLANDC && defined(__DPMI16__))
+# define LZO_ARCH_I086PM 1
+# define LZO_ARCH_IA16PM 1
+#endif
+#if defined(LZO_ARCH_ARM_THUMB) && !defined(LZO_ARCH_ARM)
+# error "this should not happen"
+#endif
+#if defined(LZO_ARCH_I086PM) && !defined(LZO_ARCH_I086)
+# error "this should not happen"
+#endif
+#if (LZO_ARCH_I086)
+# if (UINT_MAX != LZO_0xffffL)
+# error "this should not happen"
+# endif
+# if (ULONG_MAX != LZO_0xffffffffL)
+# error "this should not happen"
+# endif
+#endif
+#if (LZO_ARCH_I386)
+# if (UINT_MAX != LZO_0xffffL) && defined(__i386_int16__)
+# error "this should not happen"
+# endif
+# if (UINT_MAX != LZO_0xffffffffL) && !defined(__i386_int16__)
+# error "this should not happen"
+# endif
+# if (ULONG_MAX != LZO_0xffffffffL)
+# error "this should not happen"
+# endif
+#endif
+#if !defined(__LZO_MM_OVERRIDE)
+#if (LZO_ARCH_I086)
+#if (UINT_MAX != LZO_0xffffL)
+# error "this should not happen"
+#endif
+#if defined(__TINY__) || defined(M_I86TM) || defined(_M_I86TM)
+# define LZO_MM_TINY 1
+#elif defined(__HUGE__) || defined(_HUGE_) || defined(M_I86HM) || defined(_M_I86HM)
+# define LZO_MM_HUGE 1
+#elif defined(__SMALL__) || defined(M_I86SM) || defined(_M_I86SM) || defined(SMALL_MODEL)
+# define LZO_MM_SMALL 1
+#elif defined(__MEDIUM__) || defined(M_I86MM) || defined(_M_I86MM)
+# define LZO_MM_MEDIUM 1
+#elif defined(__COMPACT__) || defined(M_I86CM) || defined(_M_I86CM)
+# define LZO_MM_COMPACT 1
+#elif defined(__LARGE__) || defined(M_I86LM) || defined(_M_I86LM) || defined(LARGE_MODEL)
+# define LZO_MM_LARGE 1
+#elif (LZO_CC_AZTECC)
+# if defined(_LARGE_CODE) && defined(_LARGE_DATA)
+# define LZO_MM_LARGE 1
+# elif defined(_LARGE_CODE)
+# define LZO_MM_MEDIUM 1
+# elif defined(_LARGE_DATA)
+# define LZO_MM_COMPACT 1
+# else
+# define LZO_MM_SMALL 1
+# endif
+#elif (LZO_CC_ZORTECHC && defined(__VCM__))
+# define LZO_MM_LARGE 1
+#else
+# error "unknown memory model"
+#endif
+#if (LZO_OS_DOS16 || LZO_OS_OS216 || LZO_OS_WIN16)
+#define LZO_HAVE_MM_HUGE_PTR 1
+#define LZO_HAVE_MM_HUGE_ARRAY 1
+#if (LZO_MM_TINY)
+# undef LZO_HAVE_MM_HUGE_ARRAY
+#endif
+#if (LZO_CC_AZTECC || LZO_CC_PACIFICC || LZO_CC_ZORTECHC)
+# undef LZO_HAVE_MM_HUGE_PTR
+# undef LZO_HAVE_MM_HUGE_ARRAY
+#elif (LZO_CC_DMC || LZO_CC_SYMANTECC)
+# undef LZO_HAVE_MM_HUGE_ARRAY
+#elif (LZO_CC_MSC && defined(_QC))
+# undef LZO_HAVE_MM_HUGE_ARRAY
+# if (_MSC_VER < 600)
+# undef LZO_HAVE_MM_HUGE_PTR
+# endif
+#elif (LZO_CC_TURBOC && (__TURBOC__ < 0x0295))
+# undef LZO_HAVE_MM_HUGE_ARRAY
+#endif
+#if (LZO_ARCH_I086PM) && !defined(LZO_HAVE_MM_HUGE_PTR)
+# if (LZO_OS_DOS16)
+# error "this should not happen"
+# elif (LZO_CC_ZORTECHC)
+# else
+# error "this should not happen"
+# endif
+#endif
+#ifdef __cplusplus
+extern "C" {
+#endif
+#if (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0200))
+ extern void __near __cdecl _AHSHIFT(void);
+# define LZO_MM_AHSHIFT ((unsigned) _AHSHIFT)
+#elif (LZO_CC_DMC || LZO_CC_SYMANTECC || LZO_CC_ZORTECHC)
+ extern void __near __cdecl _AHSHIFT(void);
+# define LZO_MM_AHSHIFT ((unsigned) _AHSHIFT)
+#elif (LZO_CC_MSC || LZO_CC_TOPSPEEDC)
+ extern void __near __cdecl _AHSHIFT(void);
+# define LZO_MM_AHSHIFT ((unsigned) _AHSHIFT)
+#elif (LZO_CC_TURBOC && (__TURBOC__ >= 0x0295))
+ extern void __near __cdecl _AHSHIFT(void);
+# define LZO_MM_AHSHIFT ((unsigned) _AHSHIFT)
+#elif ((LZO_CC_AZTECC || LZO_CC_PACIFICC || LZO_CC_TURBOC) && LZO_OS_DOS16)
+# define LZO_MM_AHSHIFT 12
+#elif (LZO_CC_WATCOMC)
+ extern unsigned char _HShift;
+# define LZO_MM_AHSHIFT ((unsigned) _HShift)
+#else
+# error "FIXME - implement LZO_MM_AHSHIFT"
+#endif
+#ifdef __cplusplus
+}
+#endif
+#endif
+#elif (LZO_ARCH_C166)
+#if !defined(__MODEL__)
+# error "FIXME - C166 __MODEL__"
+#elif ((__MODEL__) == 0)
+# define LZO_MM_SMALL 1
+#elif ((__MODEL__) == 1)
+# define LZO_MM_SMALL 1
+#elif ((__MODEL__) == 2)
+# define LZO_MM_LARGE 1
+#elif ((__MODEL__) == 3)
+# define LZO_MM_TINY 1
+#elif ((__MODEL__) == 4)
+# define LZO_MM_XTINY 1
+#elif ((__MODEL__) == 5)
+# define LZO_MM_XSMALL 1
+#else
+# error "FIXME - C166 __MODEL__"
+#endif
+#elif (LZO_ARCH_MCS251)
+#if !defined(__MODEL__)
+# error "FIXME - MCS251 __MODEL__"
+#elif ((__MODEL__) == 0)
+# define LZO_MM_SMALL 1
+#elif ((__MODEL__) == 2)
+# define LZO_MM_LARGE 1
+#elif ((__MODEL__) == 3)
+# define LZO_MM_TINY 1
+#elif ((__MODEL__) == 4)
+# define LZO_MM_XTINY 1
+#elif ((__MODEL__) == 5)
+# define LZO_MM_XSMALL 1
+#else
+# error "FIXME - MCS251 __MODEL__"
+#endif
+#elif (LZO_ARCH_MCS51)
+#if !defined(__MODEL__)
+# error "FIXME - MCS51 __MODEL__"
+#elif ((__MODEL__) == 1)
+# define LZO_MM_SMALL 1
+#elif ((__MODEL__) == 2)
+# define LZO_MM_LARGE 1
+#elif ((__MODEL__) == 3)
+# define LZO_MM_TINY 1
+#elif ((__MODEL__) == 4)
+# define LZO_MM_XTINY 1
+#elif ((__MODEL__) == 5)
+# define LZO_MM_XSMALL 1
+#else
+# error "FIXME - MCS51 __MODEL__"
+#endif
+#elif (LZO_ARCH_CRAY_PVP)
+# define LZO_MM_PVP 1
+#else
+# define LZO_MM_FLAT 1
+#endif
+#if (LZO_MM_COMPACT)
+# define LZO_INFO_MM "compact"
+#elif (LZO_MM_FLAT)
+# define LZO_INFO_MM "flat"
+#elif (LZO_MM_HUGE)
+# define LZO_INFO_MM "huge"
+#elif (LZO_MM_LARGE)
+# define LZO_INFO_MM "large"
+#elif (LZO_MM_MEDIUM)
+# define LZO_INFO_MM "medium"
+#elif (LZO_MM_PVP)
+# define LZO_INFO_MM "pvp"
+#elif (LZO_MM_SMALL)
+# define LZO_INFO_MM "small"
+#elif (LZO_MM_TINY)
+# define LZO_INFO_MM "tiny"
+#else
+# error "unknown memory model"
+#endif
+#endif
+#if defined(SIZEOF_SHORT)
+# define LZO_SIZEOF_SHORT (SIZEOF_SHORT)
+#endif
+#if defined(SIZEOF_INT)
+# define LZO_SIZEOF_INT (SIZEOF_INT)
+#endif
+#if defined(SIZEOF_LONG)
+# define LZO_SIZEOF_LONG (SIZEOF_LONG)
+#endif
+#if defined(SIZEOF_LONG_LONG)
+# define LZO_SIZEOF_LONG_LONG (SIZEOF_LONG_LONG)
+#endif
+#if defined(SIZEOF___INT16)
+# define LZO_SIZEOF___INT16 (SIZEOF___INT16)
+#endif
+#if defined(SIZEOF___INT32)
+# define LZO_SIZEOF___INT32 (SIZEOF___INT32)
+#endif
+#if defined(SIZEOF___INT64)
+# define LZO_SIZEOF___INT64 (SIZEOF___INT64)
+#endif
+#if defined(SIZEOF_VOID_P)
+# define LZO_SIZEOF_VOID_P (SIZEOF_VOID_P)
+#endif
+#if defined(SIZEOF_SIZE_T)
+# define LZO_SIZEOF_SIZE_T (SIZEOF_SIZE_T)
+#endif
+#if defined(SIZEOF_PTRDIFF_T)
+# define LZO_SIZEOF_PTRDIFF_T (SIZEOF_PTRDIFF_T)
+#endif
+#define __LZO_LSR(x,b) (((x)+0ul) >> (b))
+#if !defined(LZO_SIZEOF_SHORT)
+# if (LZO_ARCH_CRAY_PVP)
+# define LZO_SIZEOF_SHORT 8
+# elif (USHRT_MAX == LZO_0xffffL)
+# define LZO_SIZEOF_SHORT 2
+# elif (__LZO_LSR(USHRT_MAX,7) == 1)
+# define LZO_SIZEOF_SHORT 1
+# elif (__LZO_LSR(USHRT_MAX,15) == 1)
+# define LZO_SIZEOF_SHORT 2
+# elif (__LZO_LSR(USHRT_MAX,31) == 1)
+# define LZO_SIZEOF_SHORT 4
+# elif (__LZO_LSR(USHRT_MAX,63) == 1)
+# define LZO_SIZEOF_SHORT 8
+# elif (__LZO_LSR(USHRT_MAX,127) == 1)
+# define LZO_SIZEOF_SHORT 16
+# else
+# error "LZO_SIZEOF_SHORT"
+# endif
+#endif
+#if !defined(LZO_SIZEOF_INT)
+# if (LZO_ARCH_CRAY_PVP)
+# define LZO_SIZEOF_INT 8
+# elif (UINT_MAX == LZO_0xffffL)
+# define LZO_SIZEOF_INT 2
+# elif (UINT_MAX == LZO_0xffffffffL)
+# define LZO_SIZEOF_INT 4
+# elif (__LZO_LSR(UINT_MAX,7) == 1)
+# define LZO_SIZEOF_INT 1
+# elif (__LZO_LSR(UINT_MAX,15) == 1)
+# define LZO_SIZEOF_INT 2
+# elif (__LZO_LSR(UINT_MAX,31) == 1)
+# define LZO_SIZEOF_INT 4
+# elif (__LZO_LSR(UINT_MAX,63) == 1)
+# define LZO_SIZEOF_INT 8
+# elif (__LZO_LSR(UINT_MAX,127) == 1)
+# define LZO_SIZEOF_INT 16
+# else
+# error "LZO_SIZEOF_INT"
+# endif
+#endif
+#if !defined(LZO_SIZEOF_LONG)
+# if (ULONG_MAX == LZO_0xffffffffL)
+# define LZO_SIZEOF_LONG 4
+# elif (__LZO_LSR(ULONG_MAX,7) == 1)
+# define LZO_SIZEOF_LONG 1
+# elif (__LZO_LSR(ULONG_MAX,15) == 1)
+# define LZO_SIZEOF_LONG 2
+# elif (__LZO_LSR(ULONG_MAX,31) == 1)
+# define LZO_SIZEOF_LONG 4
+# elif (__LZO_LSR(ULONG_MAX,63) == 1)
+# define LZO_SIZEOF_LONG 8
+# elif (__LZO_LSR(ULONG_MAX,127) == 1)
+# define LZO_SIZEOF_LONG 16
+# else
+# error "LZO_SIZEOF_LONG"
+# endif
+#endif
+#if !defined(LZO_SIZEOF_LONG_LONG) && !defined(LZO_SIZEOF___INT64)
+#if (LZO_SIZEOF_LONG > 0 && LZO_SIZEOF_LONG < 8)
+# if defined(__LONG_MAX__) && defined(__LONG_LONG_MAX__)
+# if (LZO_CC_GNUC >= 0x030300ul)
+# if ((__LONG_MAX__)+0 == (__LONG_LONG_MAX__)+0)
+# define LZO_SIZEOF_LONG_LONG LZO_SIZEOF_LONG
+# elif (__LZO_LSR(__LONG_LONG_MAX__,30) == 1)
+# define LZO_SIZEOF_LONG_LONG 4
+# endif
+# endif
+# endif
+#endif
+#endif
+#if !defined(LZO_SIZEOF_LONG_LONG) && !defined(LZO_SIZEOF___INT64)
+#if (LZO_SIZEOF_LONG > 0 && LZO_SIZEOF_LONG < 8)
+#if (LZO_ARCH_I086 && LZO_CC_DMC)
+#elif (LZO_CC_CILLY) && defined(__GNUC__)
+# define LZO_SIZEOF_LONG_LONG 8
+#elif (LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE)
+# define LZO_SIZEOF_LONG_LONG 8
+#elif ((LZO_OS_WIN32 || LZO_OS_WIN64 || defined(_WIN32)) && LZO_CC_MSC && (_MSC_VER >= 1400))
+# define LZO_SIZEOF_LONG_LONG 8
+#elif (LZO_OS_WIN64 || defined(_WIN64))
+# define LZO_SIZEOF___INT64 8
+#elif (LZO_ARCH_I386 && (LZO_CC_DMC))
+# define LZO_SIZEOF_LONG_LONG 8
+#elif (LZO_ARCH_I386 && (LZO_CC_SYMANTECC && (__SC__ >= 0x700)))
+# define LZO_SIZEOF_LONG_LONG 8
+#elif (LZO_ARCH_I386 && (LZO_CC_INTELC && defined(__linux__)))
+# define LZO_SIZEOF_LONG_LONG 8
+#elif (LZO_ARCH_I386 && (LZO_CC_MWERKS || LZO_CC_PELLESC || LZO_CC_PGI || LZO_CC_SUNPROC))
+# define LZO_SIZEOF_LONG_LONG 8
+#elif (LZO_ARCH_I386 && (LZO_CC_INTELC || LZO_CC_MSC))
+# define LZO_SIZEOF___INT64 8
+#elif ((LZO_OS_WIN32 || defined(_WIN32)) && (LZO_CC_MSC))
+# define LZO_SIZEOF___INT64 8
+#elif (LZO_ARCH_I386 && (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0520)))
+# define LZO_SIZEOF___INT64 8
+#elif (LZO_ARCH_I386 && (LZO_CC_WATCOMC && (__WATCOMC__ >= 1100)))
+# define LZO_SIZEOF___INT64 8
+#elif (LZO_CC_WATCOMC && defined(_INTEGRAL_MAX_BITS) && (_INTEGRAL_MAX_BITS == 64))
+# define LZO_SIZEOF___INT64 8
+#elif (LZO_OS_OS400 || defined(__OS400__)) && defined(__LLP64_IFC__)
+# define LZO_SIZEOF_LONG_LONG 8
+#elif (defined(__vms) || defined(__VMS)) && (__INITIAL_POINTER_SIZE+0 == 64)
+# define LZO_SIZEOF_LONG_LONG 8
+#elif (LZO_CC_SDCC) && (LZO_SIZEOF_INT == 2)
+#elif 1 && defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
+# define LZO_SIZEOF_LONG_LONG 8
+#endif
+#endif
+#endif
+#if defined(__cplusplus) && defined(LZO_CC_GNUC)
+# if (LZO_CC_GNUC < 0x020800ul)
+# undef LZO_SIZEOF_LONG_LONG
+# endif
+#endif
+#if defined(LZO_CFG_NO_LONG_LONG) || defined(__NO_LONG_LONG)
+# undef LZO_SIZEOF_LONG_LONG
+#endif
+#if !defined(LZO_SIZEOF_VOID_P)
+#if (LZO_ARCH_I086)
+# define __LZO_WORDSIZE 2
+# if (LZO_MM_TINY || LZO_MM_SMALL || LZO_MM_MEDIUM)
+# define LZO_SIZEOF_VOID_P 2
+# elif (LZO_MM_COMPACT || LZO_MM_LARGE || LZO_MM_HUGE)
+# define LZO_SIZEOF_VOID_P 4
+# else
+# error "LZO_MM"
+# endif
+#elif (LZO_ARCH_AVR || LZO_ARCH_Z80)
+# define __LZO_WORDSIZE 1
+# define LZO_SIZEOF_VOID_P 2
+#elif (LZO_ARCH_C166 || LZO_ARCH_MCS51 || LZO_ARCH_MCS251 || LZO_ARCH_MSP430)
+# define LZO_SIZEOF_VOID_P 2
+#elif (LZO_ARCH_H8300)
+# if defined(__NORMAL_MODE__)
+# define __LZO_WORDSIZE 4
+# define LZO_SIZEOF_VOID_P 2
+# elif defined(__H8300H__) || defined(__H8300S__) || defined(__H8300SX__)
+# define __LZO_WORDSIZE 4
+# define LZO_SIZEOF_VOID_P 4
+# else
+# define __LZO_WORDSIZE 2
+# define LZO_SIZEOF_VOID_P 2
+# endif
+# if (LZO_CC_GNUC && (LZO_CC_GNUC < 0x040000ul)) && (LZO_SIZEOF_INT == 4)
+# define LZO_SIZEOF_SIZE_T LZO_SIZEOF_INT
+# define LZO_SIZEOF_PTRDIFF_T LZO_SIZEOF_INT
+# endif
+#elif (LZO_ARCH_M16C)
+# define __LZO_WORDSIZE 2
+# if defined(__m32c_cpu__) || defined(__m32cm_cpu__)
+# define LZO_SIZEOF_VOID_P 4
+# else
+# define LZO_SIZEOF_VOID_P 2
+# endif
+#elif (LZO_SIZEOF_LONG == 8) && ((defined(__mips__) && defined(__R5900__)) || defined(__MIPS_PSX2__))
+# define __LZO_WORDSIZE 8
+# define LZO_SIZEOF_VOID_P 4
+#elif defined(__LLP64__) || defined(__LLP64) || defined(_LLP64) || defined(_WIN64)
+# define __LZO_WORDSIZE 8
+# define LZO_SIZEOF_VOID_P 8
+#elif (LZO_OS_OS400 || defined(__OS400__)) && defined(__LLP64_IFC__)
+# define LZO_SIZEOF_VOID_P LZO_SIZEOF_LONG
+# define LZO_SIZEOF_SIZE_T LZO_SIZEOF_LONG
+# define LZO_SIZEOF_PTRDIFF_T LZO_SIZEOF_LONG
+#elif (LZO_OS_OS400 || defined(__OS400__))
+# define __LZO_WORDSIZE LZO_SIZEOF_LONG
+# define LZO_SIZEOF_VOID_P 16
+# define LZO_SIZEOF_SIZE_T LZO_SIZEOF_LONG
+# define LZO_SIZEOF_PTRDIFF_T LZO_SIZEOF_LONG
+#elif (defined(__vms) || defined(__VMS)) && (__INITIAL_POINTER_SIZE+0 == 64)
+# define LZO_SIZEOF_VOID_P 8
+# define LZO_SIZEOF_SIZE_T LZO_SIZEOF_LONG
+# define LZO_SIZEOF_PTRDIFF_T LZO_SIZEOF_LONG
+#elif (LZO_ARCH_SPU)
+# if 0
+# define __LZO_WORDSIZE 16
+# endif
+# define LZO_SIZEOF_VOID_P 4
+#else
+# define LZO_SIZEOF_VOID_P LZO_SIZEOF_LONG
+#endif
+#endif
+#if !defined(LZO_WORDSIZE)
+# if defined(__LZO_WORDSIZE)
+# define LZO_WORDSIZE __LZO_WORDSIZE
+# else
+# define LZO_WORDSIZE LZO_SIZEOF_VOID_P
+# endif
+#endif
+#if !defined(LZO_SIZEOF_SIZE_T)
+#if (LZO_ARCH_I086 || LZO_ARCH_M16C)
+# define LZO_SIZEOF_SIZE_T 2
+#else
+# define LZO_SIZEOF_SIZE_T LZO_SIZEOF_VOID_P
+#endif
+#endif
+#if !defined(LZO_SIZEOF_PTRDIFF_T)
+#if (LZO_ARCH_I086)
+# if (LZO_MM_TINY || LZO_MM_SMALL || LZO_MM_MEDIUM || LZO_MM_HUGE)
+# define LZO_SIZEOF_PTRDIFF_T LZO_SIZEOF_VOID_P
+# elif (LZO_MM_COMPACT || LZO_MM_LARGE)
+# if (LZO_CC_BORLANDC || LZO_CC_TURBOC)
+# define LZO_SIZEOF_PTRDIFF_T 4
+# else
+# define LZO_SIZEOF_PTRDIFF_T 2
+# endif
+# else
+# error "LZO_MM"
+# endif
+#else
+# define LZO_SIZEOF_PTRDIFF_T LZO_SIZEOF_SIZE_T
+#endif
+#endif
+#if defined(LZO_ABI_NEUTRAL_ENDIAN)
+# undef LZO_ABI_BIG_ENDIAN
+# undef LZO_ABI_LITTLE_ENDIAN
+#elif !defined(LZO_ABI_BIG_ENDIAN) && !defined(LZO_ABI_LITTLE_ENDIAN)
+#if (LZO_ARCH_ALPHA) && (LZO_ARCH_CRAY_MPP)
+# define LZO_ABI_BIG_ENDIAN 1
+#elif (LZO_ARCH_ALPHA || LZO_ARCH_AMD64 || LZO_ARCH_BLACKFIN || LZO_ARCH_CRIS || LZO_ARCH_I086 || LZO_ARCH_I386 || LZO_ARCH_MSP430)
+# define LZO_ABI_LITTLE_ENDIAN 1
+#elif (LZO_ARCH_M68K || LZO_ARCH_S390)
+# define LZO_ABI_BIG_ENDIAN 1
+#elif 1 && defined(__IAR_SYSTEMS_ICC__) && defined(__LITTLE_ENDIAN__)
+# if (__LITTLE_ENDIAN__ == 1)
+# define LZO_ABI_LITTLE_ENDIAN 1
+# else
+# define LZO_ABI_BIG_ENDIAN 1
+# endif
+#elif 1 && defined(__BIG_ENDIAN__) && !defined(__LITTLE_ENDIAN__)
+# define LZO_ABI_BIG_ENDIAN 1
+#elif 1 && defined(__LITTLE_ENDIAN__) && !defined(__BIG_ENDIAN__)
+# define LZO_ABI_LITTLE_ENDIAN 1
+#elif 1 && (LZO_ARCH_ARM) && defined(__ARMEB__) && !defined(__ARMEL__)
+# define LZO_ABI_BIG_ENDIAN 1
+#elif 1 && (LZO_ARCH_ARM) && defined(__ARMEL__) && !defined(__ARMEB__)
+# define LZO_ABI_LITTLE_ENDIAN 1
+#elif 1 && (LZO_ARCH_MIPS) && defined(__MIPSEB__) && !defined(__MIPSEL__)
+# define LZO_ABI_BIG_ENDIAN 1
+#elif 1 && (LZO_ARCH_MIPS) && defined(__MIPSEL__) && !defined(__MIPSEB__)
+# define LZO_ABI_LITTLE_ENDIAN 1
+#endif
+#endif
+#if defined(LZO_ABI_BIG_ENDIAN) && defined(LZO_ABI_LITTLE_ENDIAN)
+# error "this should not happen"
+#endif
+#if defined(LZO_ABI_BIG_ENDIAN)
+# define LZO_INFO_ABI_ENDIAN "be"
+#elif defined(LZO_ABI_LITTLE_ENDIAN)
+# define LZO_INFO_ABI_ENDIAN "le"
+#elif defined(LZO_ABI_NEUTRAL_ENDIAN)
+# define LZO_INFO_ABI_ENDIAN "neutral"
+#endif
+#if (LZO_SIZEOF_INT == 1 && LZO_SIZEOF_LONG == 2 && LZO_SIZEOF_VOID_P == 2)
+# define LZO_ABI_I8LP16 1
+# define LZO_INFO_ABI_PM "i8lp16"
+#elif (LZO_SIZEOF_INT == 2 && LZO_SIZEOF_LONG == 2 && LZO_SIZEOF_VOID_P == 2)
+# define LZO_ABI_ILP16 1
+# define LZO_INFO_ABI_PM "ilp16"
+#elif (LZO_SIZEOF_INT == 4 && LZO_SIZEOF_LONG == 4 && LZO_SIZEOF_VOID_P == 4)
+# define LZO_ABI_ILP32 1
+# define LZO_INFO_ABI_PM "ilp32"
+#elif (LZO_SIZEOF_INT == 4 && LZO_SIZEOF_LONG == 4 && LZO_SIZEOF_VOID_P == 8 && LZO_SIZEOF_SIZE_T == 8)
+# define LZO_ABI_LLP64 1
+# define LZO_INFO_ABI_PM "llp64"
+#elif (LZO_SIZEOF_INT == 4 && LZO_SIZEOF_LONG == 8 && LZO_SIZEOF_VOID_P == 8)
+# define LZO_ABI_LP64 1
+# define LZO_INFO_ABI_PM "lp64"
+#elif (LZO_SIZEOF_INT == 8 && LZO_SIZEOF_LONG == 8 && LZO_SIZEOF_VOID_P == 8)
+# define LZO_ABI_ILP64 1
+# define LZO_INFO_ABI_PM "ilp64"
+#elif (LZO_SIZEOF_INT == 4 && LZO_SIZEOF_LONG == 8 && LZO_SIZEOF_VOID_P == 4)
+# define LZO_ABI_IP32L64 1
+# define LZO_INFO_ABI_PM "ip32l64"
+#endif
+#if !defined(__LZO_LIBC_OVERRIDE)
+#if defined(LZO_LIBC_NAKED)
+# define LZO_INFO_LIBC "naked"
+#elif defined(LZO_LIBC_FREESTANDING)
+# define LZO_INFO_LIBC "freestanding"
+#elif defined(LZO_LIBC_MOSTLY_FREESTANDING)
+# define LZO_INFO_LIBC "mfreestanding"
+#elif defined(LZO_LIBC_ISOC90)
+# define LZO_INFO_LIBC "isoc90"
+#elif defined(LZO_LIBC_ISOC99)
+# define LZO_INFO_LIBC "isoc99"
+#elif defined(__dietlibc__)
+# define LZO_LIBC_DIETLIBC 1
+# define LZO_INFO_LIBC "dietlibc"
+#elif defined(_NEWLIB_VERSION)
+# define LZO_LIBC_NEWLIB 1
+# define LZO_INFO_LIBC "newlib"
+#elif defined(__UCLIBC__) && defined(__UCLIBC_MAJOR__) && defined(__UCLIBC_MINOR__)
+# if defined(__UCLIBC_SUBLEVEL__)
+# define LZO_LIBC_UCLIBC (__UCLIBC_MAJOR__ * 0x10000L + __UCLIBC_MINOR__ * 0x100 + __UCLIBC_SUBLEVEL__)
+# else
+# define LZO_LIBC_UCLIBC 0x00090bL
+# endif
+# define LZO_INFO_LIBC "uclibc"
+#elif defined(__GLIBC__) && defined(__GLIBC_MINOR__)
+# define LZO_LIBC_GLIBC (__GLIBC__ * 0x10000L + __GLIBC_MINOR__ * 0x100)
+# define LZO_INFO_LIBC "glibc"
+#elif (LZO_CC_MWERKS) && defined(__MSL__)
+# define LZO_LIBC_MSL __MSL__
+# define LZO_INFO_LIBC "msl"
+#elif 1 && defined(__IAR_SYSTEMS_ICC__)
+# define LZO_LIBC_ISOC90 1
+# define LZO_INFO_LIBC "isoc90"
+#else
+# define LZO_LIBC_DEFAULT 1
+# define LZO_INFO_LIBC "default"
+#endif
+#endif
+#if !defined(__lzo_gnuc_extension__)
+#if (LZO_CC_GNUC >= 0x020800ul)
+# define __lzo_gnuc_extension__ __extension__
+#elif (LZO_CC_LLVM || LZO_CC_PATHSCALE)
+# define __lzo_gnuc_extension__ __extension__
+#else
+# define __lzo_gnuc_extension__
+#endif
+#endif
+#if !defined(__lzo_ua_volatile)
+# define __lzo_ua_volatile volatile
+#endif
+#if !defined(__lzo_alignof)
+#if (LZO_CC_CILLY || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE || LZO_CC_PGI)
+# define __lzo_alignof(e) __alignof__(e)
+#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 700))
+# define __lzo_alignof(e) __alignof__(e)
+#elif (LZO_CC_MSC && (_MSC_VER >= 1300))
+# define __lzo_alignof(e) __alignof(e)
+#endif
+#endif
+#if defined(__lzo_alignof)
+# define __lzo_HAVE_alignof 1
+#endif
+#if !defined(__lzo_constructor)
+#if (LZO_CC_GNUC >= 0x030400ul)
+# define __lzo_constructor __attribute__((__constructor__,__used__))
+#elif (LZO_CC_GNUC >= 0x020700ul)
+# define __lzo_constructor __attribute__((__constructor__))
+#elif (LZO_CC_LLVM || LZO_CC_PATHSCALE)
+# define __lzo_constructor __attribute__((__constructor__))
+#endif
+#endif
+#if defined(__lzo_constructor)
+# define __lzo_HAVE_constructor 1
+#endif
+#if !defined(__lzo_destructor)
+#if (LZO_CC_GNUC >= 0x030400ul)
+# define __lzo_destructor __attribute__((__destructor__,__used__))
+#elif (LZO_CC_GNUC >= 0x020700ul)
+# define __lzo_destructor __attribute__((__destructor__))
+#elif (LZO_CC_LLVM || LZO_CC_PATHSCALE)
+# define __lzo_destructor __attribute__((__destructor__))
+#endif
+#endif
+#if defined(__lzo_destructor)
+# define __lzo_HAVE_destructor 1
+#endif
+#if defined(__lzo_HAVE_destructor) && !defined(__lzo_HAVE_constructor)
+# error "this should not happen"
+#endif
+#if !defined(__lzo_inline)
+#if (LZO_CC_TURBOC && (__TURBOC__ <= 0x0295))
+#elif defined(__cplusplus)
+# define __lzo_inline inline
+#elif (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0550))
+# define __lzo_inline __inline
+#elif (LZO_CC_CILLY || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE || LZO_CC_PGI)
+# define __lzo_inline __inline__
+#elif (LZO_CC_DMC)
+# define __lzo_inline __inline
+#elif (LZO_CC_INTELC)
+# define __lzo_inline __inline
+#elif (LZO_CC_MWERKS && (__MWERKS__ >= 0x2405))
+# define __lzo_inline __inline
+#elif (LZO_CC_MSC && (_MSC_VER >= 900))
+# define __lzo_inline __inline
+#elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
+# define __lzo_inline inline
+#endif
+#endif
+#if defined(__lzo_inline)
+# define __lzo_HAVE_inline 1
+#else
+# define __lzo_inline
+#endif
+#if !defined(__lzo_forceinline)
+#if (LZO_CC_GNUC >= 0x030200ul)
+# define __lzo_forceinline __inline__ __attribute__((__always_inline__))
+#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 450) && LZO_CC_SYNTAX_MSC)
+# define __lzo_forceinline __forceinline
+#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 800) && LZO_CC_SYNTAX_GNUC)
+# define __lzo_forceinline __inline__ __attribute__((__always_inline__))
+#elif (LZO_CC_LLVM || LZO_CC_PATHSCALE)
+# define __lzo_forceinline __inline__ __attribute__((__always_inline__))
+#elif (LZO_CC_MSC && (_MSC_VER >= 1200))
+# define __lzo_forceinline __forceinline
+#endif
+#endif
+#if defined(__lzo_forceinline)
+# define __lzo_HAVE_forceinline 1
+#else
+# define __lzo_forceinline
+#endif
+#if !defined(__lzo_noinline)
+#if 1 && (LZO_ARCH_I386) && (LZO_CC_GNUC >= 0x040000ul) && (LZO_CC_GNUC < 0x040003ul)
+# define __lzo_noinline __attribute__((__noinline__,__used__))
+#elif (LZO_CC_GNUC >= 0x030200ul)
+# define __lzo_noinline __attribute__((__noinline__))
+#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 600) && LZO_CC_SYNTAX_MSC)
+# define __lzo_noinline __declspec(noinline)
+#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 800) && LZO_CC_SYNTAX_GNUC)
+# define __lzo_noinline __attribute__((__noinline__))
+#elif (LZO_CC_LLVM || LZO_CC_PATHSCALE)
+# define __lzo_noinline __attribute__((__noinline__))
+#elif (LZO_CC_MSC && (_MSC_VER >= 1300))
+# define __lzo_noinline __declspec(noinline)
+#elif (LZO_CC_MWERKS && (__MWERKS__ >= 0x3200) && (LZO_OS_WIN32 || LZO_OS_WIN64))
+# if defined(__cplusplus)
+# else
+# define __lzo_noinline __declspec(noinline)
+# endif
+#endif
+#endif
+#if defined(__lzo_noinline)
+# define __lzo_HAVE_noinline 1
+#else
+# define __lzo_noinline
+#endif
+#if (defined(__lzo_HAVE_forceinline) || defined(__lzo_HAVE_noinline)) && !defined(__lzo_HAVE_inline)
+# error "this should not happen"
+#endif
+#if !defined(__lzo_noreturn)
+#if (LZO_CC_GNUC >= 0x020700ul)
+# define __lzo_noreturn __attribute__((__noreturn__))
+#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 450) && LZO_CC_SYNTAX_MSC)
+# define __lzo_noreturn __declspec(noreturn)
+#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 600) && LZO_CC_SYNTAX_GNUC)
+# define __lzo_noreturn __attribute__((__noreturn__))
+#elif (LZO_CC_LLVM || LZO_CC_PATHSCALE)
+# define __lzo_noreturn __attribute__((__noreturn__))
+#elif (LZO_CC_MSC && (_MSC_VER >= 1200))
+# define __lzo_noreturn __declspec(noreturn)
+#endif
+#endif
+#if defined(__lzo_noreturn)
+# define __lzo_HAVE_noreturn 1
+#else
+# define __lzo_noreturn
+#endif
+#if !defined(__lzo_nothrow)
+#if (LZO_CC_GNUC >= 0x030300ul)
+# define __lzo_nothrow __attribute__((__nothrow__))
+#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 450) && LZO_CC_SYNTAX_MSC) && defined(__cplusplus)
+# define __lzo_nothrow __declspec(nothrow)
+#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 800) && LZO_CC_SYNTAX_GNUC)
+# define __lzo_nothrow __attribute__((__nothrow__))
+#elif (LZO_CC_LLVM || LZO_CC_PATHSCALE)
+# define __lzo_nothrow __attribute__((__nothrow__))
+#elif (LZO_CC_MSC && (_MSC_VER >= 1200)) && defined(__cplusplus)
+# define __lzo_nothrow __declspec(nothrow)
+#endif
+#endif
+#if defined(__lzo_nothrow)
+# define __lzo_HAVE_nothrow 1
+#else
+# define __lzo_nothrow
+#endif
+#if !defined(__lzo_restrict)
+#if (LZO_CC_GNUC >= 0x030400ul)
+# define __lzo_restrict __restrict__
+#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 600) && LZO_CC_SYNTAX_GNUC)
+# define __lzo_restrict __restrict__
+#elif (LZO_CC_LLVM)
+# define __lzo_restrict __restrict__
+#elif (LZO_CC_MSC && (_MSC_VER >= 1400))
+# define __lzo_restrict __restrict
+#endif
+#endif
+#if defined(__lzo_restrict)
+# define __lzo_HAVE_restrict 1
+#else
+# define __lzo_restrict
+#endif
+#if !defined(__lzo_likely) && !defined(__lzo_unlikely)
+#if (LZO_CC_GNUC >= 0x030200ul)
+# define __lzo_likely(e) (__builtin_expect(!!(e),1))
+# define __lzo_unlikely(e) (__builtin_expect(!!(e),0))
+#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 800))
+# define __lzo_likely(e) (__builtin_expect(!!(e),1))
+# define __lzo_unlikely(e) (__builtin_expect(!!(e),0))
+#elif (LZO_CC_LLVM || LZO_CC_PATHSCALE)
+# define __lzo_likely(e) (__builtin_expect(!!(e),1))
+# define __lzo_unlikely(e) (__builtin_expect(!!(e),0))
+#endif
+#endif
+#if defined(__lzo_likely)
+# define __lzo_HAVE_likely 1
+#else
+# define __lzo_likely(e) (e)
+#endif
+#if defined(__lzo_unlikely)
+# define __lzo_HAVE_unlikely 1
+#else
+# define __lzo_unlikely(e) (e)
+#endif
+#if !defined(LZO_UNUSED)
+# if (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0600))
+# define LZO_UNUSED(var) ((void) &var)
+# elif (LZO_CC_BORLANDC || LZO_CC_HIGHC || LZO_CC_NDPC || LZO_CC_PELLESC || LZO_CC_TURBOC)
+# define LZO_UNUSED(var) if (&var) ; else
+# elif (LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE)
+# define LZO_UNUSED(var) ((void) var)
+# elif (LZO_CC_MSC && (_MSC_VER < 900))
+# define LZO_UNUSED(var) if (&var) ; else
+# elif (LZO_CC_KEILC)
+# define LZO_UNUSED(var) {extern int __lzo_unused[1-2*!(sizeof(var)>0)];}
+# elif (LZO_CC_PACIFICC)
+# define LZO_UNUSED(var) ((void) sizeof(var))
+# elif (LZO_CC_WATCOMC) && defined(__cplusplus)
+# define LZO_UNUSED(var) ((void) var)
+# else
+# define LZO_UNUSED(var) ((void) &var)
+# endif
+#endif
+#if !defined(LZO_UNUSED_FUNC)
+# if (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0600))
+# define LZO_UNUSED_FUNC(func) ((void) func)
+# elif (LZO_CC_BORLANDC || LZO_CC_NDPC || LZO_CC_TURBOC)
+# define LZO_UNUSED_FUNC(func) if (func) ; else
+# elif (LZO_CC_LLVM)
+# define LZO_UNUSED_FUNC(func) ((void) &func)
+# elif (LZO_CC_MSC && (_MSC_VER < 900))
+# define LZO_UNUSED_FUNC(func) if (func) ; else
+# elif (LZO_CC_MSC)
+# define LZO_UNUSED_FUNC(func) ((void) &func)
+# elif (LZO_CC_KEILC || LZO_CC_PELLESC)
+# define LZO_UNUSED_FUNC(func) {extern int __lzo_unused[1-2*!(sizeof((int)func)>0)];}
+# else
+# define LZO_UNUSED_FUNC(func) ((void) func)
+# endif
+#endif
+#if !defined(LZO_UNUSED_LABEL)
+# if (LZO_CC_WATCOMC) && defined(__cplusplus)
+# define LZO_UNUSED_LABEL(l) switch(0) case 1:goto l
+# elif (LZO_CC_INTELC || LZO_CC_WATCOMC)
+# define LZO_UNUSED_LABEL(l) if (0) goto l
+# else
+# define LZO_UNUSED_LABEL(l) switch(0) case 1:goto l
+# endif
+#endif
+#if !defined(LZO_DEFINE_UNINITIALIZED_VAR)
+# if 0
+# define LZO_DEFINE_UNINITIALIZED_VAR(type,var,init) type var
+# elif 0 && (LZO_CC_GNUC)
+# define LZO_DEFINE_UNINITIALIZED_VAR(type,var,init) type var = var
+# else
+# define LZO_DEFINE_UNINITIALIZED_VAR(type,var,init) type var = init
+# endif
+#endif
+#if !defined(LZO_COMPILE_TIME_ASSERT_HEADER)
+# if (LZO_CC_AZTECC || LZO_CC_ZORTECHC)
+# define LZO_COMPILE_TIME_ASSERT_HEADER(e) extern int __lzo_cta[1-!(e)];
+# elif (LZO_CC_DMC || LZO_CC_SYMANTECC)
+# define LZO_COMPILE_TIME_ASSERT_HEADER(e) extern int __lzo_cta[1u-2*!(e)];
+# elif (LZO_CC_TURBOC && (__TURBOC__ == 0x0295))
+# define LZO_COMPILE_TIME_ASSERT_HEADER(e) extern int __lzo_cta[1-!(e)];
+# else
+# define LZO_COMPILE_TIME_ASSERT_HEADER(e) extern int __lzo_cta[1-2*!(e)];
+# endif
+#endif
+#if !defined(LZO_COMPILE_TIME_ASSERT)
+# if (LZO_CC_AZTECC)
+# define LZO_COMPILE_TIME_ASSERT(e) {typedef int __lzo_cta_t[1-!(e)];}
+# elif (LZO_CC_DMC || LZO_CC_PACIFICC || LZO_CC_SYMANTECC || LZO_CC_ZORTECHC)
+# define LZO_COMPILE_TIME_ASSERT(e) switch(0) case 1:case !(e):break;
+# elif (LZO_CC_MSC && (_MSC_VER < 900))
+# define LZO_COMPILE_TIME_ASSERT(e) switch(0) case 1:case !(e):break;
+# elif (LZO_CC_TURBOC && (__TURBOC__ == 0x0295))
+# define LZO_COMPILE_TIME_ASSERT(e) switch(0) case 1:case !(e):break;
+# else
+# define LZO_COMPILE_TIME_ASSERT(e) {typedef int __lzo_cta_t[1-2*!(e)];}
+# endif
+#endif
+#if (LZO_ARCH_I086 || LZO_ARCH_I386) && (LZO_OS_DOS16 || LZO_OS_DOS32 || LZO_OS_OS2 || LZO_OS_OS216 || LZO_OS_WIN16 || LZO_OS_WIN32 || LZO_OS_WIN64)
+# if (LZO_CC_GNUC || LZO_CC_HIGHC || LZO_CC_NDPC || LZO_CC_PACIFICC)
+# elif (LZO_CC_DMC || LZO_CC_SYMANTECC || LZO_CC_ZORTECHC)
+# define __lzo_cdecl __cdecl
+# define __lzo_cdecl_atexit
+# define __lzo_cdecl_main __cdecl
+# if (LZO_OS_OS2 && (LZO_CC_DMC || LZO_CC_SYMANTECC))
+# define __lzo_cdecl_qsort __pascal
+# elif (LZO_OS_OS2 && (LZO_CC_ZORTECHC))
+# define __lzo_cdecl_qsort _stdcall
+# else
+# define __lzo_cdecl_qsort __cdecl
+# endif
+# elif (LZO_CC_WATCOMC)
+# define __lzo_cdecl __cdecl
+# else
+# define __lzo_cdecl __cdecl
+# define __lzo_cdecl_atexit __cdecl
+# define __lzo_cdecl_main __cdecl
+# define __lzo_cdecl_qsort __cdecl
+# endif
+# if (LZO_CC_GNUC || LZO_CC_HIGHC || LZO_CC_NDPC || LZO_CC_PACIFICC || LZO_CC_WATCOMC)
+# elif (LZO_OS_OS2 && (LZO_CC_DMC || LZO_CC_SYMANTECC))
+# define __lzo_cdecl_sighandler __pascal
+# elif (LZO_OS_OS2 && (LZO_CC_ZORTECHC))
+# define __lzo_cdecl_sighandler _stdcall
+# elif (LZO_CC_MSC && (_MSC_VER >= 1400)) && defined(_M_CEE_PURE)
+# define __lzo_cdecl_sighandler __clrcall
+# elif (LZO_CC_MSC && (_MSC_VER >= 600 && _MSC_VER < 700))
+# if defined(_DLL)
+# define __lzo_cdecl_sighandler _far _cdecl _loadds
+# elif defined(_MT)
+# define __lzo_cdecl_sighandler _far _cdecl
+# else
+# define __lzo_cdecl_sighandler _cdecl
+# endif
+# else
+# define __lzo_cdecl_sighandler __cdecl
+# endif
+#elif (LZO_ARCH_I386) && (LZO_CC_WATCOMC)
+# define __lzo_cdecl __cdecl
+#elif (LZO_ARCH_M68K && LZO_OS_TOS && (LZO_CC_PUREC || LZO_CC_TURBOC))
+# define __lzo_cdecl cdecl
+#endif
+#if !defined(__lzo_cdecl)
+# define __lzo_cdecl
+#endif
+#if !defined(__lzo_cdecl_atexit)
+# define __lzo_cdecl_atexit
+#endif
+#if !defined(__lzo_cdecl_main)
+# define __lzo_cdecl_main
+#endif
+#if !defined(__lzo_cdecl_qsort)
+# define __lzo_cdecl_qsort
+#endif
+#if !defined(__lzo_cdecl_sighandler)
+# define __lzo_cdecl_sighandler
+#endif
+#if !defined(__lzo_cdecl_va)
+# define __lzo_cdecl_va __lzo_cdecl
+#endif
+#if !defined(LZO_CFG_NO_WINDOWS_H)
+#if (LZO_OS_CYGWIN || (LZO_OS_EMX && defined(__RSXNT__)) || LZO_OS_WIN32 || LZO_OS_WIN64)
+# if (LZO_CC_WATCOMC && (__WATCOMC__ < 1000))
+# elif (LZO_OS_WIN32 && LZO_CC_GNUC) && defined(__PW32__)
+# elif ((LZO_OS_CYGWIN || defined(__MINGW32__)) && (LZO_CC_GNUC && (LZO_CC_GNUC < 0x025f00ul)))
+# else
+# define LZO_HAVE_WINDOWS_H 1
+# endif
+#endif
+#endif
+#if (LZO_ARCH_ALPHA)
+# define LZO_OPT_AVOID_UINT_INDEX 1
+# define LZO_OPT_AVOID_SHORT 1
+# define LZO_OPT_AVOID_USHORT 1
+#elif (LZO_ARCH_AMD64)
+# define LZO_OPT_AVOID_INT_INDEX 1
+# define LZO_OPT_AVOID_UINT_INDEX 1
+# define LZO_OPT_UNALIGNED16 1
+# define LZO_OPT_UNALIGNED32 1
+# define LZO_OPT_UNALIGNED64 1
+#elif (LZO_ARCH_ARM && LZO_ARCH_ARM_THUMB)
+#elif (LZO_ARCH_ARM)
+# define LZO_OPT_AVOID_SHORT 1
+# define LZO_OPT_AVOID_USHORT 1
+#elif (LZO_ARCH_CRIS)
+# define LZO_OPT_UNALIGNED16 1
+# define LZO_OPT_UNALIGNED32 1
+#elif (LZO_ARCH_I386)
+# define LZO_OPT_UNALIGNED16 1
+# define LZO_OPT_UNALIGNED32 1
+#elif (LZO_ARCH_IA64)
+# define LZO_OPT_AVOID_INT_INDEX 1
+# define LZO_OPT_AVOID_UINT_INDEX 1
+# define LZO_OPT_PREFER_POSTINC 1
+#elif (LZO_ARCH_M68K)
+# define LZO_OPT_PREFER_POSTINC 1
+# define LZO_OPT_PREFER_PREDEC 1
+# if defined(__mc68020__) && !defined(__mcoldfire__)
+# define LZO_OPT_UNALIGNED16 1
+# define LZO_OPT_UNALIGNED32 1
+# endif
+#elif (LZO_ARCH_MIPS)
+# define LZO_OPT_AVOID_UINT_INDEX 1
+#elif (LZO_ARCH_POWERPC)
+# define LZO_OPT_PREFER_PREINC 1
+# define LZO_OPT_PREFER_PREDEC 1
+# if defined(LZO_ABI_BIG_ENDIAN)
+# define LZO_OPT_UNALIGNED16 1
+# define LZO_OPT_UNALIGNED32 1
+# endif
+#elif (LZO_ARCH_S390)
+# define LZO_OPT_UNALIGNED16 1
+# define LZO_OPT_UNALIGNED32 1
+# if (LZO_SIZEOF_SIZE_T == 8)
+# define LZO_OPT_UNALIGNED64 1
+# endif
+#elif (LZO_ARCH_SH)
+# define LZO_OPT_PREFER_POSTINC 1
+# define LZO_OPT_PREFER_PREDEC 1
+#endif
+#if !defined(LZO_CFG_NO_INLINE_ASM)
+#if defined(LZO_CC_LLVM)
+# define LZO_CFG_NO_INLINE_ASM 1
+#endif
+#endif
+#if !defined(LZO_CFG_NO_UNALIGNED)
+#if defined(LZO_ABI_NEUTRAL_ENDIAN) || defined(LZO_ARCH_GENERIC)
+# define LZO_CFG_NO_UNALIGNED 1
+#endif
+#endif
+#if defined(LZO_CFG_NO_UNALIGNED)
+# undef LZO_OPT_UNALIGNED16
+# undef LZO_OPT_UNALIGNED32
+# undef LZO_OPT_UNALIGNED64
+#endif
+#if defined(LZO_CFG_NO_INLINE_ASM)
+#elif (LZO_ARCH_I386 && (LZO_OS_DOS32 || LZO_OS_WIN32) && (LZO_CC_DMC || LZO_CC_INTELC || LZO_CC_MSC || LZO_CC_PELLESC))
+# define LZO_ASM_SYNTAX_MSC 1
+#elif (LZO_OS_WIN64 && (LZO_CC_DMC || LZO_CC_INTELC || LZO_CC_MSC || LZO_CC_PELLESC))
+#elif (LZO_ARCH_I386 && (LZO_CC_GNUC || LZO_CC_INTELC || LZO_CC_PATHSCALE))
+# define LZO_ASM_SYNTAX_GNUC 1
+#elif (LZO_ARCH_AMD64 && (LZO_CC_GNUC || LZO_CC_INTELC || LZO_CC_PATHSCALE))
+# define LZO_ASM_SYNTAX_GNUC 1
+#endif
+#if (LZO_ASM_SYNTAX_GNUC)
+#if (LZO_ARCH_I386 && LZO_CC_GNUC && (LZO_CC_GNUC < 0x020000ul))
+# define __LZO_ASM_CLOBBER "ax"
+#elif (LZO_CC_INTELC)
+# define __LZO_ASM_CLOBBER "memory"
+#else
+# define __LZO_ASM_CLOBBER "cc", "memory"
+#endif
+#endif
+#if defined(__LZO_INFOSTR_MM)
+#elif (LZO_MM_FLAT) && (defined(__LZO_INFOSTR_PM) || defined(LZO_INFO_ABI_PM))
+# define __LZO_INFOSTR_MM ""
+#elif defined(LZO_INFO_MM)
+# define __LZO_INFOSTR_MM "." LZO_INFO_MM
+#else
+# define __LZO_INFOSTR_MM ""
+#endif
+#if defined(__LZO_INFOSTR_PM)
+#elif defined(LZO_INFO_ABI_PM)
+# define __LZO_INFOSTR_PM "." LZO_INFO_ABI_PM
+#else
+# define __LZO_INFOSTR_PM ""
+#endif
+#if defined(__LZO_INFOSTR_ENDIAN)
+#elif defined(LZO_INFO_ABI_ENDIAN)
+# define __LZO_INFOSTR_ENDIAN "." LZO_INFO_ABI_ENDIAN
+#else
+# define __LZO_INFOSTR_ENDIAN ""
+#endif
+#if defined(__LZO_INFOSTR_OSNAME)
+#elif defined(LZO_INFO_OS_CONSOLE)
+# define __LZO_INFOSTR_OSNAME LZO_INFO_OS "." LZO_INFO_OS_CONSOLE
+#elif defined(LZO_INFO_OS_POSIX)
+# define __LZO_INFOSTR_OSNAME LZO_INFO_OS "." LZO_INFO_OS_POSIX
+#else
+# define __LZO_INFOSTR_OSNAME LZO_INFO_OS
+#endif
+#if defined(__LZO_INFOSTR_LIBC)
+#elif defined(LZO_INFO_LIBC)
+# define __LZO_INFOSTR_LIBC "." LZO_INFO_LIBC
+#else
+# define __LZO_INFOSTR_LIBC ""
+#endif
+#if defined(__LZO_INFOSTR_CCVER)
+#elif defined(LZO_INFO_CCVER)
+# define __LZO_INFOSTR_CCVER " " LZO_INFO_CCVER
+#else
+# define __LZO_INFOSTR_CCVER ""
+#endif
+#define LZO_INFO_STRING \
+ LZO_INFO_ARCH __LZO_INFOSTR_MM __LZO_INFOSTR_PM __LZO_INFOSTR_ENDIAN \
+ " " __LZO_INFOSTR_OSNAME __LZO_INFOSTR_LIBC " " LZO_INFO_CC __LZO_INFOSTR_CCVER
+
+#endif /* already included */
+
+/* vim:set ts=4 et: */
diff --git a/minilzo.c b/minilzo.c
new file mode 100644
index 0000000..6a62b31
--- /dev/null
+++ b/minilzo.c
@@ -0,0 +1,4112 @@
+/* minilzo.c -- mini subset of the LZO real-time data compression library
+
+ This file is part of the LZO real-time data compression library.
+
+ Copyright (C) 2008 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2007 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2006 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2005 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2004 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2003 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2002 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2001 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2000 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 1997 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 1996 Markus Franz Xaver Johannes Oberhumer
+ All Rights Reserved.
+
+ The LZO library 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.
+
+ The LZO library 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 the LZO library; see the file COPYING.
+ If not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ Markus F.X.J. Oberhumer
+
+ http://www.oberhumer.com/opensource/lzo/
+ */
+
+/*
+ * NOTE:
+ * the full LZO package can be found at
+ * http://www.oberhumer.com/opensource/lzo/
+ */
+
+#define __LZO_IN_MINILZO
+#define LZO_BUILD
+
+#if defined(LZO_CFG_FREESTANDING)
+# undef MINILZO_HAVE_CONFIG_H
+# define LZO_LIBC_FREESTANDING 1
+# define LZO_OS_FREESTANDING 1
+#endif
+
+#ifdef MINILZO_HAVE_CONFIG_H
+# include
+#endif
+#include
+#include
+#if defined(MINILZO_CFG_USE_INTERNAL_LZODEFS)
+
+#ifndef __LZODEFS_H_INCLUDED
+#define __LZODEFS_H_INCLUDED 1
+
+#if defined(__CYGWIN32__) && !defined(__CYGWIN__)
+# define __CYGWIN__ __CYGWIN32__
+#endif
+#if defined(__IBMCPP__) && !defined(__IBMC__)
+# define __IBMC__ __IBMCPP__
+#endif
+#if defined(__ICL) && defined(_WIN32) && !defined(__INTEL_COMPILER)
+# define __INTEL_COMPILER __ICL
+#endif
+#if 1 && defined(__INTERIX) && defined(__GNUC__) && !defined(_ALL_SOURCE)
+# define _ALL_SOURCE 1
+#endif
+#if defined(__mips__) && defined(__R5900__)
+# if !defined(__LONG_MAX__)
+# define __LONG_MAX__ 9223372036854775807L
+# endif
+#endif
+#if defined(__INTEL_COMPILER) && defined(__linux__)
+# pragma warning(disable: 193)
+#endif
+#if defined(__KEIL__) && defined(__C166__)
+# pragma warning disable = 322
+#elif 0 && defined(__C251__)
+# pragma warning disable = 322
+#endif
+#if defined(_MSC_VER) && !defined(__INTEL_COMPILER) && !defined(__MWERKS__)
+# if (_MSC_VER >= 1300)
+# pragma warning(disable: 4668)
+# endif
+#endif
+#if 0 && defined(__WATCOMC__)
+# if (__WATCOMC__ >= 1050) && (__WATCOMC__ < 1060)
+# pragma warning 203 9
+# endif
+#endif
+#if defined(__BORLANDC__) && defined(__MSDOS__) && !defined(__FLAT__)
+# pragma option -h
+#endif
+#if 0
+#define LZO_0xffffL 0xfffful
+#define LZO_0xffffffffL 0xfffffffful
+#else
+#define LZO_0xffffL 65535ul
+#define LZO_0xffffffffL 4294967295ul
+#endif
+#if (LZO_0xffffL == LZO_0xffffffffL)
+# error "your preprocessor is broken 1"
+#endif
+#if (16ul * 16384ul != 262144ul)
+# error "your preprocessor is broken 2"
+#endif
+#if 0
+#if (32767 >= 4294967295ul)
+# error "your preprocessor is broken 3"
+#endif
+#if (65535u >= 4294967295ul)
+# error "your preprocessor is broken 4"
+#endif
+#endif
+#if (UINT_MAX == LZO_0xffffL)
+#if defined(__ZTC__) && defined(__I86__) && !defined(__OS2__)
+# if !defined(MSDOS)
+# define MSDOS 1
+# endif
+# if !defined(_MSDOS)
+# define _MSDOS 1
+# endif
+#elif 0 && defined(__VERSION) && defined(MB_LEN_MAX)
+# if (__VERSION == 520) && (MB_LEN_MAX == 1)
+# if !defined(__AZTEC_C__)
+# define __AZTEC_C__ __VERSION
+# endif
+# if !defined(__DOS__)
+# define __DOS__ 1
+# endif
+# endif
+#endif
+#endif
+#if defined(_MSC_VER) && defined(M_I86HM) && (UINT_MAX == LZO_0xffffL)
+# define ptrdiff_t long
+# define _PTRDIFF_T_DEFINED
+#endif
+#if (UINT_MAX == LZO_0xffffL)
+# undef __LZO_RENAME_A
+# undef __LZO_RENAME_B
+# if defined(__AZTEC_C__) && defined(__DOS__)
+# define __LZO_RENAME_A 1
+# elif defined(_MSC_VER) && defined(MSDOS)
+# if (_MSC_VER < 600)
+# define __LZO_RENAME_A 1
+# elif (_MSC_VER < 700)
+# define __LZO_RENAME_B 1
+# endif
+# elif defined(__TSC__) && defined(__OS2__)
+# define __LZO_RENAME_A 1
+# elif defined(__MSDOS__) && defined(__TURBOC__) && (__TURBOC__ < 0x0410)
+# define __LZO_RENAME_A 1
+# elif defined(__PACIFIC__) && defined(DOS)
+# if !defined(__far)
+# define __far far
+# endif
+# if !defined(__near)
+# define __near near
+# endif
+# endif
+# if defined(__LZO_RENAME_A)
+# if !defined(__cdecl)
+# define __cdecl cdecl
+# endif
+# if !defined(__far)
+# define __far far
+# endif
+# if !defined(__huge)
+# define __huge huge
+# endif
+# if !defined(__near)
+# define __near near
+# endif
+# if !defined(__pascal)
+# define __pascal pascal
+# endif
+# if !defined(__huge)
+# define __huge huge
+# endif
+# elif defined(__LZO_RENAME_B)
+# if !defined(__cdecl)
+# define __cdecl _cdecl
+# endif
+# if !defined(__far)
+# define __far _far
+# endif
+# if !defined(__huge)
+# define __huge _huge
+# endif
+# if !defined(__near)
+# define __near _near
+# endif
+# if !defined(__pascal)
+# define __pascal _pascal
+# endif
+# elif (defined(__PUREC__) || defined(__TURBOC__)) && defined(__TOS__)
+# if !defined(__cdecl)
+# define __cdecl cdecl
+# endif
+# if !defined(__pascal)
+# define __pascal pascal
+# endif
+# endif
+# undef __LZO_RENAME_A
+# undef __LZO_RENAME_B
+#endif
+#if (UINT_MAX == LZO_0xffffL)
+#if defined(__AZTEC_C__) && defined(__DOS__)
+# define LZO_BROKEN_CDECL_ALT_SYNTAX 1
+#elif defined(_MSC_VER) && defined(MSDOS)
+# if (_MSC_VER < 600)
+# define LZO_BROKEN_INTEGRAL_CONSTANTS 1
+# endif
+# if (_MSC_VER < 700)
+# define LZO_BROKEN_INTEGRAL_PROMOTION 1
+# define LZO_BROKEN_SIZEOF 1
+# endif
+#elif defined(__PACIFIC__) && defined(DOS)
+# define LZO_BROKEN_INTEGRAL_CONSTANTS 1
+#elif defined(__TURBOC__) && defined(__MSDOS__)
+# if (__TURBOC__ < 0x0150)
+# define LZO_BROKEN_CDECL_ALT_SYNTAX 1
+# define LZO_BROKEN_INTEGRAL_CONSTANTS 1
+# define LZO_BROKEN_INTEGRAL_PROMOTION 1
+# endif
+# if (__TURBOC__ < 0x0200)
+# define LZO_BROKEN_SIZEOF 1
+# endif
+# if (__TURBOC__ < 0x0400) && defined(__cplusplus)
+# define LZO_BROKEN_CDECL_ALT_SYNTAX 1
+# endif
+#elif (defined(__PUREC__) || defined(__TURBOC__)) && defined(__TOS__)
+# define LZO_BROKEN_CDECL_ALT_SYNTAX 1
+# define LZO_BROKEN_SIZEOF 1
+#endif
+#endif
+#if defined(__WATCOMC__) && (__WATCOMC__ < 900)
+# define LZO_BROKEN_INTEGRAL_CONSTANTS 1
+#endif
+#if defined(_CRAY) && defined(_CRAY1)
+# define LZO_BROKEN_SIGNED_RIGHT_SHIFT 1
+#endif
+#define LZO_PP_STRINGIZE(x) #x
+#define LZO_PP_MACRO_EXPAND(x) LZO_PP_STRINGIZE(x)
+#define LZO_PP_CONCAT2(a,b) a ## b
+#define LZO_PP_CONCAT3(a,b,c) a ## b ## c
+#define LZO_PP_CONCAT4(a,b,c,d) a ## b ## c ## d
+#define LZO_PP_CONCAT5(a,b,c,d,e) a ## b ## c ## d ## e
+#define LZO_PP_ECONCAT2(a,b) LZO_PP_CONCAT2(a,b)
+#define LZO_PP_ECONCAT3(a,b,c) LZO_PP_CONCAT3(a,b,c)
+#define LZO_PP_ECONCAT4(a,b,c,d) LZO_PP_CONCAT4(a,b,c,d)
+#define LZO_PP_ECONCAT5(a,b,c,d,e) LZO_PP_CONCAT5(a,b,c,d,e)
+#if 1
+#define LZO_CPP_STRINGIZE(x) #x
+#define LZO_CPP_MACRO_EXPAND(x) LZO_CPP_STRINGIZE(x)
+#define LZO_CPP_CONCAT2(a,b) a ## b
+#define LZO_CPP_CONCAT3(a,b,c) a ## b ## c
+#define LZO_CPP_CONCAT4(a,b,c,d) a ## b ## c ## d
+#define LZO_CPP_CONCAT5(a,b,c,d,e) a ## b ## c ## d ## e
+#define LZO_CPP_ECONCAT2(a,b) LZO_CPP_CONCAT2(a,b)
+#define LZO_CPP_ECONCAT3(a,b,c) LZO_CPP_CONCAT3(a,b,c)
+#define LZO_CPP_ECONCAT4(a,b,c,d) LZO_CPP_CONCAT4(a,b,c,d)
+#define LZO_CPP_ECONCAT5(a,b,c,d,e) LZO_CPP_CONCAT5(a,b,c,d,e)
+#endif
+#define __LZO_MASK_GEN(o,b) (((((o) << ((b)-1)) - (o)) << 1) + (o))
+#if 1 && defined(__cplusplus)
+# if !defined(__STDC_CONSTANT_MACROS)
+# define __STDC_CONSTANT_MACROS 1
+# endif
+# if !defined(__STDC_LIMIT_MACROS)
+# define __STDC_LIMIT_MACROS 1
+# endif
+#endif
+#if defined(__cplusplus)
+# define LZO_EXTERN_C extern "C"
+#else
+# define LZO_EXTERN_C extern
+#endif
+#if !defined(__LZO_OS_OVERRIDE)
+#if defined(LZO_OS_FREESTANDING)
+# define LZO_INFO_OS "freestanding"
+#elif defined(LZO_OS_EMBEDDED)
+# define LZO_INFO_OS "embedded"
+#elif 1 && defined(__IAR_SYSTEMS_ICC__)
+# define LZO_OS_EMBEDDED 1
+# define LZO_INFO_OS "embedded"
+#elif defined(__CYGWIN__) && defined(__GNUC__)
+# define LZO_OS_CYGWIN 1
+# define LZO_INFO_OS "cygwin"
+#elif defined(__EMX__) && defined(__GNUC__)
+# define LZO_OS_EMX 1
+# define LZO_INFO_OS "emx"
+#elif defined(__BEOS__)
+# define LZO_OS_BEOS 1
+# define LZO_INFO_OS "beos"
+#elif defined(__Lynx__)
+# define LZO_OS_LYNXOS 1
+# define LZO_INFO_OS "lynxos"
+#elif defined(__OS400__)
+# define LZO_OS_OS400 1
+# define LZO_INFO_OS "os400"
+#elif defined(__QNX__)
+# define LZO_OS_QNX 1
+# define LZO_INFO_OS "qnx"
+#elif defined(__BORLANDC__) && defined(__DPMI32__) && (__BORLANDC__ >= 0x0460)
+# define LZO_OS_DOS32 1
+# define LZO_INFO_OS "dos32"
+#elif defined(__BORLANDC__) && defined(__DPMI16__)
+# define LZO_OS_DOS16 1
+# define LZO_INFO_OS "dos16"
+#elif defined(__ZTC__) && defined(DOS386)
+# define LZO_OS_DOS32 1
+# define LZO_INFO_OS "dos32"
+#elif defined(__OS2__) || defined(__OS2V2__)
+# if (UINT_MAX == LZO_0xffffL)
+# define LZO_OS_OS216 1
+# define LZO_INFO_OS "os216"
+# elif (UINT_MAX == LZO_0xffffffffL)
+# define LZO_OS_OS2 1
+# define LZO_INFO_OS "os2"
+# else
+# error "check your limits.h header"
+# endif
+#elif defined(__WIN64__) || defined(_WIN64) || defined(WIN64)
+# define LZO_OS_WIN64 1
+# define LZO_INFO_OS "win64"
+#elif defined(__WIN32__) || defined(_WIN32) || defined(WIN32) || defined(__WINDOWS_386__)
+# define LZO_OS_WIN32 1
+# define LZO_INFO_OS "win32"
+#elif defined(__MWERKS__) && defined(__INTEL__)
+# define LZO_OS_WIN32 1
+# define LZO_INFO_OS "win32"
+#elif defined(__WINDOWS__) || defined(_WINDOWS) || defined(_Windows)
+# if (UINT_MAX == LZO_0xffffL)
+# define LZO_OS_WIN16 1
+# define LZO_INFO_OS "win16"
+# elif (UINT_MAX == LZO_0xffffffffL)
+# define LZO_OS_WIN32 1
+# define LZO_INFO_OS "win32"
+# else
+# error "check your limits.h header"
+# endif
+#elif defined(__DOS__) || defined(__MSDOS__) || defined(_MSDOS) || defined(MSDOS) || (defined(__PACIFIC__) && defined(DOS))
+# if (UINT_MAX == LZO_0xffffL)
+# define LZO_OS_DOS16 1
+# define LZO_INFO_OS "dos16"
+# elif (UINT_MAX == LZO_0xffffffffL)
+# define LZO_OS_DOS32 1
+# define LZO_INFO_OS "dos32"
+# else
+# error "check your limits.h header"
+# endif
+#elif defined(__WATCOMC__)
+# if defined(__NT__) && (UINT_MAX == LZO_0xffffL)
+# define LZO_OS_DOS16 1
+# define LZO_INFO_OS "dos16"
+# elif defined(__NT__) && (__WATCOMC__ < 1100)
+# define LZO_OS_WIN32 1
+# define LZO_INFO_OS "win32"
+# elif defined(__linux__) || defined(__LINUX__)
+# define LZO_OS_POSIX 1
+# define LZO_INFO_OS "posix"
+# else
+# error "please specify a target using the -bt compiler option"
+# endif
+#elif defined(__palmos__)
+# define LZO_OS_PALMOS 1
+# define LZO_INFO_OS "palmos"
+#elif defined(__TOS__) || defined(__atarist__)
+# define LZO_OS_TOS 1
+# define LZO_INFO_OS "tos"
+#elif defined(macintosh) && !defined(__ppc__)
+# define LZO_OS_MACCLASSIC 1
+# define LZO_INFO_OS "macclassic"
+#elif defined(__VMS)
+# define LZO_OS_VMS 1
+# define LZO_INFO_OS "vms"
+#elif ((defined(__mips__) && defined(__R5900__)) || defined(__MIPS_PSX2__))
+# define LZO_OS_CONSOLE 1
+# define LZO_OS_CONSOLE_PS2 1
+# define LZO_INFO_OS "console"
+# define LZO_INFO_OS_CONSOLE "ps2"
+#elif (defined(__mips__) && defined(__psp__))
+# define LZO_OS_CONSOLE 1
+# define LZO_OS_CONSOLE_PSP 1
+# define LZO_INFO_OS "console"
+# define LZO_INFO_OS_CONSOLE "psp"
+#else
+# define LZO_OS_POSIX 1
+# define LZO_INFO_OS "posix"
+#endif
+#if (LZO_OS_POSIX)
+# if defined(_AIX) || defined(__AIX__) || defined(__aix__)
+# define LZO_OS_POSIX_AIX 1
+# define LZO_INFO_OS_POSIX "aix"
+# elif defined(__FreeBSD__)
+# define LZO_OS_POSIX_FREEBSD 1
+# define LZO_INFO_OS_POSIX "freebsd"
+# elif defined(__hpux__) || defined(__hpux)
+# define LZO_OS_POSIX_HPUX 1
+# define LZO_INFO_OS_POSIX "hpux"
+# elif defined(__INTERIX)
+# define LZO_OS_POSIX_INTERIX 1
+# define LZO_INFO_OS_POSIX "interix"
+# elif defined(__IRIX__) || defined(__irix__)
+# define LZO_OS_POSIX_IRIX 1
+# define LZO_INFO_OS_POSIX "irix"
+# elif defined(__linux__) || defined(__linux) || defined(__LINUX__)
+# define LZO_OS_POSIX_LINUX 1
+# define LZO_INFO_OS_POSIX "linux"
+# elif defined(__APPLE__) || defined(__MACOS__)
+# define LZO_OS_POSIX_MACOSX 1
+# define LZO_INFO_OS_POSIX "macosx"
+# elif defined(__minix__) || defined(__minix)
+# define LZO_OS_POSIX_MINIX 1
+# define LZO_INFO_OS_POSIX "minix"
+# elif defined(__NetBSD__)
+# define LZO_OS_POSIX_NETBSD 1
+# define LZO_INFO_OS_POSIX "netbsd"
+# elif defined(__OpenBSD__)
+# define LZO_OS_POSIX_OPENBSD 1
+# define LZO_INFO_OS_POSIX "openbsd"
+# elif defined(__osf__)
+# define LZO_OS_POSIX_OSF 1
+# define LZO_INFO_OS_POSIX "osf"
+# elif defined(__solaris__) || defined(__sun)
+# if defined(__SVR4) || defined(__svr4__)
+# define LZO_OS_POSIX_SOLARIS 1
+# define LZO_INFO_OS_POSIX "solaris"
+# else
+# define LZO_OS_POSIX_SUNOS 1
+# define LZO_INFO_OS_POSIX "sunos"
+# endif
+# elif defined(__ultrix__) || defined(__ultrix)
+# define LZO_OS_POSIX_ULTRIX 1
+# define LZO_INFO_OS_POSIX "ultrix"
+# elif defined(_UNICOS)
+# define LZO_OS_POSIX_UNICOS 1
+# define LZO_INFO_OS_POSIX "unicos"
+# else
+# define LZO_OS_POSIX_UNKNOWN 1
+# define LZO_INFO_OS_POSIX "unknown"
+# endif
+#endif
+#endif
+#if (LZO_OS_DOS16 || LZO_OS_OS216 || LZO_OS_WIN16)
+# if (UINT_MAX != LZO_0xffffL)
+# error "this should not happen"
+# endif
+# if (ULONG_MAX != LZO_0xffffffffL)
+# error "this should not happen"
+# endif
+#endif
+#if (LZO_OS_DOS32 || LZO_OS_OS2 || LZO_OS_WIN32 || LZO_OS_WIN64)
+# if (UINT_MAX != LZO_0xffffffffL)
+# error "this should not happen"
+# endif
+# if (ULONG_MAX != LZO_0xffffffffL)
+# error "this should not happen"
+# endif
+#endif
+#if defined(CIL) && defined(_GNUCC) && defined(__GNUC__)
+# define LZO_CC_CILLY 1
+# define LZO_INFO_CC "Cilly"
+# if defined(__CILLY__)
+# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__CILLY__)
+# else
+# define LZO_INFO_CCVER "unknown"
+# endif
+#elif 0 && defined(SDCC) && defined(__VERSION__) && !defined(__GNUC__)
+# define LZO_CC_SDCC 1
+# define LZO_INFO_CC "sdcc"
+# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(SDCC)
+#elif defined(__PATHSCALE__) && defined(__PATHCC_PATCHLEVEL__)
+# define LZO_CC_PATHSCALE (__PATHCC__ * 0x10000L + __PATHCC_MINOR__ * 0x100 + __PATHCC_PATCHLEVEL__)
+# define LZO_INFO_CC "Pathscale C"
+# define LZO_INFO_CCVER __PATHSCALE__
+#elif defined(__INTEL_COMPILER)
+# define LZO_CC_INTELC 1
+# define LZO_INFO_CC "Intel C"
+# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__INTEL_COMPILER)
+# if defined(_WIN32) || defined(_WIN64)
+# define LZO_CC_SYNTAX_MSC 1
+# else
+# define LZO_CC_SYNTAX_GNUC 1
+# endif
+#elif defined(__POCC__) && defined(_WIN32)
+# define LZO_CC_PELLESC 1
+# define LZO_INFO_CC "Pelles C"
+# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__POCC__)
+#elif defined(__llvm__) && defined(__GNUC__) && defined(__VERSION__)
+# if defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__)
+# define LZO_CC_LLVM (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100 + __GNUC_PATCHLEVEL__)
+# else
+# define LZO_CC_LLVM (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100)
+# endif
+# define LZO_INFO_CC "llvm-gcc"
+# define LZO_INFO_CCVER __VERSION__
+#elif defined(__GNUC__) && defined(__VERSION__)
+# if defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__)
+# define LZO_CC_GNUC (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100 + __GNUC_PATCHLEVEL__)
+# elif defined(__GNUC_MINOR__)
+# define LZO_CC_GNUC (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100)
+# else
+# define LZO_CC_GNUC (__GNUC__ * 0x10000L)
+# endif
+# define LZO_INFO_CC "gcc"
+# define LZO_INFO_CCVER __VERSION__
+#elif defined(__ACK__) && defined(_ACK)
+# define LZO_CC_ACK 1
+# define LZO_INFO_CC "Amsterdam Compiler Kit C"
+# define LZO_INFO_CCVER "unknown"
+#elif defined(__AZTEC_C__)
+# define LZO_CC_AZTECC 1
+# define LZO_INFO_CC "Aztec C"
+# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__AZTEC_C__)
+#elif defined(__BORLANDC__)
+# define LZO_CC_BORLANDC 1
+# define LZO_INFO_CC "Borland C"
+# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__BORLANDC__)
+#elif defined(_CRAYC) && defined(_RELEASE)
+# define LZO_CC_CRAYC 1
+# define LZO_INFO_CC "Cray C"
+# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(_RELEASE)
+#elif defined(__DMC__) && defined(__SC__)
+# define LZO_CC_DMC 1
+# define LZO_INFO_CC "Digital Mars C"
+# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__DMC__)
+#elif defined(__DECC)
+# define LZO_CC_DECC 1
+# define LZO_INFO_CC "DEC C"
+# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__DECC)
+#elif defined(__HIGHC__)
+# define LZO_CC_HIGHC 1
+# define LZO_INFO_CC "MetaWare High C"
+# define LZO_INFO_CCVER "unknown"
+#elif defined(__IAR_SYSTEMS_ICC__)
+# define LZO_CC_IARC 1
+# define LZO_INFO_CC "IAR C"
+# if defined(__VER__)
+# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__VER__)
+# else
+# define LZO_INFO_CCVER "unknown"
+# endif
+#elif defined(__IBMC__)
+# define LZO_CC_IBMC 1
+# define LZO_INFO_CC "IBM C"
+# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__IBMC__)
+#elif defined(__KEIL__) && defined(__C166__)
+# define LZO_CC_KEILC 1
+# define LZO_INFO_CC "Keil C"
+# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__C166__)
+#elif defined(__LCC__) && defined(_WIN32) && defined(__LCCOPTIMLEVEL)
+# define LZO_CC_LCCWIN32 1
+# define LZO_INFO_CC "lcc-win32"
+# define LZO_INFO_CCVER "unknown"
+#elif defined(__LCC__)
+# define LZO_CC_LCC 1
+# define LZO_INFO_CC "lcc"
+# if defined(__LCC_VERSION__)
+# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__LCC_VERSION__)
+# else
+# define LZO_INFO_CCVER "unknown"
+# endif
+#elif defined(_MSC_VER)
+# define LZO_CC_MSC 1
+# define LZO_INFO_CC "Microsoft C"
+# if defined(_MSC_FULL_VER)
+# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(_MSC_VER) "." LZO_PP_MACRO_EXPAND(_MSC_FULL_VER)
+# else
+# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(_MSC_VER)
+# endif
+#elif defined(__MWERKS__)
+# define LZO_CC_MWERKS 1
+# define LZO_INFO_CC "Metrowerks C"
+# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__MWERKS__)
+#elif (defined(__NDPC__) || defined(__NDPX__)) && defined(__i386)
+# define LZO_CC_NDPC 1
+# define LZO_INFO_CC "Microway NDP C"
+# define LZO_INFO_CCVER "unknown"
+#elif defined(__PACIFIC__)
+# define LZO_CC_PACIFICC 1
+# define LZO_INFO_CC "Pacific C"
+# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__PACIFIC__)
+#elif defined(__PGI) && (defined(__linux__) || defined(__WIN32__))
+# define LZO_CC_PGI 1
+# define LZO_INFO_CC "Portland Group PGI C"
+# define LZO_INFO_CCVER "unknown"
+#elif defined(__PUREC__) && defined(__TOS__)
+# define LZO_CC_PUREC 1
+# define LZO_INFO_CC "Pure C"
+# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__PUREC__)
+#elif defined(__SC__) && defined(__ZTC__)
+# define LZO_CC_SYMANTECC 1
+# define LZO_INFO_CC "Symantec C"
+# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__SC__)
+#elif defined(__SUNPRO_C)
+# define LZO_INFO_CC "SunPro C"
+# if ((__SUNPRO_C)+0 > 0)
+# define LZO_CC_SUNPROC __SUNPRO_C
+# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__SUNPRO_C)
+# else
+# define LZO_CC_SUNPROC 1
+# define LZO_INFO_CCVER "unknown"
+# endif
+#elif defined(__SUNPRO_CC)
+# define LZO_INFO_CC "SunPro C"
+# if ((__SUNPRO_CC)+0 > 0)
+# define LZO_CC_SUNPROC __SUNPRO_CC
+# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__SUNPRO_CC)
+# else
+# define LZO_CC_SUNPROC 1
+# define LZO_INFO_CCVER "unknown"
+# endif
+#elif defined(__TINYC__)
+# define LZO_CC_TINYC 1
+# define LZO_INFO_CC "Tiny C"
+# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__TINYC__)
+#elif defined(__TSC__)
+# define LZO_CC_TOPSPEEDC 1
+# define LZO_INFO_CC "TopSpeed C"
+# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__TSC__)
+#elif defined(__WATCOMC__)
+# define LZO_CC_WATCOMC 1
+# define LZO_INFO_CC "Watcom C"
+# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__WATCOMC__)
+#elif defined(__TURBOC__)
+# define LZO_CC_TURBOC 1
+# define LZO_INFO_CC "Turbo C"
+# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__TURBOC__)
+#elif defined(__ZTC__)
+# define LZO_CC_ZORTECHC 1
+# define LZO_INFO_CC "Zortech C"
+# if (__ZTC__ == 0x310)
+# define LZO_INFO_CCVER "0x310"
+# else
+# define LZO_INFO_CCVER LZO_PP_MACRO_EXPAND(__ZTC__)
+# endif
+#else
+# define LZO_CC_UNKNOWN 1
+# define LZO_INFO_CC "unknown"
+# define LZO_INFO_CCVER "unknown"
+#endif
+#if 0 && (LZO_CC_MSC && (_MSC_VER >= 1200)) && !defined(_MSC_FULL_VER)
+# error "LZO_CC_MSC: _MSC_FULL_VER is not defined"
+#endif
+#if !defined(__LZO_ARCH_OVERRIDE) && !defined(LZO_ARCH_GENERIC) && defined(_CRAY)
+# if (UINT_MAX > LZO_0xffffffffL) && defined(_CRAY)
+# if defined(_CRAYMPP) || defined(_CRAYT3D) || defined(_CRAYT3E)
+# define LZO_ARCH_CRAY_MPP 1
+# elif defined(_CRAY1)
+# define LZO_ARCH_CRAY_PVP 1
+# endif
+# endif
+#endif
+#if !defined(__LZO_ARCH_OVERRIDE)
+#if defined(LZO_ARCH_GENERIC)
+# define LZO_INFO_ARCH "generic"
+#elif (LZO_OS_DOS16 || LZO_OS_OS216 || LZO_OS_WIN16)
+# define LZO_ARCH_I086 1
+# define LZO_ARCH_IA16 1
+# define LZO_INFO_ARCH "i086"
+#elif defined(__alpha__) || defined(__alpha) || defined(_M_ALPHA)
+# define LZO_ARCH_ALPHA 1
+# define LZO_INFO_ARCH "alpha"
+#elif (LZO_ARCH_CRAY_MPP) && (defined(_CRAYT3D) || defined(_CRAYT3E))
+# define LZO_ARCH_ALPHA 1
+# define LZO_INFO_ARCH "alpha"
+#elif defined(__amd64__) || defined(__x86_64__) || defined(_M_AMD64)
+# define LZO_ARCH_AMD64 1
+# define LZO_INFO_ARCH "amd64"
+#elif defined(__thumb__) || (defined(_M_ARM) && defined(_M_THUMB))
+# define LZO_ARCH_ARM 1
+# define LZO_ARCH_ARM_THUMB 1
+# define LZO_INFO_ARCH "arm_thumb"
+#elif defined(__IAR_SYSTEMS_ICC__) && defined(__ICCARM__)
+# define LZO_ARCH_ARM 1
+# if defined(__CPU_MODE__) && ((__CPU_MODE__)+0 == 1)
+# define LZO_ARCH_ARM_THUMB 1
+# define LZO_INFO_ARCH "arm_thumb"
+# elif defined(__CPU_MODE__) && ((__CPU_MODE__)+0 == 2)
+# define LZO_INFO_ARCH "arm"
+# else
+# define LZO_INFO_ARCH "arm"
+# endif
+#elif defined(__arm__) || defined(_M_ARM)
+# define LZO_ARCH_ARM 1
+# define LZO_INFO_ARCH "arm"
+#elif (UINT_MAX <= LZO_0xffffL) && defined(__AVR__)
+# define LZO_ARCH_AVR 1
+# define LZO_INFO_ARCH "avr"
+#elif defined(__bfin__)
+# define LZO_ARCH_BLACKFIN 1
+# define LZO_INFO_ARCH "blackfin"
+#elif (UINT_MAX == LZO_0xffffL) && defined(__C166__)
+# define LZO_ARCH_C166 1
+# define LZO_INFO_ARCH "c166"
+#elif defined(__cris__)
+# define LZO_ARCH_CRIS 1
+# define LZO_INFO_ARCH "cris"
+#elif defined(__IAR_SYSTEMS_ICC__) && defined(__ICCEZ80__)
+# define LZO_ARCH_EZ80 1
+# define LZO_INFO_ARCH "ez80"
+#elif defined(__H8300__) || defined(__H8300H__) || defined(__H8300S__) || defined(__H8300SX__)
+# define LZO_ARCH_H8300 1
+# define LZO_INFO_ARCH "h8300"
+#elif defined(__hppa__) || defined(__hppa)
+# define LZO_ARCH_HPPA 1
+# define LZO_INFO_ARCH "hppa"
+#elif defined(__386__) || defined(__i386__) || defined(__i386) || defined(_M_IX86) || defined(_M_I386)
+# define LZO_ARCH_I386 1
+# define LZO_ARCH_IA32 1
+# define LZO_INFO_ARCH "i386"
+#elif (LZO_CC_ZORTECHC && defined(__I86__))
+# define LZO_ARCH_I386 1
+# define LZO_ARCH_IA32 1
+# define LZO_INFO_ARCH "i386"
+#elif (LZO_OS_DOS32 && LZO_CC_HIGHC) && defined(_I386)
+# define LZO_ARCH_I386 1
+# define LZO_ARCH_IA32 1
+# define LZO_INFO_ARCH "i386"
+#elif defined(__ia64__) || defined(__ia64) || defined(_M_IA64)
+# define LZO_ARCH_IA64 1
+# define LZO_INFO_ARCH "ia64"
+#elif (UINT_MAX == LZO_0xffffL) && defined(__m32c__)
+# define LZO_ARCH_M16C 1
+# define LZO_INFO_ARCH "m16c"
+#elif defined(__IAR_SYSTEMS_ICC__) && defined(__ICCM16C__)
+# define LZO_ARCH_M16C 1
+# define LZO_INFO_ARCH "m16c"
+#elif defined(__m32r__)
+# define LZO_ARCH_M32R 1
+# define LZO_INFO_ARCH "m32r"
+#elif (LZO_OS_TOS) || defined(__m68k__) || defined(__m68000__) || defined(__mc68000__) || defined(__mc68020__) || defined(_M_M68K)
+# define LZO_ARCH_M68K 1
+# define LZO_INFO_ARCH "m68k"
+#elif (UINT_MAX == LZO_0xffffL) && defined(__C251__)
+# define LZO_ARCH_MCS251 1
+# define LZO_INFO_ARCH "mcs251"
+#elif (UINT_MAX == LZO_0xffffL) && defined(__C51__)
+# define LZO_ARCH_MCS51 1
+# define LZO_INFO_ARCH "mcs51"
+#elif defined(__IAR_SYSTEMS_ICC__) && defined(__ICC8051__)
+# define LZO_ARCH_MCS51 1
+# define LZO_INFO_ARCH "mcs51"
+#elif defined(__mips__) || defined(__mips) || defined(_MIPS_ARCH) || defined(_M_MRX000)
+# define LZO_ARCH_MIPS 1
+# define LZO_INFO_ARCH "mips"
+#elif (UINT_MAX == LZO_0xffffL) && defined(__MSP430__)
+# define LZO_ARCH_MSP430 1
+# define LZO_INFO_ARCH "msp430"
+#elif defined(__IAR_SYSTEMS_ICC__) && defined(__ICC430__)
+# define LZO_ARCH_MSP430 1
+# define LZO_INFO_ARCH "msp430"
+#elif defined(__powerpc__) || defined(__powerpc) || defined(__ppc__) || defined(__PPC__) || defined(_M_PPC) || defined(_ARCH_PPC) || defined(_ARCH_PWR)
+# define LZO_ARCH_POWERPC 1
+# define LZO_INFO_ARCH "powerpc"
+#elif defined(__s390__) || defined(__s390) || defined(__s390x__) || defined(__s390x)
+# define LZO_ARCH_S390 1
+# define LZO_INFO_ARCH "s390"
+#elif defined(__sh__) || defined(_M_SH)
+# define LZO_ARCH_SH 1
+# define LZO_INFO_ARCH "sh"
+#elif defined(__sparc__) || defined(__sparc) || defined(__sparcv8)
+# define LZO_ARCH_SPARC 1
+# define LZO_INFO_ARCH "sparc"
+#elif defined(__SPU__)
+# define LZO_ARCH_SPU 1
+# define LZO_INFO_ARCH "spu"
+#elif (UINT_MAX == LZO_0xffffL) && defined(__z80)
+# define LZO_ARCH_Z80 1
+# define LZO_INFO_ARCH "z80"
+#elif (LZO_ARCH_CRAY_PVP)
+# if defined(_CRAYSV1)
+# define LZO_ARCH_CRAY_SV1 1
+# define LZO_INFO_ARCH "cray_sv1"
+# elif (_ADDR64)
+# define LZO_ARCH_CRAY_T90 1
+# define LZO_INFO_ARCH "cray_t90"
+# elif (_ADDR32)
+# define LZO_ARCH_CRAY_YMP 1
+# define LZO_INFO_ARCH "cray_ymp"
+# else
+# define LZO_ARCH_CRAY_XMP 1
+# define LZO_INFO_ARCH "cray_xmp"
+# endif
+#else
+# define LZO_ARCH_UNKNOWN 1
+# define LZO_INFO_ARCH "unknown"
+#endif
+#endif
+#if 1 && (LZO_ARCH_UNKNOWN) && (LZO_OS_DOS32 || LZO_OS_OS2)
+# error "FIXME - missing define for CPU architecture"
+#endif
+#if 1 && (LZO_ARCH_UNKNOWN) && (LZO_OS_WIN32)
+# error "FIXME - missing WIN32 define for CPU architecture"
+#endif
+#if 1 && (LZO_ARCH_UNKNOWN) && (LZO_OS_WIN64)
+# error "FIXME - missing WIN64 define for CPU architecture"
+#endif
+#if (LZO_OS_OS216 || LZO_OS_WIN16)
+# define LZO_ARCH_I086PM 1
+# define LZO_ARCH_IA16PM 1
+#elif 1 && (LZO_OS_DOS16 && defined(BLX286))
+# define LZO_ARCH_I086PM 1
+# define LZO_ARCH_IA16PM 1
+#elif 1 && (LZO_OS_DOS16 && defined(DOSX286))
+# define LZO_ARCH_I086PM 1
+# define LZO_ARCH_IA16PM 1
+#elif 1 && (LZO_OS_DOS16 && LZO_CC_BORLANDC && defined(__DPMI16__))
+# define LZO_ARCH_I086PM 1
+# define LZO_ARCH_IA16PM 1
+#endif
+#if defined(LZO_ARCH_ARM_THUMB) && !defined(LZO_ARCH_ARM)
+# error "this should not happen"
+#endif
+#if defined(LZO_ARCH_I086PM) && !defined(LZO_ARCH_I086)
+# error "this should not happen"
+#endif
+#if (LZO_ARCH_I086)
+# if (UINT_MAX != LZO_0xffffL)
+# error "this should not happen"
+# endif
+# if (ULONG_MAX != LZO_0xffffffffL)
+# error "this should not happen"
+# endif
+#endif
+#if (LZO_ARCH_I386)
+# if (UINT_MAX != LZO_0xffffL) && defined(__i386_int16__)
+# error "this should not happen"
+# endif
+# if (UINT_MAX != LZO_0xffffffffL) && !defined(__i386_int16__)
+# error "this should not happen"
+# endif
+# if (ULONG_MAX != LZO_0xffffffffL)
+# error "this should not happen"
+# endif
+#endif
+#if !defined(__LZO_MM_OVERRIDE)
+#if (LZO_ARCH_I086)
+#if (UINT_MAX != LZO_0xffffL)
+# error "this should not happen"
+#endif
+#if defined(__TINY__) || defined(M_I86TM) || defined(_M_I86TM)
+# define LZO_MM_TINY 1
+#elif defined(__HUGE__) || defined(_HUGE_) || defined(M_I86HM) || defined(_M_I86HM)
+# define LZO_MM_HUGE 1
+#elif defined(__SMALL__) || defined(M_I86SM) || defined(_M_I86SM) || defined(SMALL_MODEL)
+# define LZO_MM_SMALL 1
+#elif defined(__MEDIUM__) || defined(M_I86MM) || defined(_M_I86MM)
+# define LZO_MM_MEDIUM 1
+#elif defined(__COMPACT__) || defined(M_I86CM) || defined(_M_I86CM)
+# define LZO_MM_COMPACT 1
+#elif defined(__LARGE__) || defined(M_I86LM) || defined(_M_I86LM) || defined(LARGE_MODEL)
+# define LZO_MM_LARGE 1
+#elif (LZO_CC_AZTECC)
+# if defined(_LARGE_CODE) && defined(_LARGE_DATA)
+# define LZO_MM_LARGE 1
+# elif defined(_LARGE_CODE)
+# define LZO_MM_MEDIUM 1
+# elif defined(_LARGE_DATA)
+# define LZO_MM_COMPACT 1
+# else
+# define LZO_MM_SMALL 1
+# endif
+#elif (LZO_CC_ZORTECHC && defined(__VCM__))
+# define LZO_MM_LARGE 1
+#else
+# error "unknown memory model"
+#endif
+#if (LZO_OS_DOS16 || LZO_OS_OS216 || LZO_OS_WIN16)
+#define LZO_HAVE_MM_HUGE_PTR 1
+#define LZO_HAVE_MM_HUGE_ARRAY 1
+#if (LZO_MM_TINY)
+# undef LZO_HAVE_MM_HUGE_ARRAY
+#endif
+#if (LZO_CC_AZTECC || LZO_CC_PACIFICC || LZO_CC_ZORTECHC)
+# undef LZO_HAVE_MM_HUGE_PTR
+# undef LZO_HAVE_MM_HUGE_ARRAY
+#elif (LZO_CC_DMC || LZO_CC_SYMANTECC)
+# undef LZO_HAVE_MM_HUGE_ARRAY
+#elif (LZO_CC_MSC && defined(_QC))
+# undef LZO_HAVE_MM_HUGE_ARRAY
+# if (_MSC_VER < 600)
+# undef LZO_HAVE_MM_HUGE_PTR
+# endif
+#elif (LZO_CC_TURBOC && (__TURBOC__ < 0x0295))
+# undef LZO_HAVE_MM_HUGE_ARRAY
+#endif
+#if (LZO_ARCH_I086PM) && !defined(LZO_HAVE_MM_HUGE_PTR)
+# if (LZO_OS_DOS16)
+# error "this should not happen"
+# elif (LZO_CC_ZORTECHC)
+# else
+# error "this should not happen"
+# endif
+#endif
+#ifdef __cplusplus
+extern "C" {
+#endif
+#if (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0200))
+ extern void __near __cdecl _AHSHIFT(void);
+# define LZO_MM_AHSHIFT ((unsigned) _AHSHIFT)
+#elif (LZO_CC_DMC || LZO_CC_SYMANTECC || LZO_CC_ZORTECHC)
+ extern void __near __cdecl _AHSHIFT(void);
+# define LZO_MM_AHSHIFT ((unsigned) _AHSHIFT)
+#elif (LZO_CC_MSC || LZO_CC_TOPSPEEDC)
+ extern void __near __cdecl _AHSHIFT(void);
+# define LZO_MM_AHSHIFT ((unsigned) _AHSHIFT)
+#elif (LZO_CC_TURBOC && (__TURBOC__ >= 0x0295))
+ extern void __near __cdecl _AHSHIFT(void);
+# define LZO_MM_AHSHIFT ((unsigned) _AHSHIFT)
+#elif ((LZO_CC_AZTECC || LZO_CC_PACIFICC || LZO_CC_TURBOC) && LZO_OS_DOS16)
+# define LZO_MM_AHSHIFT 12
+#elif (LZO_CC_WATCOMC)
+ extern unsigned char _HShift;
+# define LZO_MM_AHSHIFT ((unsigned) _HShift)
+#else
+# error "FIXME - implement LZO_MM_AHSHIFT"
+#endif
+#ifdef __cplusplus
+}
+#endif
+#endif
+#elif (LZO_ARCH_C166)
+#if !defined(__MODEL__)
+# error "FIXME - C166 __MODEL__"
+#elif ((__MODEL__) == 0)
+# define LZO_MM_SMALL 1
+#elif ((__MODEL__) == 1)
+# define LZO_MM_SMALL 1
+#elif ((__MODEL__) == 2)
+# define LZO_MM_LARGE 1
+#elif ((__MODEL__) == 3)
+# define LZO_MM_TINY 1
+#elif ((__MODEL__) == 4)
+# define LZO_MM_XTINY 1
+#elif ((__MODEL__) == 5)
+# define LZO_MM_XSMALL 1
+#else
+# error "FIXME - C166 __MODEL__"
+#endif
+#elif (LZO_ARCH_MCS251)
+#if !defined(__MODEL__)
+# error "FIXME - MCS251 __MODEL__"
+#elif ((__MODEL__) == 0)
+# define LZO_MM_SMALL 1
+#elif ((__MODEL__) == 2)
+# define LZO_MM_LARGE 1
+#elif ((__MODEL__) == 3)
+# define LZO_MM_TINY 1
+#elif ((__MODEL__) == 4)
+# define LZO_MM_XTINY 1
+#elif ((__MODEL__) == 5)
+# define LZO_MM_XSMALL 1
+#else
+# error "FIXME - MCS251 __MODEL__"
+#endif
+#elif (LZO_ARCH_MCS51)
+#if !defined(__MODEL__)
+# error "FIXME - MCS51 __MODEL__"
+#elif ((__MODEL__) == 1)
+# define LZO_MM_SMALL 1
+#elif ((__MODEL__) == 2)
+# define LZO_MM_LARGE 1
+#elif ((__MODEL__) == 3)
+# define LZO_MM_TINY 1
+#elif ((__MODEL__) == 4)
+# define LZO_MM_XTINY 1
+#elif ((__MODEL__) == 5)
+# define LZO_MM_XSMALL 1
+#else
+# error "FIXME - MCS51 __MODEL__"
+#endif
+#elif (LZO_ARCH_CRAY_PVP)
+# define LZO_MM_PVP 1
+#else
+# define LZO_MM_FLAT 1
+#endif
+#if (LZO_MM_COMPACT)
+# define LZO_INFO_MM "compact"
+#elif (LZO_MM_FLAT)
+# define LZO_INFO_MM "flat"
+#elif (LZO_MM_HUGE)
+# define LZO_INFO_MM "huge"
+#elif (LZO_MM_LARGE)
+# define LZO_INFO_MM "large"
+#elif (LZO_MM_MEDIUM)
+# define LZO_INFO_MM "medium"
+#elif (LZO_MM_PVP)
+# define LZO_INFO_MM "pvp"
+#elif (LZO_MM_SMALL)
+# define LZO_INFO_MM "small"
+#elif (LZO_MM_TINY)
+# define LZO_INFO_MM "tiny"
+#else
+# error "unknown memory model"
+#endif
+#endif
+#if defined(SIZEOF_SHORT)
+# define LZO_SIZEOF_SHORT (SIZEOF_SHORT)
+#endif
+#if defined(SIZEOF_INT)
+# define LZO_SIZEOF_INT (SIZEOF_INT)
+#endif
+#if defined(SIZEOF_LONG)
+# define LZO_SIZEOF_LONG (SIZEOF_LONG)
+#endif
+#if defined(SIZEOF_LONG_LONG)
+# define LZO_SIZEOF_LONG_LONG (SIZEOF_LONG_LONG)
+#endif
+#if defined(SIZEOF___INT16)
+# define LZO_SIZEOF___INT16 (SIZEOF___INT16)
+#endif
+#if defined(SIZEOF___INT32)
+# define LZO_SIZEOF___INT32 (SIZEOF___INT32)
+#endif
+#if defined(SIZEOF___INT64)
+# define LZO_SIZEOF___INT64 (SIZEOF___INT64)
+#endif
+#if defined(SIZEOF_VOID_P)
+# define LZO_SIZEOF_VOID_P (SIZEOF_VOID_P)
+#endif
+#if defined(SIZEOF_SIZE_T)
+# define LZO_SIZEOF_SIZE_T (SIZEOF_SIZE_T)
+#endif
+#if defined(SIZEOF_PTRDIFF_T)
+# define LZO_SIZEOF_PTRDIFF_T (SIZEOF_PTRDIFF_T)
+#endif
+#define __LZO_LSR(x,b) (((x)+0ul) >> (b))
+#if !defined(LZO_SIZEOF_SHORT)
+# if (LZO_ARCH_CRAY_PVP)
+# define LZO_SIZEOF_SHORT 8
+# elif (USHRT_MAX == LZO_0xffffL)
+# define LZO_SIZEOF_SHORT 2
+# elif (__LZO_LSR(USHRT_MAX,7) == 1)
+# define LZO_SIZEOF_SHORT 1
+# elif (__LZO_LSR(USHRT_MAX,15) == 1)
+# define LZO_SIZEOF_SHORT 2
+# elif (__LZO_LSR(USHRT_MAX,31) == 1)
+# define LZO_SIZEOF_SHORT 4
+# elif (__LZO_LSR(USHRT_MAX,63) == 1)
+# define LZO_SIZEOF_SHORT 8
+# elif (__LZO_LSR(USHRT_MAX,127) == 1)
+# define LZO_SIZEOF_SHORT 16
+# else
+# error "LZO_SIZEOF_SHORT"
+# endif
+#endif
+#if !defined(LZO_SIZEOF_INT)
+# if (LZO_ARCH_CRAY_PVP)
+# define LZO_SIZEOF_INT 8
+# elif (UINT_MAX == LZO_0xffffL)
+# define LZO_SIZEOF_INT 2
+# elif (UINT_MAX == LZO_0xffffffffL)
+# define LZO_SIZEOF_INT 4
+# elif (__LZO_LSR(UINT_MAX,7) == 1)
+# define LZO_SIZEOF_INT 1
+# elif (__LZO_LSR(UINT_MAX,15) == 1)
+# define LZO_SIZEOF_INT 2
+# elif (__LZO_LSR(UINT_MAX,31) == 1)
+# define LZO_SIZEOF_INT 4
+# elif (__LZO_LSR(UINT_MAX,63) == 1)
+# define LZO_SIZEOF_INT 8
+# elif (__LZO_LSR(UINT_MAX,127) == 1)
+# define LZO_SIZEOF_INT 16
+# else
+# error "LZO_SIZEOF_INT"
+# endif
+#endif
+#if !defined(LZO_SIZEOF_LONG)
+# if (ULONG_MAX == LZO_0xffffffffL)
+# define LZO_SIZEOF_LONG 4
+# elif (__LZO_LSR(ULONG_MAX,7) == 1)
+# define LZO_SIZEOF_LONG 1
+# elif (__LZO_LSR(ULONG_MAX,15) == 1)
+# define LZO_SIZEOF_LONG 2
+# elif (__LZO_LSR(ULONG_MAX,31) == 1)
+# define LZO_SIZEOF_LONG 4
+# elif (__LZO_LSR(ULONG_MAX,63) == 1)
+# define LZO_SIZEOF_LONG 8
+# elif (__LZO_LSR(ULONG_MAX,127) == 1)
+# define LZO_SIZEOF_LONG 16
+# else
+# error "LZO_SIZEOF_LONG"
+# endif
+#endif
+#if !defined(LZO_SIZEOF_LONG_LONG) && !defined(LZO_SIZEOF___INT64)
+#if (LZO_SIZEOF_LONG > 0 && LZO_SIZEOF_LONG < 8)
+# if defined(__LONG_MAX__) && defined(__LONG_LONG_MAX__)
+# if (LZO_CC_GNUC >= 0x030300ul)
+# if ((__LONG_MAX__)+0 == (__LONG_LONG_MAX__)+0)
+# define LZO_SIZEOF_LONG_LONG LZO_SIZEOF_LONG
+# elif (__LZO_LSR(__LONG_LONG_MAX__,30) == 1)
+# define LZO_SIZEOF_LONG_LONG 4
+# endif
+# endif
+# endif
+#endif
+#endif
+#if !defined(LZO_SIZEOF_LONG_LONG) && !defined(LZO_SIZEOF___INT64)
+#if (LZO_SIZEOF_LONG > 0 && LZO_SIZEOF_LONG < 8)
+#if (LZO_ARCH_I086 && LZO_CC_DMC)
+#elif (LZO_CC_CILLY) && defined(__GNUC__)
+# define LZO_SIZEOF_LONG_LONG 8
+#elif (LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE)
+# define LZO_SIZEOF_LONG_LONG 8
+#elif ((LZO_OS_WIN32 || LZO_OS_WIN64 || defined(_WIN32)) && LZO_CC_MSC && (_MSC_VER >= 1400))
+# define LZO_SIZEOF_LONG_LONG 8
+#elif (LZO_OS_WIN64 || defined(_WIN64))
+# define LZO_SIZEOF___INT64 8
+#elif (LZO_ARCH_I386 && (LZO_CC_DMC))
+# define LZO_SIZEOF_LONG_LONG 8
+#elif (LZO_ARCH_I386 && (LZO_CC_SYMANTECC && (__SC__ >= 0x700)))
+# define LZO_SIZEOF_LONG_LONG 8
+#elif (LZO_ARCH_I386 && (LZO_CC_INTELC && defined(__linux__)))
+# define LZO_SIZEOF_LONG_LONG 8
+#elif (LZO_ARCH_I386 && (LZO_CC_MWERKS || LZO_CC_PELLESC || LZO_CC_PGI || LZO_CC_SUNPROC))
+# define LZO_SIZEOF_LONG_LONG 8
+#elif (LZO_ARCH_I386 && (LZO_CC_INTELC || LZO_CC_MSC))
+# define LZO_SIZEOF___INT64 8
+#elif ((LZO_OS_WIN32 || defined(_WIN32)) && (LZO_CC_MSC))
+# define LZO_SIZEOF___INT64 8
+#elif (LZO_ARCH_I386 && (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0520)))
+# define LZO_SIZEOF___INT64 8
+#elif (LZO_ARCH_I386 && (LZO_CC_WATCOMC && (__WATCOMC__ >= 1100)))
+# define LZO_SIZEOF___INT64 8
+#elif (LZO_CC_WATCOMC && defined(_INTEGRAL_MAX_BITS) && (_INTEGRAL_MAX_BITS == 64))
+# define LZO_SIZEOF___INT64 8
+#elif (LZO_OS_OS400 || defined(__OS400__)) && defined(__LLP64_IFC__)
+# define LZO_SIZEOF_LONG_LONG 8
+#elif (defined(__vms) || defined(__VMS)) && (__INITIAL_POINTER_SIZE+0 == 64)
+# define LZO_SIZEOF_LONG_LONG 8
+#elif (LZO_CC_SDCC) && (LZO_SIZEOF_INT == 2)
+#elif 1 && defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
+# define LZO_SIZEOF_LONG_LONG 8
+#endif
+#endif
+#endif
+#if defined(__cplusplus) && defined(LZO_CC_GNUC)
+# if (LZO_CC_GNUC < 0x020800ul)
+# undef LZO_SIZEOF_LONG_LONG
+# endif
+#endif
+#if defined(LZO_CFG_NO_LONG_LONG) || defined(__NO_LONG_LONG)
+# undef LZO_SIZEOF_LONG_LONG
+#endif
+#if !defined(LZO_SIZEOF_VOID_P)
+#if (LZO_ARCH_I086)
+# define __LZO_WORDSIZE 2
+# if (LZO_MM_TINY || LZO_MM_SMALL || LZO_MM_MEDIUM)
+# define LZO_SIZEOF_VOID_P 2
+# elif (LZO_MM_COMPACT || LZO_MM_LARGE || LZO_MM_HUGE)
+# define LZO_SIZEOF_VOID_P 4
+# else
+# error "LZO_MM"
+# endif
+#elif (LZO_ARCH_AVR || LZO_ARCH_Z80)
+# define __LZO_WORDSIZE 1
+# define LZO_SIZEOF_VOID_P 2
+#elif (LZO_ARCH_C166 || LZO_ARCH_MCS51 || LZO_ARCH_MCS251 || LZO_ARCH_MSP430)
+# define LZO_SIZEOF_VOID_P 2
+#elif (LZO_ARCH_H8300)
+# if defined(__NORMAL_MODE__)
+# define __LZO_WORDSIZE 4
+# define LZO_SIZEOF_VOID_P 2
+# elif defined(__H8300H__) || defined(__H8300S__) || defined(__H8300SX__)
+# define __LZO_WORDSIZE 4
+# define LZO_SIZEOF_VOID_P 4
+# else
+# define __LZO_WORDSIZE 2
+# define LZO_SIZEOF_VOID_P 2
+# endif
+# if (LZO_CC_GNUC && (LZO_CC_GNUC < 0x040000ul)) && (LZO_SIZEOF_INT == 4)
+# define LZO_SIZEOF_SIZE_T LZO_SIZEOF_INT
+# define LZO_SIZEOF_PTRDIFF_T LZO_SIZEOF_INT
+# endif
+#elif (LZO_ARCH_M16C)
+# define __LZO_WORDSIZE 2
+# if defined(__m32c_cpu__) || defined(__m32cm_cpu__)
+# define LZO_SIZEOF_VOID_P 4
+# else
+# define LZO_SIZEOF_VOID_P 2
+# endif
+#elif (LZO_SIZEOF_LONG == 8) && ((defined(__mips__) && defined(__R5900__)) || defined(__MIPS_PSX2__))
+# define __LZO_WORDSIZE 8
+# define LZO_SIZEOF_VOID_P 4
+#elif defined(__LLP64__) || defined(__LLP64) || defined(_LLP64) || defined(_WIN64)
+# define __LZO_WORDSIZE 8
+# define LZO_SIZEOF_VOID_P 8
+#elif (LZO_OS_OS400 || defined(__OS400__)) && defined(__LLP64_IFC__)
+# define LZO_SIZEOF_VOID_P LZO_SIZEOF_LONG
+# define LZO_SIZEOF_SIZE_T LZO_SIZEOF_LONG
+# define LZO_SIZEOF_PTRDIFF_T LZO_SIZEOF_LONG
+#elif (LZO_OS_OS400 || defined(__OS400__))
+# define __LZO_WORDSIZE LZO_SIZEOF_LONG
+# define LZO_SIZEOF_VOID_P 16
+# define LZO_SIZEOF_SIZE_T LZO_SIZEOF_LONG
+# define LZO_SIZEOF_PTRDIFF_T LZO_SIZEOF_LONG
+#elif (defined(__vms) || defined(__VMS)) && (__INITIAL_POINTER_SIZE+0 == 64)
+# define LZO_SIZEOF_VOID_P 8
+# define LZO_SIZEOF_SIZE_T LZO_SIZEOF_LONG
+# define LZO_SIZEOF_PTRDIFF_T LZO_SIZEOF_LONG
+#elif (LZO_ARCH_SPU)
+# if 0
+# define __LZO_WORDSIZE 16
+# endif
+# define LZO_SIZEOF_VOID_P 4
+#else
+# define LZO_SIZEOF_VOID_P LZO_SIZEOF_LONG
+#endif
+#endif
+#if !defined(LZO_WORDSIZE)
+# if defined(__LZO_WORDSIZE)
+# define LZO_WORDSIZE __LZO_WORDSIZE
+# else
+# define LZO_WORDSIZE LZO_SIZEOF_VOID_P
+# endif
+#endif
+#if !defined(LZO_SIZEOF_SIZE_T)
+#if (LZO_ARCH_I086 || LZO_ARCH_M16C)
+# define LZO_SIZEOF_SIZE_T 2
+#else
+# define LZO_SIZEOF_SIZE_T LZO_SIZEOF_VOID_P
+#endif
+#endif
+#if !defined(LZO_SIZEOF_PTRDIFF_T)
+#if (LZO_ARCH_I086)
+# if (LZO_MM_TINY || LZO_MM_SMALL || LZO_MM_MEDIUM || LZO_MM_HUGE)
+# define LZO_SIZEOF_PTRDIFF_T LZO_SIZEOF_VOID_P
+# elif (LZO_MM_COMPACT || LZO_MM_LARGE)
+# if (LZO_CC_BORLANDC || LZO_CC_TURBOC)
+# define LZO_SIZEOF_PTRDIFF_T 4
+# else
+# define LZO_SIZEOF_PTRDIFF_T 2
+# endif
+# else
+# error "LZO_MM"
+# endif
+#else
+# define LZO_SIZEOF_PTRDIFF_T LZO_SIZEOF_SIZE_T
+#endif
+#endif
+#if defined(LZO_ABI_NEUTRAL_ENDIAN)
+# undef LZO_ABI_BIG_ENDIAN
+# undef LZO_ABI_LITTLE_ENDIAN
+#elif !defined(LZO_ABI_BIG_ENDIAN) && !defined(LZO_ABI_LITTLE_ENDIAN)
+#if (LZO_ARCH_ALPHA) && (LZO_ARCH_CRAY_MPP)
+# define LZO_ABI_BIG_ENDIAN 1
+#elif (LZO_ARCH_ALPHA || LZO_ARCH_AMD64 || LZO_ARCH_BLACKFIN || LZO_ARCH_CRIS || LZO_ARCH_I086 || LZO_ARCH_I386 || LZO_ARCH_MSP430)
+# define LZO_ABI_LITTLE_ENDIAN 1
+#elif (LZO_ARCH_M68K || LZO_ARCH_S390)
+# define LZO_ABI_BIG_ENDIAN 1
+#elif 1 && defined(__IAR_SYSTEMS_ICC__) && defined(__LITTLE_ENDIAN__)
+# if (__LITTLE_ENDIAN__ == 1)
+# define LZO_ABI_LITTLE_ENDIAN 1
+# else
+# define LZO_ABI_BIG_ENDIAN 1
+# endif
+#elif 1 && defined(__BIG_ENDIAN__) && !defined(__LITTLE_ENDIAN__)
+# define LZO_ABI_BIG_ENDIAN 1
+#elif 1 && defined(__LITTLE_ENDIAN__) && !defined(__BIG_ENDIAN__)
+# define LZO_ABI_LITTLE_ENDIAN 1
+#elif 1 && (LZO_ARCH_ARM) && defined(__ARMEB__) && !defined(__ARMEL__)
+# define LZO_ABI_BIG_ENDIAN 1
+#elif 1 && (LZO_ARCH_ARM) && defined(__ARMEL__) && !defined(__ARMEB__)
+# define LZO_ABI_LITTLE_ENDIAN 1
+#elif 1 && (LZO_ARCH_MIPS) && defined(__MIPSEB__) && !defined(__MIPSEL__)
+# define LZO_ABI_BIG_ENDIAN 1
+#elif 1 && (LZO_ARCH_MIPS) && defined(__MIPSEL__) && !defined(__MIPSEB__)
+# define LZO_ABI_LITTLE_ENDIAN 1
+#endif
+#endif
+#if defined(LZO_ABI_BIG_ENDIAN) && defined(LZO_ABI_LITTLE_ENDIAN)
+# error "this should not happen"
+#endif
+#if defined(LZO_ABI_BIG_ENDIAN)
+# define LZO_INFO_ABI_ENDIAN "be"
+#elif defined(LZO_ABI_LITTLE_ENDIAN)
+# define LZO_INFO_ABI_ENDIAN "le"
+#elif defined(LZO_ABI_NEUTRAL_ENDIAN)
+# define LZO_INFO_ABI_ENDIAN "neutral"
+#endif
+#if (LZO_SIZEOF_INT == 1 && LZO_SIZEOF_LONG == 2 && LZO_SIZEOF_VOID_P == 2)
+# define LZO_ABI_I8LP16 1
+# define LZO_INFO_ABI_PM "i8lp16"
+#elif (LZO_SIZEOF_INT == 2 && LZO_SIZEOF_LONG == 2 && LZO_SIZEOF_VOID_P == 2)
+# define LZO_ABI_ILP16 1
+# define LZO_INFO_ABI_PM "ilp16"
+#elif (LZO_SIZEOF_INT == 4 && LZO_SIZEOF_LONG == 4 && LZO_SIZEOF_VOID_P == 4)
+# define LZO_ABI_ILP32 1
+# define LZO_INFO_ABI_PM "ilp32"
+#elif (LZO_SIZEOF_INT == 4 && LZO_SIZEOF_LONG == 4 && LZO_SIZEOF_VOID_P == 8 && LZO_SIZEOF_SIZE_T == 8)
+# define LZO_ABI_LLP64 1
+# define LZO_INFO_ABI_PM "llp64"
+#elif (LZO_SIZEOF_INT == 4 && LZO_SIZEOF_LONG == 8 && LZO_SIZEOF_VOID_P == 8)
+# define LZO_ABI_LP64 1
+# define LZO_INFO_ABI_PM "lp64"
+#elif (LZO_SIZEOF_INT == 8 && LZO_SIZEOF_LONG == 8 && LZO_SIZEOF_VOID_P == 8)
+# define LZO_ABI_ILP64 1
+# define LZO_INFO_ABI_PM "ilp64"
+#elif (LZO_SIZEOF_INT == 4 && LZO_SIZEOF_LONG == 8 && LZO_SIZEOF_VOID_P == 4)
+# define LZO_ABI_IP32L64 1
+# define LZO_INFO_ABI_PM "ip32l64"
+#endif
+#if !defined(__LZO_LIBC_OVERRIDE)
+#if defined(LZO_LIBC_NAKED)
+# define LZO_INFO_LIBC "naked"
+#elif defined(LZO_LIBC_FREESTANDING)
+# define LZO_INFO_LIBC "freestanding"
+#elif defined(LZO_LIBC_MOSTLY_FREESTANDING)
+# define LZO_INFO_LIBC "mfreestanding"
+#elif defined(LZO_LIBC_ISOC90)
+# define LZO_INFO_LIBC "isoc90"
+#elif defined(LZO_LIBC_ISOC99)
+# define LZO_INFO_LIBC "isoc99"
+#elif defined(__dietlibc__)
+# define LZO_LIBC_DIETLIBC 1
+# define LZO_INFO_LIBC "dietlibc"
+#elif defined(_NEWLIB_VERSION)
+# define LZO_LIBC_NEWLIB 1
+# define LZO_INFO_LIBC "newlib"
+#elif defined(__UCLIBC__) && defined(__UCLIBC_MAJOR__) && defined(__UCLIBC_MINOR__)
+# if defined(__UCLIBC_SUBLEVEL__)
+# define LZO_LIBC_UCLIBC (__UCLIBC_MAJOR__ * 0x10000L + __UCLIBC_MINOR__ * 0x100 + __UCLIBC_SUBLEVEL__)
+# else
+# define LZO_LIBC_UCLIBC 0x00090bL
+# endif
+# define LZO_INFO_LIBC "uclibc"
+#elif defined(__GLIBC__) && defined(__GLIBC_MINOR__)
+# define LZO_LIBC_GLIBC (__GLIBC__ * 0x10000L + __GLIBC_MINOR__ * 0x100)
+# define LZO_INFO_LIBC "glibc"
+#elif (LZO_CC_MWERKS) && defined(__MSL__)
+# define LZO_LIBC_MSL __MSL__
+# define LZO_INFO_LIBC "msl"
+#elif 1 && defined(__IAR_SYSTEMS_ICC__)
+# define LZO_LIBC_ISOC90 1
+# define LZO_INFO_LIBC "isoc90"
+#else
+# define LZO_LIBC_DEFAULT 1
+# define LZO_INFO_LIBC "default"
+#endif
+#endif
+#if !defined(__lzo_gnuc_extension__)
+#if (LZO_CC_GNUC >= 0x020800ul)
+# define __lzo_gnuc_extension__ __extension__
+#elif (LZO_CC_LLVM || LZO_CC_PATHSCALE)
+# define __lzo_gnuc_extension__ __extension__
+#else
+# define __lzo_gnuc_extension__
+#endif
+#endif
+#if !defined(__lzo_ua_volatile)
+# define __lzo_ua_volatile volatile
+#endif
+#if !defined(__lzo_alignof)
+#if (LZO_CC_CILLY || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE || LZO_CC_PGI)
+# define __lzo_alignof(e) __alignof__(e)
+#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 700))
+# define __lzo_alignof(e) __alignof__(e)
+#elif (LZO_CC_MSC && (_MSC_VER >= 1300))
+# define __lzo_alignof(e) __alignof(e)
+#endif
+#endif
+#if defined(__lzo_alignof)
+# define __lzo_HAVE_alignof 1
+#endif
+#if !defined(__lzo_constructor)
+#if (LZO_CC_GNUC >= 0x030400ul)
+# define __lzo_constructor __attribute__((__constructor__,__used__))
+#elif (LZO_CC_GNUC >= 0x020700ul)
+# define __lzo_constructor __attribute__((__constructor__))
+#elif (LZO_CC_LLVM || LZO_CC_PATHSCALE)
+# define __lzo_constructor __attribute__((__constructor__))
+#endif
+#endif
+#if defined(__lzo_constructor)
+# define __lzo_HAVE_constructor 1
+#endif
+#if !defined(__lzo_destructor)
+#if (LZO_CC_GNUC >= 0x030400ul)
+# define __lzo_destructor __attribute__((__destructor__,__used__))
+#elif (LZO_CC_GNUC >= 0x020700ul)
+# define __lzo_destructor __attribute__((__destructor__))
+#elif (LZO_CC_LLVM || LZO_CC_PATHSCALE)
+# define __lzo_destructor __attribute__((__destructor__))
+#endif
+#endif
+#if defined(__lzo_destructor)
+# define __lzo_HAVE_destructor 1
+#endif
+#if defined(__lzo_HAVE_destructor) && !defined(__lzo_HAVE_constructor)
+# error "this should not happen"
+#endif
+#if !defined(__lzo_inline)
+#if (LZO_CC_TURBOC && (__TURBOC__ <= 0x0295))
+#elif defined(__cplusplus)
+# define __lzo_inline inline
+#elif (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0550))
+# define __lzo_inline __inline
+#elif (LZO_CC_CILLY || LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE || LZO_CC_PGI)
+# define __lzo_inline __inline__
+#elif (LZO_CC_DMC)
+# define __lzo_inline __inline
+#elif (LZO_CC_INTELC)
+# define __lzo_inline __inline
+#elif (LZO_CC_MWERKS && (__MWERKS__ >= 0x2405))
+# define __lzo_inline __inline
+#elif (LZO_CC_MSC && (_MSC_VER >= 900))
+# define __lzo_inline __inline
+#elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
+# define __lzo_inline inline
+#endif
+#endif
+#if defined(__lzo_inline)
+# define __lzo_HAVE_inline 1
+#else
+# define __lzo_inline
+#endif
+#if !defined(__lzo_forceinline)
+#if (LZO_CC_GNUC >= 0x030200ul)
+# define __lzo_forceinline __inline__ __attribute__((__always_inline__))
+#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 450) && LZO_CC_SYNTAX_MSC)
+# define __lzo_forceinline __forceinline
+#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 800) && LZO_CC_SYNTAX_GNUC)
+# define __lzo_forceinline __inline__ __attribute__((__always_inline__))
+#elif (LZO_CC_LLVM || LZO_CC_PATHSCALE)
+# define __lzo_forceinline __inline__ __attribute__((__always_inline__))
+#elif (LZO_CC_MSC && (_MSC_VER >= 1200))
+# define __lzo_forceinline __forceinline
+#endif
+#endif
+#if defined(__lzo_forceinline)
+# define __lzo_HAVE_forceinline 1
+#else
+# define __lzo_forceinline
+#endif
+#if !defined(__lzo_noinline)
+#if 1 && (LZO_ARCH_I386) && (LZO_CC_GNUC >= 0x040000ul) && (LZO_CC_GNUC < 0x040003ul)
+# define __lzo_noinline __attribute__((__noinline__,__used__))
+#elif (LZO_CC_GNUC >= 0x030200ul)
+# define __lzo_noinline __attribute__((__noinline__))
+#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 600) && LZO_CC_SYNTAX_MSC)
+# define __lzo_noinline __declspec(noinline)
+#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 800) && LZO_CC_SYNTAX_GNUC)
+# define __lzo_noinline __attribute__((__noinline__))
+#elif (LZO_CC_LLVM || LZO_CC_PATHSCALE)
+# define __lzo_noinline __attribute__((__noinline__))
+#elif (LZO_CC_MSC && (_MSC_VER >= 1300))
+# define __lzo_noinline __declspec(noinline)
+#elif (LZO_CC_MWERKS && (__MWERKS__ >= 0x3200) && (LZO_OS_WIN32 || LZO_OS_WIN64))
+# if defined(__cplusplus)
+# else
+# define __lzo_noinline __declspec(noinline)
+# endif
+#endif
+#endif
+#if defined(__lzo_noinline)
+# define __lzo_HAVE_noinline 1
+#else
+# define __lzo_noinline
+#endif
+#if (defined(__lzo_HAVE_forceinline) || defined(__lzo_HAVE_noinline)) && !defined(__lzo_HAVE_inline)
+# error "this should not happen"
+#endif
+#if !defined(__lzo_noreturn)
+#if (LZO_CC_GNUC >= 0x020700ul)
+# define __lzo_noreturn __attribute__((__noreturn__))
+#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 450) && LZO_CC_SYNTAX_MSC)
+# define __lzo_noreturn __declspec(noreturn)
+#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 600) && LZO_CC_SYNTAX_GNUC)
+# define __lzo_noreturn __attribute__((__noreturn__))
+#elif (LZO_CC_LLVM || LZO_CC_PATHSCALE)
+# define __lzo_noreturn __attribute__((__noreturn__))
+#elif (LZO_CC_MSC && (_MSC_VER >= 1200))
+# define __lzo_noreturn __declspec(noreturn)
+#endif
+#endif
+#if defined(__lzo_noreturn)
+# define __lzo_HAVE_noreturn 1
+#else
+# define __lzo_noreturn
+#endif
+#if !defined(__lzo_nothrow)
+#if (LZO_CC_GNUC >= 0x030300ul)
+# define __lzo_nothrow __attribute__((__nothrow__))
+#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 450) && LZO_CC_SYNTAX_MSC) && defined(__cplusplus)
+# define __lzo_nothrow __declspec(nothrow)
+#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 800) && LZO_CC_SYNTAX_GNUC)
+# define __lzo_nothrow __attribute__((__nothrow__))
+#elif (LZO_CC_LLVM || LZO_CC_PATHSCALE)
+# define __lzo_nothrow __attribute__((__nothrow__))
+#elif (LZO_CC_MSC && (_MSC_VER >= 1200)) && defined(__cplusplus)
+# define __lzo_nothrow __declspec(nothrow)
+#endif
+#endif
+#if defined(__lzo_nothrow)
+# define __lzo_HAVE_nothrow 1
+#else
+# define __lzo_nothrow
+#endif
+#if !defined(__lzo_restrict)
+#if (LZO_CC_GNUC >= 0x030400ul)
+# define __lzo_restrict __restrict__
+#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 600) && LZO_CC_SYNTAX_GNUC)
+# define __lzo_restrict __restrict__
+#elif (LZO_CC_LLVM)
+# define __lzo_restrict __restrict__
+#elif (LZO_CC_MSC && (_MSC_VER >= 1400))
+# define __lzo_restrict __restrict
+#endif
+#endif
+#if defined(__lzo_restrict)
+# define __lzo_HAVE_restrict 1
+#else
+# define __lzo_restrict
+#endif
+#if !defined(__lzo_likely) && !defined(__lzo_unlikely)
+#if (LZO_CC_GNUC >= 0x030200ul)
+# define __lzo_likely(e) (__builtin_expect(!!(e),1))
+# define __lzo_unlikely(e) (__builtin_expect(!!(e),0))
+#elif (LZO_CC_INTELC && (__INTEL_COMPILER >= 800))
+# define __lzo_likely(e) (__builtin_expect(!!(e),1))
+# define __lzo_unlikely(e) (__builtin_expect(!!(e),0))
+#elif (LZO_CC_LLVM || LZO_CC_PATHSCALE)
+# define __lzo_likely(e) (__builtin_expect(!!(e),1))
+# define __lzo_unlikely(e) (__builtin_expect(!!(e),0))
+#endif
+#endif
+#if defined(__lzo_likely)
+# define __lzo_HAVE_likely 1
+#else
+# define __lzo_likely(e) (e)
+#endif
+#if defined(__lzo_unlikely)
+# define __lzo_HAVE_unlikely 1
+#else
+# define __lzo_unlikely(e) (e)
+#endif
+#if !defined(LZO_UNUSED)
+# if (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0600))
+# define LZO_UNUSED(var) ((void) &var)
+# elif (LZO_CC_BORLANDC || LZO_CC_HIGHC || LZO_CC_NDPC || LZO_CC_PELLESC || LZO_CC_TURBOC)
+# define LZO_UNUSED(var) if (&var) ; else
+# elif (LZO_CC_GNUC || LZO_CC_LLVM || LZO_CC_PATHSCALE)
+# define LZO_UNUSED(var) ((void) var)
+# elif (LZO_CC_MSC && (_MSC_VER < 900))
+# define LZO_UNUSED(var) if (&var) ; else
+# elif (LZO_CC_KEILC)
+# define LZO_UNUSED(var) {extern int __lzo_unused[1-2*!(sizeof(var)>0)];}
+# elif (LZO_CC_PACIFICC)
+# define LZO_UNUSED(var) ((void) sizeof(var))
+# elif (LZO_CC_WATCOMC) && defined(__cplusplus)
+# define LZO_UNUSED(var) ((void) var)
+# else
+# define LZO_UNUSED(var) ((void) &var)
+# endif
+#endif
+#if !defined(LZO_UNUSED_FUNC)
+# if (LZO_CC_BORLANDC && (__BORLANDC__ >= 0x0600))
+# define LZO_UNUSED_FUNC(func) ((void) func)
+# elif (LZO_CC_BORLANDC || LZO_CC_NDPC || LZO_CC_TURBOC)
+# define LZO_UNUSED_FUNC(func) if (func) ; else
+# elif (LZO_CC_LLVM)
+# define LZO_UNUSED_FUNC(func) ((void) &func)
+# elif (LZO_CC_MSC && (_MSC_VER < 900))
+# define LZO_UNUSED_FUNC(func) if (func) ; else
+# elif (LZO_CC_MSC)
+# define LZO_UNUSED_FUNC(func) ((void) &func)
+# elif (LZO_CC_KEILC || LZO_CC_PELLESC)
+# define LZO_UNUSED_FUNC(func) {extern int __lzo_unused[1-2*!(sizeof((int)func)>0)];}
+# else
+# define LZO_UNUSED_FUNC(func) ((void) func)
+# endif
+#endif
+#if !defined(LZO_UNUSED_LABEL)
+# if (LZO_CC_WATCOMC) && defined(__cplusplus)
+# define LZO_UNUSED_LABEL(l) switch(0) case 1:goto l
+# elif (LZO_CC_INTELC || LZO_CC_WATCOMC)
+# define LZO_UNUSED_LABEL(l) if (0) goto l
+# else
+# define LZO_UNUSED_LABEL(l) switch(0) case 1:goto l
+# endif
+#endif
+#if !defined(LZO_DEFINE_UNINITIALIZED_VAR)
+# if 0
+# define LZO_DEFINE_UNINITIALIZED_VAR(type,var,init) type var
+# elif 0 && (LZO_CC_GNUC)
+# define LZO_DEFINE_UNINITIALIZED_VAR(type,var,init) type var = var
+# else
+# define LZO_DEFINE_UNINITIALIZED_VAR(type,var,init) type var = init
+# endif
+#endif
+#if !defined(LZO_COMPILE_TIME_ASSERT_HEADER)
+# if (LZO_CC_AZTECC || LZO_CC_ZORTECHC)
+# define LZO_COMPILE_TIME_ASSERT_HEADER(e) extern int __lzo_cta[1-!(e)];
+# elif (LZO_CC_DMC || LZO_CC_SYMANTECC)
+# define LZO_COMPILE_TIME_ASSERT_HEADER(e) extern int __lzo_cta[1u-2*!(e)];
+# elif (LZO_CC_TURBOC && (__TURBOC__ == 0x0295))
+# define LZO_COMPILE_TIME_ASSERT_HEADER(e) extern int __lzo_cta[1-!(e)];
+# else
+# define LZO_COMPILE_TIME_ASSERT_HEADER(e) extern int __lzo_cta[1-2*!(e)];
+# endif
+#endif
+#if !defined(LZO_COMPILE_TIME_ASSERT)
+# if (LZO_CC_AZTECC)
+# define LZO_COMPILE_TIME_ASSERT(e) {typedef int __lzo_cta_t[1-!(e)];}
+# elif (LZO_CC_DMC || LZO_CC_PACIFICC || LZO_CC_SYMANTECC || LZO_CC_ZORTECHC)
+# define LZO_COMPILE_TIME_ASSERT(e) switch(0) case 1:case !(e):break;
+# elif (LZO_CC_MSC && (_MSC_VER < 900))
+# define LZO_COMPILE_TIME_ASSERT(e) switch(0) case 1:case !(e):break;
+# elif (LZO_CC_TURBOC && (__TURBOC__ == 0x0295))
+# define LZO_COMPILE_TIME_ASSERT(e) switch(0) case 1:case !(e):break;
+# else
+# define LZO_COMPILE_TIME_ASSERT(e) {typedef int __lzo_cta_t[1-2*!(e)];}
+# endif
+#endif
+#if (LZO_ARCH_I086 || LZO_ARCH_I386) && (LZO_OS_DOS16 || LZO_OS_DOS32 || LZO_OS_OS2 || LZO_OS_OS216 || LZO_OS_WIN16 || LZO_OS_WIN32 || LZO_OS_WIN64)
+# if (LZO_CC_GNUC || LZO_CC_HIGHC || LZO_CC_NDPC || LZO_CC_PACIFICC)
+# elif (LZO_CC_DMC || LZO_CC_SYMANTECC || LZO_CC_ZORTECHC)
+# define __lzo_cdecl __cdecl
+# define __lzo_cdecl_atexit
+# define __lzo_cdecl_main __cdecl
+# if (LZO_OS_OS2 && (LZO_CC_DMC || LZO_CC_SYMANTECC))
+# define __lzo_cdecl_qsort __pascal
+# elif (LZO_OS_OS2 && (LZO_CC_ZORTECHC))
+# define __lzo_cdecl_qsort _stdcall
+# else
+# define __lzo_cdecl_qsort __cdecl
+# endif
+# elif (LZO_CC_WATCOMC)
+# define __lzo_cdecl __cdecl
+# else
+# define __lzo_cdecl __cdecl
+# define __lzo_cdecl_atexit __cdecl
+# define __lzo_cdecl_main __cdecl
+# define __lzo_cdecl_qsort __cdecl
+# endif
+# if (LZO_CC_GNUC || LZO_CC_HIGHC || LZO_CC_NDPC || LZO_CC_PACIFICC || LZO_CC_WATCOMC)
+# elif (LZO_OS_OS2 && (LZO_CC_DMC || LZO_CC_SYMANTECC))
+# define __lzo_cdecl_sighandler __pascal
+# elif (LZO_OS_OS2 && (LZO_CC_ZORTECHC))
+# define __lzo_cdecl_sighandler _stdcall
+# elif (LZO_CC_MSC && (_MSC_VER >= 1400)) && defined(_M_CEE_PURE)
+# define __lzo_cdecl_sighandler __clrcall
+# elif (LZO_CC_MSC && (_MSC_VER >= 600 && _MSC_VER < 700))
+# if defined(_DLL)
+# define __lzo_cdecl_sighandler _far _cdecl _loadds
+# elif defined(_MT)
+# define __lzo_cdecl_sighandler _far _cdecl
+# else
+# define __lzo_cdecl_sighandler _cdecl
+# endif
+# else
+# define __lzo_cdecl_sighandler __cdecl
+# endif
+#elif (LZO_ARCH_I386) && (LZO_CC_WATCOMC)
+# define __lzo_cdecl __cdecl
+#elif (LZO_ARCH_M68K && LZO_OS_TOS && (LZO_CC_PUREC || LZO_CC_TURBOC))
+# define __lzo_cdecl cdecl
+#endif
+#if !defined(__lzo_cdecl)
+# define __lzo_cdecl
+#endif
+#if !defined(__lzo_cdecl_atexit)
+# define __lzo_cdecl_atexit
+#endif
+#if !defined(__lzo_cdecl_main)
+# define __lzo_cdecl_main
+#endif
+#if !defined(__lzo_cdecl_qsort)
+# define __lzo_cdecl_qsort
+#endif
+#if !defined(__lzo_cdecl_sighandler)
+# define __lzo_cdecl_sighandler
+#endif
+#if !defined(__lzo_cdecl_va)
+# define __lzo_cdecl_va __lzo_cdecl
+#endif
+#if !defined(LZO_CFG_NO_WINDOWS_H)
+#if (LZO_OS_CYGWIN || (LZO_OS_EMX && defined(__RSXNT__)) || LZO_OS_WIN32 || LZO_OS_WIN64)
+# if (LZO_CC_WATCOMC && (__WATCOMC__ < 1000))
+# elif (LZO_OS_WIN32 && LZO_CC_GNUC) && defined(__PW32__)
+# elif ((LZO_OS_CYGWIN || defined(__MINGW32__)) && (LZO_CC_GNUC && (LZO_CC_GNUC < 0x025f00ul)))
+# else
+# define LZO_HAVE_WINDOWS_H 1
+# endif
+#endif
+#endif
+#if (LZO_ARCH_ALPHA)
+# define LZO_OPT_AVOID_UINT_INDEX 1
+# define LZO_OPT_AVOID_SHORT 1
+# define LZO_OPT_AVOID_USHORT 1
+#elif (LZO_ARCH_AMD64)
+# define LZO_OPT_AVOID_INT_INDEX 1
+# define LZO_OPT_AVOID_UINT_INDEX 1
+# define LZO_OPT_UNALIGNED16 1
+# define LZO_OPT_UNALIGNED32 1
+# define LZO_OPT_UNALIGNED64 1
+#elif (LZO_ARCH_ARM && LZO_ARCH_ARM_THUMB)
+#elif (LZO_ARCH_ARM)
+# define LZO_OPT_AVOID_SHORT 1
+# define LZO_OPT_AVOID_USHORT 1
+#elif (LZO_ARCH_CRIS)
+# define LZO_OPT_UNALIGNED16 1
+# define LZO_OPT_UNALIGNED32 1
+#elif (LZO_ARCH_I386)
+# define LZO_OPT_UNALIGNED16 1
+# define LZO_OPT_UNALIGNED32 1
+#elif (LZO_ARCH_IA64)
+# define LZO_OPT_AVOID_INT_INDEX 1
+# define LZO_OPT_AVOID_UINT_INDEX 1
+# define LZO_OPT_PREFER_POSTINC 1
+#elif (LZO_ARCH_M68K)
+# define LZO_OPT_PREFER_POSTINC 1
+# define LZO_OPT_PREFER_PREDEC 1
+# if defined(__mc68020__) && !defined(__mcoldfire__)
+# define LZO_OPT_UNALIGNED16 1
+# define LZO_OPT_UNALIGNED32 1
+# endif
+#elif (LZO_ARCH_MIPS)
+# define LZO_OPT_AVOID_UINT_INDEX 1
+#elif (LZO_ARCH_POWERPC)
+# define LZO_OPT_PREFER_PREINC 1
+# define LZO_OPT_PREFER_PREDEC 1
+# if defined(LZO_ABI_BIG_ENDIAN)
+# define LZO_OPT_UNALIGNED16 1
+# define LZO_OPT_UNALIGNED32 1
+# endif
+#elif (LZO_ARCH_S390)
+# define LZO_OPT_UNALIGNED16 1
+# define LZO_OPT_UNALIGNED32 1
+# if (LZO_SIZEOF_SIZE_T == 8)
+# define LZO_OPT_UNALIGNED64 1
+# endif
+#elif (LZO_ARCH_SH)
+# define LZO_OPT_PREFER_POSTINC 1
+# define LZO_OPT_PREFER_PREDEC 1
+#endif
+#if !defined(LZO_CFG_NO_INLINE_ASM)
+#if defined(LZO_CC_LLVM)
+# define LZO_CFG_NO_INLINE_ASM 1
+#endif
+#endif
+#if !defined(LZO_CFG_NO_UNALIGNED)
+#if defined(LZO_ABI_NEUTRAL_ENDIAN) || defined(LZO_ARCH_GENERIC)
+# define LZO_CFG_NO_UNALIGNED 1
+#endif
+#endif
+#if defined(LZO_CFG_NO_UNALIGNED)
+# undef LZO_OPT_UNALIGNED16
+# undef LZO_OPT_UNALIGNED32
+# undef LZO_OPT_UNALIGNED64
+#endif
+#if defined(LZO_CFG_NO_INLINE_ASM)
+#elif (LZO_ARCH_I386 && (LZO_OS_DOS32 || LZO_OS_WIN32) && (LZO_CC_DMC || LZO_CC_INTELC || LZO_CC_MSC || LZO_CC_PELLESC))
+# define LZO_ASM_SYNTAX_MSC 1
+#elif (LZO_OS_WIN64 && (LZO_CC_DMC || LZO_CC_INTELC || LZO_CC_MSC || LZO_CC_PELLESC))
+#elif (LZO_ARCH_I386 && (LZO_CC_GNUC || LZO_CC_INTELC || LZO_CC_PATHSCALE))
+# define LZO_ASM_SYNTAX_GNUC 1
+#elif (LZO_ARCH_AMD64 && (LZO_CC_GNUC || LZO_CC_INTELC || LZO_CC_PATHSCALE))
+# define LZO_ASM_SYNTAX_GNUC 1
+#endif
+#if (LZO_ASM_SYNTAX_GNUC)
+#if (LZO_ARCH_I386 && LZO_CC_GNUC && (LZO_CC_GNUC < 0x020000ul))
+# define __LZO_ASM_CLOBBER "ax"
+#elif (LZO_CC_INTELC)
+# define __LZO_ASM_CLOBBER "memory"
+#else
+# define __LZO_ASM_CLOBBER "cc", "memory"
+#endif
+#endif
+#if defined(__LZO_INFOSTR_MM)
+#elif (LZO_MM_FLAT) && (defined(__LZO_INFOSTR_PM) || defined(LZO_INFO_ABI_PM))
+# define __LZO_INFOSTR_MM ""
+#elif defined(LZO_INFO_MM)
+# define __LZO_INFOSTR_MM "." LZO_INFO_MM
+#else
+# define __LZO_INFOSTR_MM ""
+#endif
+#if defined(__LZO_INFOSTR_PM)
+#elif defined(LZO_INFO_ABI_PM)
+# define __LZO_INFOSTR_PM "." LZO_INFO_ABI_PM
+#else
+# define __LZO_INFOSTR_PM ""
+#endif
+#if defined(__LZO_INFOSTR_ENDIAN)
+#elif defined(LZO_INFO_ABI_ENDIAN)
+# define __LZO_INFOSTR_ENDIAN "." LZO_INFO_ABI_ENDIAN
+#else
+# define __LZO_INFOSTR_ENDIAN ""
+#endif
+#if defined(__LZO_INFOSTR_OSNAME)
+#elif defined(LZO_INFO_OS_CONSOLE)
+# define __LZO_INFOSTR_OSNAME LZO_INFO_OS "." LZO_INFO_OS_CONSOLE
+#elif defined(LZO_INFO_OS_POSIX)
+# define __LZO_INFOSTR_OSNAME LZO_INFO_OS "." LZO_INFO_OS_POSIX
+#else
+# define __LZO_INFOSTR_OSNAME LZO_INFO_OS
+#endif
+#if defined(__LZO_INFOSTR_LIBC)
+#elif defined(LZO_INFO_LIBC)
+# define __LZO_INFOSTR_LIBC "." LZO_INFO_LIBC
+#else
+# define __LZO_INFOSTR_LIBC ""
+#endif
+#if defined(__LZO_INFOSTR_CCVER)
+#elif defined(LZO_INFO_CCVER)
+# define __LZO_INFOSTR_CCVER " " LZO_INFO_CCVER
+#else
+# define __LZO_INFOSTR_CCVER ""
+#endif
+#define LZO_INFO_STRING \
+ LZO_INFO_ARCH __LZO_INFOSTR_MM __LZO_INFOSTR_PM __LZO_INFOSTR_ENDIAN \
+ " " __LZO_INFOSTR_OSNAME __LZO_INFOSTR_LIBC " " LZO_INFO_CC __LZO_INFOSTR_CCVER
+
+#endif
+
+#endif
+
+#undef LZO_HAVE_CONFIG_H
+#include "minilzo.h"
+
+#if !defined(MINILZO_VERSION) || (MINILZO_VERSION != 0x2030)
+# error "version mismatch in miniLZO source files"
+#endif
+
+#ifdef MINILZO_HAVE_CONFIG_H
+# define LZO_HAVE_CONFIG_H
+#endif
+
+#ifndef __LZO_CONF_H
+#define __LZO_CONF_H
+
+#if !defined(__LZO_IN_MINILZO)
+#if defined(LZO_CFG_FREESTANDING)
+# define LZO_LIBC_FREESTANDING 1
+# define LZO_OS_FREESTANDING 1
+# define ACC_LIBC_FREESTANDING 1
+# define ACC_OS_FREESTANDING 1
+#endif
+#if defined(LZO_CFG_NO_UNALIGNED)
+# define ACC_CFG_NO_UNALIGNED 1
+#endif
+#if defined(LZO_ARCH_GENERIC)
+# define ACC_ARCH_GENERIC 1
+#endif
+#if defined(LZO_ABI_NEUTRAL_ENDIAN)
+# define ACC_ABI_NEUTRAL_ENDIAN 1
+#endif
+#if defined(LZO_HAVE_CONFIG_H)
+# define ACC_CONFIG_NO_HEADER 1
+#endif
+#if defined(LZO_CFG_EXTRA_CONFIG_HEADER)
+# include LZO_CFG_EXTRA_CONFIG_HEADER
+#endif
+#if defined(__LZOCONF_H) || defined(__LZOCONF_H_INCLUDED)
+# error "include this file first"
+#endif
+#include "lzo/lzoconf.h"
+#endif
+
+#if (LZO_VERSION < 0x02000) || !defined(__LZOCONF_H_INCLUDED)
+# error "version mismatch"
+#endif
+
+#if (LZO_CC_BORLANDC && LZO_ARCH_I086)
+# pragma option -h
+#endif
+
+#if (LZO_CC_MSC && (_MSC_VER >= 1000))
+# pragma warning(disable: 4127 4701)
+#endif
+#if (LZO_CC_MSC && (_MSC_VER >= 1300))
+# pragma warning(disable: 4820)
+# pragma warning(disable: 4514 4710 4711)
+#endif
+
+#if (LZO_CC_SUNPROC)
+# pragma error_messages(off,E_END_OF_LOOP_CODE_NOT_REACHED)
+# pragma error_messages(off,E_LOOP_NOT_ENTERED_AT_TOP)
+#endif
+
+#if defined(__LZO_MMODEL_HUGE) && (!LZO_HAVE_MM_HUGE_PTR)
+# error "this should not happen - check defines for __huge"
+#endif
+
+#if defined(__LZO_IN_MINILZO) || defined(LZO_CFG_FREESTANDING)
+#elif (LZO_OS_DOS16 || LZO_OS_OS216 || LZO_OS_WIN16)
+# define ACC_WANT_ACC_INCD_H 1
+# define ACC_WANT_ACC_INCE_H 1
+# define ACC_WANT_ACC_INCI_H 1
+#elif 1
+# include
+#else
+# define ACC_WANT_ACC_INCD_H 1
+#endif
+
+#if (LZO_ARCH_I086)
+# define ACC_MM_AHSHIFT LZO_MM_AHSHIFT
+# define ACC_PTR_FP_OFF(x) (((const unsigned __far*)&(x))[0])
+# define ACC_PTR_FP_SEG(x) (((const unsigned __far*)&(x))[1])
+# define ACC_PTR_MK_FP(s,o) ((void __far*)(((unsigned long)(s)<<16)+(unsigned)(o)))
+#endif
+
+#if !defined(lzo_uintptr_t)
+# if defined(__LZO_MMODEL_HUGE)
+# define lzo_uintptr_t unsigned long
+# elif 1 && defined(LZO_OS_OS400) && (LZO_SIZEOF_VOID_P == 16)
+# define __LZO_UINTPTR_T_IS_POINTER 1
+ typedef char* lzo_uintptr_t;
+# define lzo_uintptr_t lzo_uintptr_t
+# elif (LZO_SIZEOF_SIZE_T == LZO_SIZEOF_VOID_P)
+# define lzo_uintptr_t size_t
+# elif (LZO_SIZEOF_LONG == LZO_SIZEOF_VOID_P)
+# define lzo_uintptr_t unsigned long
+# elif (LZO_SIZEOF_INT == LZO_SIZEOF_VOID_P)
+# define lzo_uintptr_t unsigned int
+# elif (LZO_SIZEOF_LONG_LONG == LZO_SIZEOF_VOID_P)
+# define lzo_uintptr_t unsigned long long
+# else
+# define lzo_uintptr_t size_t
+# endif
+#endif
+LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_uintptr_t) >= sizeof(lzo_voidp))
+
+#if 1 && !defined(LZO_CFG_FREESTANDING)
+#if 1 && !defined(HAVE_STRING_H)
+#define HAVE_STRING_H 1
+#endif
+#if 1 && !defined(HAVE_MEMCMP)
+#define HAVE_MEMCMP 1
+#endif
+#if 1 && !defined(HAVE_MEMCPY)
+#define HAVE_MEMCPY 1
+#endif
+#if 1 && !defined(HAVE_MEMMOVE)
+#define HAVE_MEMMOVE 1
+#endif
+#if 1 && !defined(HAVE_MEMSET)
+#define HAVE_MEMSET 1
+#endif
+#endif
+
+#if 1 && defined(HAVE_STRING_H)
+#include
+#endif
+
+#if defined(LZO_CFG_FREESTANDING)
+# undef HAVE_MEMCMP
+# undef HAVE_MEMCPY
+# undef HAVE_MEMMOVE
+# undef HAVE_MEMSET
+#endif
+
+#if !defined(HAVE_MEMCMP)
+# undef memcmp
+# define memcmp(a,b,c) lzo_memcmp(a,b,c)
+#elif !defined(__LZO_MMODEL_HUGE)
+# define lzo_memcmp(a,b,c) memcmp(a,b,c)
+#endif
+#if !defined(HAVE_MEMCPY)
+# undef memcpy
+# define memcpy(a,b,c) lzo_memcpy(a,b,c)
+#elif !defined(__LZO_MMODEL_HUGE)
+# define lzo_memcpy(a,b,c) memcpy(a,b,c)
+#endif
+#if !defined(HAVE_MEMMOVE)
+# undef memmove
+# define memmove(a,b,c) lzo_memmove(a,b,c)
+#elif !defined(__LZO_MMODEL_HUGE)
+# define lzo_memmove(a,b,c) memmove(a,b,c)
+#endif
+#if !defined(HAVE_MEMSET)
+# undef memset
+# define memset(a,b,c) lzo_memset(a,b,c)
+#elif !defined(__LZO_MMODEL_HUGE)
+# define lzo_memset(a,b,c) memset(a,b,c)
+#endif
+
+#undef NDEBUG
+#if defined(LZO_CFG_FREESTANDING)
+# undef LZO_DEBUG
+# define NDEBUG 1
+# undef assert
+# define assert(e) ((void)0)
+#else
+# if !defined(LZO_DEBUG)
+# define NDEBUG 1
+# endif
+# include
+#endif
+
+#if 0 && defined(__BOUNDS_CHECKING_ON)
+# include
+#else
+# define BOUNDS_CHECKING_OFF_DURING(stmt) stmt
+# define BOUNDS_CHECKING_OFF_IN_EXPR(expr) (expr)
+#endif
+
+#if !defined(__lzo_inline)
+# define __lzo_inline
+#endif
+#if !defined(__lzo_forceinline)
+# define __lzo_forceinline
+#endif
+#if !defined(__lzo_noinline)
+# define __lzo_noinline
+#endif
+
+#if 1
+# define LZO_BYTE(x) ((unsigned char) (x))
+#else
+# define LZO_BYTE(x) ((unsigned char) ((x) & 0xff))
+#endif
+
+#define LZO_MAX(a,b) ((a) >= (b) ? (a) : (b))
+#define LZO_MIN(a,b) ((a) <= (b) ? (a) : (b))
+#define LZO_MAX3(a,b,c) ((a) >= (b) ? LZO_MAX(a,c) : LZO_MAX(b,c))
+#define LZO_MIN3(a,b,c) ((a) <= (b) ? LZO_MIN(a,c) : LZO_MIN(b,c))
+
+#define lzo_sizeof(type) ((lzo_uint) (sizeof(type)))
+
+#define LZO_HIGH(array) ((lzo_uint) (sizeof(array)/sizeof(*(array))))
+
+#define LZO_SIZE(bits) (1u << (bits))
+#define LZO_MASK(bits) (LZO_SIZE(bits) - 1)
+
+#define LZO_LSIZE(bits) (1ul << (bits))
+#define LZO_LMASK(bits) (LZO_LSIZE(bits) - 1)
+
+#define LZO_USIZE(bits) ((lzo_uint) 1 << (bits))
+#define LZO_UMASK(bits) (LZO_USIZE(bits) - 1)
+
+#if !defined(DMUL)
+#if 0
+
+# define DMUL(a,b) ((lzo_xint) ((lzo_uint32)(a) * (lzo_uint32)(b)))
+#else
+# define DMUL(a,b) ((lzo_xint) ((a) * (b)))
+#endif
+#endif
+
+#if 1 && !defined(LZO_CFG_NO_UNALIGNED)
+#if 1 && (LZO_ARCH_AMD64 || LZO_ARCH_I386)
+# if (LZO_SIZEOF_SHORT == 2)
+# define LZO_UNALIGNED_OK_2
+# endif
+# if (LZO_SIZEOF_INT == 4)
+# define LZO_UNALIGNED_OK_4
+# endif
+#endif
+#endif
+
+#if defined(LZO_UNALIGNED_OK_2)
+ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(short) == 2)
+#endif
+#if defined(LZO_UNALIGNED_OK_4)
+ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_uint32) == 4)
+#elif defined(LZO_ALIGNED_OK_4)
+ LZO_COMPILE_TIME_ASSERT_HEADER(sizeof(lzo_uint32) == 4)
+#endif
+
+#define MEMCPY8_DS(dest,src,len) \
+ lzo_memcpy(dest,src,len); dest += len; src += len
+
+#define BZERO8_PTR(s,l,n) \
+ lzo_memset((lzo_voidp)(s),0,(lzo_uint)(l)*(n))
+
+#define MEMCPY_DS(dest,src,len) \
+ do *dest++ = *src++; while (--len > 0)
+
+__LZO_EXTERN_C int __lzo_init_done;
+__LZO_EXTERN_C const char __lzo_copyright[];
+LZO_EXTERN(const lzo_bytep) lzo_copyright(void);
+
+#ifndef __LZO_PTR_H
+#define __LZO_PTR_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if !defined(lzo_uintptr_t)
+# if defined(__LZO_MMODEL_HUGE)
+# define lzo_uintptr_t unsigned long
+# else
+# define lzo_uintptr_t acc_uintptr_t
+# ifdef __ACC_INTPTR_T_IS_POINTER
+# define __LZO_UINTPTR_T_IS_POINTER 1
+# endif
+# endif
+#endif
+
+#if (LZO_ARCH_I086)
+#define PTR(a) ((lzo_bytep) (a))
+#define PTR_ALIGNED_4(a) ((ACC_PTR_FP_OFF(a) & 3) == 0)
+#define PTR_ALIGNED2_4(a,b) (((ACC_PTR_FP_OFF(a) | ACC_PTR_FP_OFF(b)) & 3) == 0)
+#elif (LZO_MM_PVP)
+#define PTR(a) ((lzo_bytep) (a))
+#define PTR_ALIGNED_8(a) ((((lzo_uintptr_t)(a)) >> 61) == 0)
+#define PTR_ALIGNED2_8(a,b) ((((lzo_uintptr_t)(a)|(lzo_uintptr_t)(b)) >> 61) == 0)
+#else
+#define PTR(a) ((lzo_uintptr_t) (a))
+#define PTR_LINEAR(a) PTR(a)
+#define PTR_ALIGNED_4(a) ((PTR_LINEAR(a) & 3) == 0)
+#define PTR_ALIGNED_8(a) ((PTR_LINEAR(a) & 7) == 0)
+#define PTR_ALIGNED2_4(a,b) (((PTR_LINEAR(a) | PTR_LINEAR(b)) & 3) == 0)
+#define PTR_ALIGNED2_8(a,b) (((PTR_LINEAR(a) | PTR_LINEAR(b)) & 7) == 0)
+#endif
+
+#define PTR_LT(a,b) (PTR(a) < PTR(b))
+#define PTR_GE(a,b) (PTR(a) >= PTR(b))
+#define PTR_DIFF(a,b) (PTR(a) - PTR(b))
+#define pd(a,b) ((lzo_uint) ((a)-(b)))
+
+LZO_EXTERN(lzo_uintptr_t)
+__lzo_ptr_linear(const lzo_voidp ptr);
+
+typedef union
+{
+ char a_char;
+ unsigned char a_uchar;
+ short a_short;
+ unsigned short a_ushort;
+ int a_int;
+ unsigned int a_uint;
+ long a_long;
+ unsigned long a_ulong;
+ lzo_int a_lzo_int;
+ lzo_uint a_lzo_uint;
+ lzo_int32 a_lzo_int32;
+ lzo_uint32 a_lzo_uint32;
+ ptrdiff_t a_ptrdiff_t;
+ lzo_uintptr_t a_lzo_uintptr_t;
+ lzo_voidp a_lzo_voidp;
+ void * a_void_p;
+ lzo_bytep a_lzo_bytep;
+ lzo_bytepp a_lzo_bytepp;
+ lzo_uintp a_lzo_uintp;
+ lzo_uint * a_lzo_uint_p;
+ lzo_uint32p a_lzo_uint32p;
+ lzo_uint32 * a_lzo_uint32_p;
+ unsigned char * a_uchar_p;
+ char * a_char_p;
+}
+lzo_full_align_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+#define LZO_DETERMINISTIC
+
+#define LZO_DICT_USE_PTR
+#if 0 && (LZO_ARCH_I086)
+# undef LZO_DICT_USE_PTR
+#endif
+
+#if defined(LZO_DICT_USE_PTR)
+# define lzo_dict_t const lzo_bytep
+# define lzo_dict_p lzo_dict_t __LZO_MMODEL *
+#else
+# define lzo_dict_t lzo_uint
+# define lzo_dict_p lzo_dict_t __LZO_MMODEL *
+#endif
+
+#endif
+
+#if !defined(MINILZO_CFG_SKIP_LZO_PTR)
+
+LZO_PUBLIC(lzo_uintptr_t)
+__lzo_ptr_linear(const lzo_voidp ptr)
+{
+ lzo_uintptr_t p;
+
+#if (LZO_ARCH_I086)
+ p = (((lzo_uintptr_t)(ACC_PTR_FP_SEG(ptr))) << (16 - ACC_MM_AHSHIFT)) + (ACC_PTR_FP_OFF(ptr));
+#elif (LZO_MM_PVP)
+ p = (lzo_uintptr_t) (ptr);
+ p = (p << 3) | (p >> 61);
+#else
+ p = (lzo_uintptr_t) PTR_LINEAR(ptr);
+#endif
+
+ return p;
+}
+
+LZO_PUBLIC(unsigned)
+__lzo_align_gap(const lzo_voidp ptr, lzo_uint size)
+{
+#if defined(__LZO_UINTPTR_T_IS_POINTER)
+ size_t n = (size_t) ptr;
+ n = (((n + size - 1) / size) * size) - n;
+#else
+ lzo_uintptr_t p, n;
+ p = __lzo_ptr_linear(ptr);
+ n = (((p + size - 1) / size) * size) - p;
+#endif
+
+ assert(size > 0);
+ assert((long)n >= 0);
+ assert(n <= size);
+ return (unsigned)n;
+}
+
+#endif
+
+/* If you use the LZO library in a product, I would appreciate that you
+ * keep this copyright string in the executable of your product.
+ */
+
+const char __lzo_copyright[] =
+#if !defined(__LZO_IN_MINLZO)
+ LZO_VERSION_STRING;
+#else
+ "\r\n\n"
+ "LZO data compression library.\n"
+ "$Copyright: LZO (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 Markus Franz Xaver Johannes Oberhumer\n"
+ "\n"
+ "http://www.oberhumer.com $\n\n"
+ "$Id: LZO version: v" LZO_VERSION_STRING ", " LZO_VERSION_DATE " $\n"
+ "$Built: " __DATE__ " " __TIME__ " $\n"
+ "$Info: " LZO_INFO_STRING " $\n";
+#endif
+
+LZO_PUBLIC(const lzo_bytep)
+lzo_copyright(void)
+{
+#if (LZO_OS_DOS16 && LZO_CC_TURBOC)
+ return (lzo_voidp) __lzo_copyright;
+#else
+ return (const lzo_bytep) __lzo_copyright;
+#endif
+}
+
+LZO_PUBLIC(unsigned)
+lzo_version(void)
+{
+ return LZO_VERSION;
+}
+
+LZO_PUBLIC(const char *)
+lzo_version_string(void)
+{
+ return LZO_VERSION_STRING;
+}
+
+LZO_PUBLIC(const char *)
+lzo_version_date(void)
+{
+ return LZO_VERSION_DATE;
+}
+
+LZO_PUBLIC(const lzo_charp)
+_lzo_version_string(void)
+{
+ return LZO_VERSION_STRING;
+}
+
+LZO_PUBLIC(const lzo_charp)
+_lzo_version_date(void)
+{
+ return LZO_VERSION_DATE;
+}
+
+#define LZO_BASE 65521u
+#define LZO_NMAX 5552
+
+#define LZO_DO1(buf,i) s1 += buf[i]; s2 += s1
+#define LZO_DO2(buf,i) LZO_DO1(buf,i); LZO_DO1(buf,i+1);
+#define LZO_DO4(buf,i) LZO_DO2(buf,i); LZO_DO2(buf,i+2);
+#define LZO_DO8(buf,i) LZO_DO4(buf,i); LZO_DO4(buf,i+4);
+#define LZO_DO16(buf,i) LZO_DO8(buf,i); LZO_DO8(buf,i+8);
+
+LZO_PUBLIC(lzo_uint32)
+lzo_adler32(lzo_uint32 adler, const lzo_bytep buf, lzo_uint len)
+{
+ lzo_uint32 s1 = adler & 0xffff;
+ lzo_uint32 s2 = (adler >> 16) & 0xffff;
+ unsigned k;
+
+ if (buf == NULL)
+ return 1;
+
+ while (len > 0)
+ {
+ k = len < LZO_NMAX ? (unsigned) len : LZO_NMAX;
+ len -= k;
+ if (k >= 16) do
+ {
+ LZO_DO16(buf,0);
+ buf += 16;
+ k -= 16;
+ } while (k >= 16);
+ if (k != 0) do
+ {
+ s1 += *buf++;
+ s2 += s1;
+ } while (--k > 0);
+ s1 %= LZO_BASE;
+ s2 %= LZO_BASE;
+ }
+ return (s2 << 16) | s1;
+}
+
+#undef LZO_DO1
+#undef LZO_DO2
+#undef LZO_DO4
+#undef LZO_DO8
+#undef LZO_DO16
+
+#if !defined(MINILZO_CFG_SKIP_LZO_STRING)
+#undef lzo_memcmp
+#undef lzo_memcpy
+#undef lzo_memmove
+#undef lzo_memset
+#if !defined(__LZO_MMODEL_HUGE)
+# undef LZO_HAVE_MM_HUGE_PTR
+#endif
+#define lzo_hsize_t lzo_uint
+#define lzo_hvoid_p lzo_voidp
+#define lzo_hbyte_p lzo_bytep
+#define LZOLIB_PUBLIC(r,f) LZO_PUBLIC(r) f
+#define lzo_hmemcmp lzo_memcmp
+#define lzo_hmemcpy lzo_memcpy
+#define lzo_hmemmove lzo_memmove
+#define lzo_hmemset lzo_memset
+#define __LZOLIB_HMEMCPY_CH_INCLUDED 1
+#if !defined(LZOLIB_PUBLIC)
+# define LZOLIB_PUBLIC(r,f) r __LZOLIB_FUNCNAME(f)
+#endif
+LZOLIB_PUBLIC(int, lzo_hmemcmp) (const lzo_hvoid_p s1, const lzo_hvoid_p s2, lzo_hsize_t len)
+{
+#if (LZO_HAVE_MM_HUGE_PTR) || !defined(HAVE_MEMCMP)
+ const lzo_hbyte_p p1 = (const lzo_hbyte_p) s1;
+ const lzo_hbyte_p p2 = (const lzo_hbyte_p) s2;
+ if __lzo_likely(len > 0) do
+ {
+ int d = *p1 - *p2;
+ if (d != 0)
+ return d;
+ p1++; p2++;
+ } while __lzo_likely(--len > 0);
+ return 0;
+#else
+ return memcmp(s1, s2, len);
+#endif
+}
+LZOLIB_PUBLIC(lzo_hvoid_p, lzo_hmemcpy) (lzo_hvoid_p dest, const lzo_hvoid_p src, lzo_hsize_t len)
+{
+#if (LZO_HAVE_MM_HUGE_PTR) || !defined(HAVE_MEMCPY)
+ lzo_hbyte_p p1 = (lzo_hbyte_p) dest;
+ const lzo_hbyte_p p2 = (const lzo_hbyte_p) src;
+ if (!(len > 0) || p1 == p2)
+ return dest;
+ do
+ *p1++ = *p2++;
+ while __lzo_likely(--len > 0);
+ return dest;
+#else
+ return memcpy(dest, src, len);
+#endif
+}
+LZOLIB_PUBLIC(lzo_hvoid_p, lzo_hmemmove) (lzo_hvoid_p dest, const lzo_hvoid_p src, lzo_hsize_t len)
+{
+#if (LZO_HAVE_MM_HUGE_PTR) || !defined(HAVE_MEMMOVE)
+ lzo_hbyte_p p1 = (lzo_hbyte_p) dest;
+ const lzo_hbyte_p p2 = (const lzo_hbyte_p) src;
+ if (!(len > 0) || p1 == p2)
+ return dest;
+ if (p1 < p2)
+ {
+ do
+ *p1++ = *p2++;
+ while __lzo_likely(--len > 0);
+ }
+ else
+ {
+ p1 += len;
+ p2 += len;
+ do
+ *--p1 = *--p2;
+ while __lzo_likely(--len > 0);
+ }
+ return dest;
+#else
+ return memmove(dest, src, len);
+#endif
+}
+LZOLIB_PUBLIC(lzo_hvoid_p, lzo_hmemset) (lzo_hvoid_p s, int c, lzo_hsize_t len)
+{
+#if (LZO_HAVE_MM_HUGE_PTR) || !defined(HAVE_MEMSET)
+ lzo_hbyte_p p = (lzo_hbyte_p) s;
+ if __lzo_likely(len > 0) do
+ *p++ = (unsigned char) c;
+ while __lzo_likely(--len > 0);
+ return s;
+#else
+ return memset(s, c, len);
+#endif
+}
+#undef LZOLIB_PUBLIC
+#endif
+
+#if !defined(__LZO_IN_MINILZO)
+
+#define ACC_WANT_ACC_CHK_CH 1
+#undef ACCCHK_ASSERT
+
+ ACCCHK_ASSERT_IS_SIGNED_T(lzo_int)
+ ACCCHK_ASSERT_IS_UNSIGNED_T(lzo_uint)
+
+ ACCCHK_ASSERT_IS_SIGNED_T(lzo_int32)
+ ACCCHK_ASSERT_IS_UNSIGNED_T(lzo_uint32)
+ ACCCHK_ASSERT((LZO_UINT32_C(1) << (int)(8*sizeof(LZO_UINT32_C(1))-1)) > 0)
+ ACCCHK_ASSERT(sizeof(lzo_uint32) >= 4)
+
+#if !defined(__LZO_UINTPTR_T_IS_POINTER)
+ ACCCHK_ASSERT_IS_UNSIGNED_T(lzo_uintptr_t)
+#endif
+ ACCCHK_ASSERT(sizeof(lzo_uintptr_t) >= sizeof(lzo_voidp))
+
+ ACCCHK_ASSERT_IS_UNSIGNED_T(lzo_xint)
+ ACCCHK_ASSERT(sizeof(lzo_xint) >= sizeof(lzo_uint32))
+ ACCCHK_ASSERT(sizeof(lzo_xint) >= sizeof(lzo_uint))
+ ACCCHK_ASSERT(sizeof(lzo_xint) == sizeof(lzo_uint32) || sizeof(lzo_xint) == sizeof(lzo_uint))
+
+#endif
+#undef ACCCHK_ASSERT
+
+LZO_PUBLIC(int)
+_lzo_config_check(void)
+{
+ lzo_bool r = 1;
+ union { unsigned char c[2*sizeof(lzo_xint)]; lzo_xint l[2]; } u;
+ lzo_uintptr_t p;
+
+#if !defined(LZO_CFG_NO_CONFIG_CHECK)
+#if defined(LZO_ABI_BIG_ENDIAN)
+ u.l[0] = u.l[1] = 0; u.c[sizeof(lzo_xint) - 1] = 128;
+ r &= (u.l[0] == 128);
+#endif
+#if defined(LZO_ABI_LITTLE_ENDIAN)
+ u.l[0] = u.l[1] = 0; u.c[0] = 128;
+ r &= (u.l[0] == 128);
+#endif
+#if defined(LZO_UNALIGNED_OK_2)
+ p = (lzo_uintptr_t) (const lzo_voidp) &u.c[0];
+ u.l[0] = u.l[1] = 0;
+ r &= ((* (const lzo_ushortp) (p+1)) == 0);
+#endif
+#if defined(LZO_UNALIGNED_OK_4)
+ p = (lzo_uintptr_t) (const lzo_voidp) &u.c[0];
+ u.l[0] = u.l[1] = 0;
+ r &= ((* (const lzo_uint32p) (p+1)) == 0);
+#endif
+#endif
+
+ LZO_UNUSED(u); LZO_UNUSED(p);
+ return r == 1 ? LZO_E_OK : LZO_E_ERROR;
+}
+
+int __lzo_init_done = 0;
+
+LZO_PUBLIC(int)
+__lzo_init_v2(unsigned v, int s1, int s2, int s3, int s4, int s5,
+ int s6, int s7, int s8, int s9)
+{
+ int r;
+
+#if defined(__LZO_IN_MINILZO)
+#elif (LZO_CC_MSC && ((_MSC_VER) < 700))
+#else
+#define ACC_WANT_ACC_CHK_CH 1
+#undef ACCCHK_ASSERT
+#define ACCCHK_ASSERT(expr) LZO_COMPILE_TIME_ASSERT(expr)
+#endif
+#undef ACCCHK_ASSERT
+
+ __lzo_init_done = 1;
+
+ if (v == 0)
+ return LZO_E_ERROR;
+
+ r = (s1 == -1 || s1 == (int) sizeof(short)) &&
+ (s2 == -1 || s2 == (int) sizeof(int)) &&
+ (s3 == -1 || s3 == (int) sizeof(long)) &&
+ (s4 == -1 || s4 == (int) sizeof(lzo_uint32)) &&
+ (s5 == -1 || s5 == (int) sizeof(lzo_uint)) &&
+ (s6 == -1 || s6 == (int) lzo_sizeof_dict_t) &&
+ (s7 == -1 || s7 == (int) sizeof(char *)) &&
+ (s8 == -1 || s8 == (int) sizeof(lzo_voidp)) &&
+ (s9 == -1 || s9 == (int) sizeof(lzo_callback_t));
+ if (!r)
+ return LZO_E_ERROR;
+
+ r = _lzo_config_check();
+ if (r != LZO_E_OK)
+ return r;
+
+ return r;
+}
+
+#if !defined(__LZO_IN_MINILZO)
+
+#if (LZO_OS_WIN16 && LZO_CC_WATCOMC) && defined(__SW_BD)
+
+#if 0
+BOOL FAR PASCAL LibMain ( HANDLE hInstance, WORD wDataSegment,
+ WORD wHeapSize, LPSTR lpszCmdLine )
+#else
+int __far __pascal LibMain ( int a, short b, short c, long d )
+#endif
+{
+ LZO_UNUSED(a); LZO_UNUSED(b); LZO_UNUSED(c); LZO_UNUSED(d);
+ return 1;
+}
+
+#endif
+
+#endif
+
+#define do_compress _lzo1x_1_do_compress
+
+#if !defined(MINILZO_CFG_SKIP_LZO1X_1_COMPRESS)
+
+#define LZO_NEED_DICT_H
+#define D_BITS 14
+#define D_INDEX1(d,p) d = DM(DMUL(0x21,DX3(p,5,5,6)) >> 5)
+#define D_INDEX2(d,p) d = (d & (D_MASK & 0x7ff)) ^ (D_HIGH | 0x1f)
+
+#ifndef __LZO_CONFIG1X_H
+#define __LZO_CONFIG1X_H
+
+#if !defined(LZO1X) && !defined(LZO1Y) && !defined(LZO1Z)
+# define LZO1X
+#endif
+
+#if !defined(__LZO_IN_MINILZO)
+#include "lzo/lzo1x.h"
+#endif
+
+#define LZO_EOF_CODE
+#undef LZO_DETERMINISTIC
+
+#define M1_MAX_OFFSET 0x0400
+#ifndef M2_MAX_OFFSET
+#define M2_MAX_OFFSET 0x0800
+#endif
+#define M3_MAX_OFFSET 0x4000
+#define M4_MAX_OFFSET 0xbfff
+
+#define MX_MAX_OFFSET (M1_MAX_OFFSET + M2_MAX_OFFSET)
+
+#define M1_MIN_LEN 2
+#define M1_MAX_LEN 2
+#define M2_MIN_LEN 3
+#ifndef M2_MAX_LEN
+#define M2_MAX_LEN 8
+#endif
+#define M3_MIN_LEN 3
+#define M3_MAX_LEN 33
+#define M4_MIN_LEN 3
+#define M4_MAX_LEN 9
+
+#define M1_MARKER 0
+#define M2_MARKER 64
+#define M3_MARKER 32
+#define M4_MARKER 16
+
+#ifndef MIN_LOOKAHEAD
+#define MIN_LOOKAHEAD (M2_MAX_LEN + 1)
+#endif
+
+#if defined(LZO_NEED_DICT_H)
+
+#ifndef LZO_HASH
+#define LZO_HASH LZO_HASH_LZO_INCREMENTAL_B
+#endif
+#define DL_MIN_LEN M2_MIN_LEN
+
+#ifndef __LZO_DICT_H
+#define __LZO_DICT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if !defined(D_BITS) && defined(DBITS)
+# define D_BITS DBITS
+#endif
+#if !defined(D_BITS)
+# error "D_BITS is not defined"
+#endif
+#if (D_BITS < 16)
+# define D_SIZE LZO_SIZE(D_BITS)
+# define D_MASK LZO_MASK(D_BITS)
+#else
+# define D_SIZE LZO_USIZE(D_BITS)
+# define D_MASK LZO_UMASK(D_BITS)
+#endif
+#define D_HIGH ((D_MASK >> 1) + 1)
+
+#if !defined(DD_BITS)
+# define DD_BITS 0
+#endif
+#define DD_SIZE LZO_SIZE(DD_BITS)
+#define DD_MASK LZO_MASK(DD_BITS)
+
+#if !defined(DL_BITS)
+# define DL_BITS (D_BITS - DD_BITS)
+#endif
+#if (DL_BITS < 16)
+# define DL_SIZE LZO_SIZE(DL_BITS)
+# define DL_MASK LZO_MASK(DL_BITS)
+#else
+# define DL_SIZE LZO_USIZE(DL_BITS)
+# define DL_MASK LZO_UMASK(DL_BITS)
+#endif
+
+#if (D_BITS != DL_BITS + DD_BITS)
+# error "D_BITS does not match"
+#endif
+#if (D_BITS < 8 || D_BITS > 18)
+# error "invalid D_BITS"
+#endif
+#if (DL_BITS < 8 || DL_BITS > 20)
+# error "invalid DL_BITS"
+#endif
+#if (DD_BITS < 0 || DD_BITS > 6)
+# error "invalid DD_BITS"
+#endif
+
+#if !defined(DL_MIN_LEN)
+# define DL_MIN_LEN 3
+#endif
+#if !defined(DL_SHIFT)
+# define DL_SHIFT ((DL_BITS + (DL_MIN_LEN - 1)) / DL_MIN_LEN)
+#endif
+
+#define LZO_HASH_GZIP 1
+#define LZO_HASH_GZIP_INCREMENTAL 2
+#define LZO_HASH_LZO_INCREMENTAL_A 3
+#define LZO_HASH_LZO_INCREMENTAL_B 4
+
+#if !defined(LZO_HASH)
+# error "choose a hashing strategy"
+#endif
+
+#undef DM
+#undef DX
+
+#if (DL_MIN_LEN == 3)
+# define _DV2_A(p,shift1,shift2) \
+ (((( (lzo_xint)((p)[0]) << shift1) ^ (p)[1]) << shift2) ^ (p)[2])
+# define _DV2_B(p,shift1,shift2) \
+ (((( (lzo_xint)((p)[2]) << shift1) ^ (p)[1]) << shift2) ^ (p)[0])
+# define _DV3_B(p,shift1,shift2,shift3) \
+ ((_DV2_B((p)+1,shift1,shift2) << (shift3)) ^ (p)[0])
+#elif (DL_MIN_LEN == 2)
+# define _DV2_A(p,shift1,shift2) \
+ (( (lzo_xint)(p[0]) << shift1) ^ p[1])
+# define _DV2_B(p,shift1,shift2) \
+ (( (lzo_xint)(p[1]) << shift1) ^ p[2])
+#else
+# error "invalid DL_MIN_LEN"
+#endif
+#define _DV_A(p,shift) _DV2_A(p,shift,shift)
+#define _DV_B(p,shift) _DV2_B(p,shift,shift)
+#define DA2(p,s1,s2) \
+ (((((lzo_xint)((p)[2]) << (s2)) + (p)[1]) << (s1)) + (p)[0])
+#define DS2(p,s1,s2) \
+ (((((lzo_xint)((p)[2]) << (s2)) - (p)[1]) << (s1)) - (p)[0])
+#define DX2(p,s1,s2) \
+ (((((lzo_xint)((p)[2]) << (s2)) ^ (p)[1]) << (s1)) ^ (p)[0])
+#define DA3(p,s1,s2,s3) ((DA2((p)+1,s2,s3) << (s1)) + (p)[0])
+#define DS3(p,s1,s2,s3) ((DS2((p)+1,s2,s3) << (s1)) - (p)[0])
+#define DX3(p,s1,s2,s3) ((DX2((p)+1,s2,s3) << (s1)) ^ (p)[0])
+#define DMS(v,s) ((lzo_uint) (((v) & (D_MASK >> (s))) << (s)))
+#define DM(v) DMS(v,0)
+
+#if (LZO_HASH == LZO_HASH_GZIP)
+# define _DINDEX(dv,p) (_DV_A((p),DL_SHIFT))
+
+#elif (LZO_HASH == LZO_HASH_GZIP_INCREMENTAL)
+# define __LZO_HASH_INCREMENTAL
+# define DVAL_FIRST(dv,p) dv = _DV_A((p),DL_SHIFT)
+# define DVAL_NEXT(dv,p) dv = (((dv) << DL_SHIFT) ^ p[2])
+# define _DINDEX(dv,p) (dv)
+# define DVAL_LOOKAHEAD DL_MIN_LEN
+
+#elif (LZO_HASH == LZO_HASH_LZO_INCREMENTAL_A)
+# define __LZO_HASH_INCREMENTAL
+# define DVAL_FIRST(dv,p) dv = _DV_A((p),5)
+# define DVAL_NEXT(dv,p) \
+ dv ^= (lzo_xint)(p[-1]) << (2*5); dv = (((dv) << 5) ^ p[2])
+# define _DINDEX(dv,p) ((DMUL(0x9f5f,dv)) >> 5)
+# define DVAL_LOOKAHEAD DL_MIN_LEN
+
+#elif (LZO_HASH == LZO_HASH_LZO_INCREMENTAL_B)
+# define __LZO_HASH_INCREMENTAL
+# define DVAL_FIRST(dv,p) dv = _DV_B((p),5)
+# define DVAL_NEXT(dv,p) \
+ dv ^= p[-1]; dv = (((dv) >> 5) ^ ((lzo_xint)(p[2]) << (2*5)))
+# define _DINDEX(dv,p) ((DMUL(0x9f5f,dv)) >> 5)
+# define DVAL_LOOKAHEAD DL_MIN_LEN
+
+#else
+# error "choose a hashing strategy"
+#endif
+
+#ifndef DINDEX
+#define DINDEX(dv,p) ((lzo_uint)((_DINDEX(dv,p)) & DL_MASK) << DD_BITS)
+#endif
+#if !defined(DINDEX1) && defined(D_INDEX1)
+#define DINDEX1 D_INDEX1
+#endif
+#if !defined(DINDEX2) && defined(D_INDEX2)
+#define DINDEX2 D_INDEX2
+#endif
+
+#if !defined(__LZO_HASH_INCREMENTAL)
+# define DVAL_FIRST(dv,p) ((void) 0)
+# define DVAL_NEXT(dv,p) ((void) 0)
+# define DVAL_LOOKAHEAD 0
+#endif
+
+#if !defined(DVAL_ASSERT)
+#if defined(__LZO_HASH_INCREMENTAL) && !defined(NDEBUG)
+static void DVAL_ASSERT(lzo_xint dv, const lzo_bytep p)
+{
+ lzo_xint df;
+ DVAL_FIRST(df,(p));
+ assert(DINDEX(dv,p) == DINDEX(df,p));
+}
+#else
+# define DVAL_ASSERT(dv,p) ((void) 0)
+#endif
+#endif
+
+#if defined(LZO_DICT_USE_PTR)
+# define DENTRY(p,in) (p)
+# define GINDEX(m_pos,m_off,dict,dindex,in) m_pos = dict[dindex]
+#else
+# define DENTRY(p,in) ((lzo_uint) ((p)-(in)))
+# define GINDEX(m_pos,m_off,dict,dindex,in) m_off = dict[dindex]
+#endif
+
+#if (DD_BITS == 0)
+
+# define UPDATE_D(dict,drun,dv,p,in) dict[ DINDEX(dv,p) ] = DENTRY(p,in)
+# define UPDATE_I(dict,drun,index,p,in) dict[index] = DENTRY(p,in)
+# define UPDATE_P(ptr,drun,p,in) (ptr)[0] = DENTRY(p,in)
+
+#else
+
+# define UPDATE_D(dict,drun,dv,p,in) \
+ dict[ DINDEX(dv,p) + drun++ ] = DENTRY(p,in); drun &= DD_MASK
+# define UPDATE_I(dict,drun,index,p,in) \
+ dict[ (index) + drun++ ] = DENTRY(p,in); drun &= DD_MASK
+# define UPDATE_P(ptr,drun,p,in) \
+ (ptr) [ drun++ ] = DENTRY(p,in); drun &= DD_MASK
+
+#endif
+
+#if defined(LZO_DICT_USE_PTR)
+
+#define LZO_CHECK_MPOS_DET(m_pos,m_off,in,ip,max_offset) \
+ (m_pos == NULL || (m_off = pd(ip, m_pos)) > max_offset)
+
+#define LZO_CHECK_MPOS_NON_DET(m_pos,m_off,in,ip,max_offset) \
+ (BOUNDS_CHECKING_OFF_IN_EXPR(( \
+ m_pos = ip - (lzo_uint) PTR_DIFF(ip,m_pos), \
+ PTR_LT(m_pos,in) || \
+ (m_off = (lzo_uint) PTR_DIFF(ip,m_pos)) <= 0 || \
+ m_off > max_offset )))
+
+#else
+
+#define LZO_CHECK_MPOS_DET(m_pos,m_off,in,ip,max_offset) \
+ (m_off == 0 || \
+ ((m_off = pd(ip, in) - m_off) > max_offset) || \
+ (m_pos = (ip) - (m_off), 0) )
+
+#define LZO_CHECK_MPOS_NON_DET(m_pos,m_off,in,ip,max_offset) \
+ (pd(ip, in) <= m_off || \
+ ((m_off = pd(ip, in) - m_off) > max_offset) || \
+ (m_pos = (ip) - (m_off), 0) )
+
+#endif
+
+#if defined(LZO_DETERMINISTIC)
+# define LZO_CHECK_MPOS LZO_CHECK_MPOS_DET
+#else
+# define LZO_CHECK_MPOS LZO_CHECK_MPOS_NON_DET
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+#endif
+
+#endif
+
+#define DO_COMPRESS lzo1x_1_compress
+
+static __lzo_noinline lzo_uint
+do_compress ( const lzo_bytep in , lzo_uint in_len,
+ lzo_bytep out, lzo_uintp out_len,
+ lzo_voidp wrkmem )
+{
+ register const lzo_bytep ip;
+ lzo_bytep op;
+ const lzo_bytep const in_end = in + in_len;
+ const lzo_bytep const ip_end = in + in_len - M2_MAX_LEN - 5;
+ const lzo_bytep ii;
+ lzo_dict_p const dict = (lzo_dict_p) wrkmem;
+
+ op = out;
+ ip = in;
+ ii = ip;
+
+ ip += 4;
+ for (;;)
+ {
+ register const lzo_bytep m_pos;
+ lzo_uint m_off;
+ lzo_uint m_len;
+ lzo_uint dindex;
+
+ DINDEX1(dindex,ip);
+ GINDEX(m_pos,m_off,dict,dindex,in);
+ if (LZO_CHECK_MPOS_NON_DET(m_pos,m_off,in,ip,M4_MAX_OFFSET))
+ goto literal;
+#if 1
+ if (m_off <= M2_MAX_OFFSET || m_pos[3] == ip[3])
+ goto try_match;
+ DINDEX2(dindex,ip);
+#endif
+ GINDEX(m_pos,m_off,dict,dindex,in);
+ if (LZO_CHECK_MPOS_NON_DET(m_pos,m_off,in,ip,M4_MAX_OFFSET))
+ goto literal;
+ if (m_off <= M2_MAX_OFFSET || m_pos[3] == ip[3])
+ goto try_match;
+ goto literal;
+
+try_match:
+#if 1 && defined(LZO_UNALIGNED_OK_2)
+ if (* (const lzo_ushortp) m_pos != * (const lzo_ushortp) ip)
+#else
+ if (m_pos[0] != ip[0] || m_pos[1] != ip[1])
+#endif
+ {
+ }
+ else
+ {
+ if __lzo_likely(m_pos[2] == ip[2])
+ {
+#if 0
+ if (m_off <= M2_MAX_OFFSET)
+ goto match;
+ if (lit <= 3)
+ goto match;
+ if (lit == 3)
+ {
+ assert(op - 2 > out); op[-2] |= LZO_BYTE(3);
+ *op++ = *ii++; *op++ = *ii++; *op++ = *ii++;
+ goto code_match;
+ }
+ if (m_pos[3] == ip[3])
+#endif
+ goto match;
+ }
+ else
+ {
+#if 0
+#if 0
+ if (m_off <= M1_MAX_OFFSET && lit > 0 && lit <= 3)
+#else
+ if (m_off <= M1_MAX_OFFSET && lit == 3)
+#endif
+ {
+ register lzo_uint t;
+
+ t = lit;
+ assert(op - 2 > out); op[-2] |= LZO_BYTE(t);
+ do *op++ = *ii++; while (--t > 0);
+ assert(ii == ip);
+ m_off -= 1;
+ *op++ = LZO_BYTE(M1_MARKER | ((m_off & 3) << 2));
+ *op++ = LZO_BYTE(m_off >> 2);
+ ip += 2;
+ goto match_done;
+ }
+#endif
+ }
+ }
+
+literal:
+ UPDATE_I(dict,0,dindex,ip,in);
+ ++ip;
+ if __lzo_unlikely(ip >= ip_end)
+ break;
+ continue;
+
+match:
+ UPDATE_I(dict,0,dindex,ip,in);
+ if (pd(ip,ii) > 0)
+ {
+ register lzo_uint t = pd(ip,ii);
+
+ if (t <= 3)
+ {
+ assert(op - 2 > out);
+ op[-2] |= LZO_BYTE(t);
+ }
+ else if (t <= 18)
+ *op++ = LZO_BYTE(t - 3);
+ else
+ {
+ register lzo_uint tt = t - 18;
+
+ *op++ = 0;
+ while (tt > 255)
+ {
+ tt -= 255;
+ *op++ = 0;
+ }
+ assert(tt > 0);
+ *op++ = LZO_BYTE(tt);
+ }
+ do *op++ = *ii++; while (--t > 0);
+ }
+
+ assert(ii == ip);
+ ip += 3;
+ if (m_pos[3] != *ip++ || m_pos[4] != *ip++ || m_pos[5] != *ip++ ||
+ m_pos[6] != *ip++ || m_pos[7] != *ip++ || m_pos[8] != *ip++
+#ifdef LZO1Y
+ || m_pos[ 9] != *ip++ || m_pos[10] != *ip++ || m_pos[11] != *ip++
+ || m_pos[12] != *ip++ || m_pos[13] != *ip++ || m_pos[14] != *ip++
+#endif
+ )
+ {
+ --ip;
+ m_len = pd(ip, ii);
+ assert(m_len >= 3); assert(m_len <= M2_MAX_LEN);
+
+ if (m_off <= M2_MAX_OFFSET)
+ {
+ m_off -= 1;
+#if defined(LZO1X)
+ *op++ = LZO_BYTE(((m_len - 1) << 5) | ((m_off & 7) << 2));
+ *op++ = LZO_BYTE(m_off >> 3);
+#elif defined(LZO1Y)
+ *op++ = LZO_BYTE(((m_len + 1) << 4) | ((m_off & 3) << 2));
+ *op++ = LZO_BYTE(m_off >> 2);
+#endif
+ }
+ else if (m_off <= M3_MAX_OFFSET)
+ {
+ m_off -= 1;
+ *op++ = LZO_BYTE(M3_MARKER | (m_len - 2));
+ goto m3_m4_offset;
+ }
+ else
+#if defined(LZO1X)
+ {
+ m_off -= 0x4000;
+ assert(m_off > 0); assert(m_off <= 0x7fff);
+ *op++ = LZO_BYTE(M4_MARKER |
+ ((m_off & 0x4000) >> 11) | (m_len - 2));
+ goto m3_m4_offset;
+ }
+#elif defined(LZO1Y)
+ goto m4_match;
+#endif
+ }
+ else
+ {
+ {
+ const lzo_bytep end = in_end;
+ const lzo_bytep m = m_pos + M2_MAX_LEN + 1;
+ while (ip < end && *m == *ip)
+ m++, ip++;
+ m_len = pd(ip, ii);
+ }
+ assert(m_len > M2_MAX_LEN);
+
+ if (m_off <= M3_MAX_OFFSET)
+ {
+ m_off -= 1;
+ if (m_len <= 33)
+ *op++ = LZO_BYTE(M3_MARKER | (m_len - 2));
+ else
+ {
+ m_len -= 33;
+ *op++ = M3_MARKER | 0;
+ goto m3_m4_len;
+ }
+ }
+ else
+ {
+#if defined(LZO1Y)
+m4_match:
+#endif
+ m_off -= 0x4000;
+ assert(m_off > 0); assert(m_off <= 0x7fff);
+ if (m_len <= M4_MAX_LEN)
+ *op++ = LZO_BYTE(M4_MARKER |
+ ((m_off & 0x4000) >> 11) | (m_len - 2));
+ else
+ {
+ m_len -= M4_MAX_LEN;
+ *op++ = LZO_BYTE(M4_MARKER | ((m_off & 0x4000) >> 11));
+m3_m4_len:
+ while (m_len > 255)
+ {
+ m_len -= 255;
+ *op++ = 0;
+ }
+ assert(m_len > 0);
+ *op++ = LZO_BYTE(m_len);
+ }
+ }
+
+m3_m4_offset:
+ *op++ = LZO_BYTE((m_off & 63) << 2);
+ *op++ = LZO_BYTE(m_off >> 6);
+ }
+
+#if 0
+match_done:
+#endif
+ ii = ip;
+ if __lzo_unlikely(ip >= ip_end)
+ break;
+ }
+
+ *out_len = pd(op, out);
+ return pd(in_end,ii);
+}
+
+LZO_PUBLIC(int)
+DO_COMPRESS ( const lzo_bytep in , lzo_uint in_len,
+ lzo_bytep out, lzo_uintp out_len,
+ lzo_voidp wrkmem )
+{
+ lzo_bytep op = out;
+ lzo_uint t;
+
+ if __lzo_unlikely(in_len <= M2_MAX_LEN + 5)
+ t = in_len;
+ else
+ {
+ t = do_compress(in,in_len,op,out_len,wrkmem);
+ op += *out_len;
+ }
+
+ if (t > 0)
+ {
+ const lzo_bytep ii = in + in_len - t;
+
+ if (op == out && t <= 238)
+ *op++ = LZO_BYTE(17 + t);
+ else if (t <= 3)
+ op[-2] |= LZO_BYTE(t);
+ else if (t <= 18)
+ *op++ = LZO_BYTE(t - 3);
+ else
+ {
+ lzo_uint tt = t - 18;
+
+ *op++ = 0;
+ while (tt > 255)
+ {
+ tt -= 255;
+ *op++ = 0;
+ }
+ assert(tt > 0);
+ *op++ = LZO_BYTE(tt);
+ }
+ do *op++ = *ii++; while (--t > 0);
+ }
+
+ *op++ = M4_MARKER | 1;
+ *op++ = 0;
+ *op++ = 0;
+
+ *out_len = pd(op, out);
+ return LZO_E_OK;
+}
+
+#endif
+
+#undef do_compress
+#undef DO_COMPRESS
+#undef LZO_HASH
+
+#undef LZO_TEST_OVERRUN
+#undef DO_DECOMPRESS
+#define DO_DECOMPRESS lzo1x_decompress
+
+#if !defined(MINILZO_CFG_SKIP_LZO1X_DECOMPRESS)
+
+#if defined(LZO_TEST_OVERRUN)
+# if !defined(LZO_TEST_OVERRUN_INPUT)
+# define LZO_TEST_OVERRUN_INPUT 2
+# endif
+# if !defined(LZO_TEST_OVERRUN_OUTPUT)
+# define LZO_TEST_OVERRUN_OUTPUT 2
+# endif
+# if !defined(LZO_TEST_OVERRUN_LOOKBEHIND)
+# define LZO_TEST_OVERRUN_LOOKBEHIND
+# endif
+#endif
+
+#undef TEST_IP
+#undef TEST_OP
+#undef TEST_LB
+#undef TEST_LBO
+#undef NEED_IP
+#undef NEED_OP
+#undef HAVE_TEST_IP
+#undef HAVE_TEST_OP
+#undef HAVE_NEED_IP
+#undef HAVE_NEED_OP
+#undef HAVE_ANY_IP
+#undef HAVE_ANY_OP
+
+#if defined(LZO_TEST_OVERRUN_INPUT)
+# if (LZO_TEST_OVERRUN_INPUT >= 1)
+# define TEST_IP (ip < ip_end)
+# endif
+# if (LZO_TEST_OVERRUN_INPUT >= 2)
+# define NEED_IP(x) \
+ if ((lzo_uint)(ip_end - ip) < (lzo_uint)(x)) goto input_overrun
+# endif
+#endif
+
+#if defined(LZO_TEST_OVERRUN_OUTPUT)
+# if (LZO_TEST_OVERRUN_OUTPUT >= 1)
+# define TEST_OP (op <= op_end)
+# endif
+# if (LZO_TEST_OVERRUN_OUTPUT >= 2)
+# undef TEST_OP
+# define NEED_OP(x) \
+ if ((lzo_uint)(op_end - op) < (lzo_uint)(x)) goto output_overrun
+# endif
+#endif
+
+#if defined(LZO_TEST_OVERRUN_LOOKBEHIND)
+# define TEST_LB(m_pos) if (m_pos < out || m_pos >= op) goto lookbehind_overrun
+# define TEST_LBO(m_pos,o) if (m_pos < out || m_pos >= op - (o)) goto lookbehind_overrun
+#else
+# define TEST_LB(m_pos) ((void) 0)
+# define TEST_LBO(m_pos,o) ((void) 0)
+#endif
+
+#if !defined(LZO_EOF_CODE) && !defined(TEST_IP)
+# define TEST_IP (ip < ip_end)
+#endif
+
+#if defined(TEST_IP)
+# define HAVE_TEST_IP
+#else
+# define TEST_IP 1
+#endif
+#if defined(TEST_OP)
+# define HAVE_TEST_OP
+#else
+# define TEST_OP 1
+#endif
+
+#if defined(NEED_IP)
+# define HAVE_NEED_IP
+#else
+# define NEED_IP(x) ((void) 0)
+#endif
+#if defined(NEED_OP)
+# define HAVE_NEED_OP
+#else
+# define NEED_OP(x) ((void) 0)
+#endif
+
+#if defined(HAVE_TEST_IP) || defined(HAVE_NEED_IP)
+# define HAVE_ANY_IP
+#endif
+#if defined(HAVE_TEST_OP) || defined(HAVE_NEED_OP)
+# define HAVE_ANY_OP
+#endif
+
+#undef __COPY4
+#define __COPY4(dst,src) * (lzo_uint32p)(dst) = * (const lzo_uint32p)(src)
+
+#undef COPY4
+#if defined(LZO_UNALIGNED_OK_4)
+# define COPY4(dst,src) __COPY4(dst,src)
+#elif defined(LZO_ALIGNED_OK_4)
+# define COPY4(dst,src) __COPY4((lzo_uintptr_t)(dst),(lzo_uintptr_t)(src))
+#endif
+
+#if defined(DO_DECOMPRESS)
+LZO_PUBLIC(int)
+DO_DECOMPRESS ( const lzo_bytep in , lzo_uint in_len,
+ lzo_bytep out, lzo_uintp out_len,
+ lzo_voidp wrkmem )
+#endif
+{
+ register lzo_bytep op;
+ register const lzo_bytep ip;
+ register lzo_uint t;
+#if defined(COPY_DICT)
+ lzo_uint m_off;
+ const lzo_bytep dict_end;
+#else
+ register const lzo_bytep m_pos;
+#endif
+
+ const lzo_bytep const ip_end = in + in_len;
+#if defined(HAVE_ANY_OP)
+ lzo_bytep const op_end = out + *out_len;
+#endif
+#if defined(LZO1Z)
+ lzo_uint last_m_off = 0;
+#endif
+
+ LZO_UNUSED(wrkmem);
+
+#if defined(COPY_DICT)
+ if (dict)
+ {
+ if (dict_len > M4_MAX_OFFSET)
+ {
+ dict += dict_len - M4_MAX_OFFSET;
+ dict_len = M4_MAX_OFFSET;
+ }
+ dict_end = dict + dict_len;
+ }
+ else
+ {
+ dict_len = 0;
+ dict_end = NULL;
+ }
+#endif
+
+ *out_len = 0;
+
+ op = out;
+ ip = in;
+
+ if (*ip > 17)
+ {
+ t = *ip++ - 17;
+ if (t < 4)
+ goto match_next;
+ assert(t > 0); NEED_OP(t); NEED_IP(t+1);
+ do *op++ = *ip++; while (--t > 0);
+ goto first_literal_run;
+ }
+
+ while (TEST_IP && TEST_OP)
+ {
+ t = *ip++;
+ if (t >= 16)
+ goto match;
+ if (t == 0)
+ {
+ NEED_IP(1);
+ while (*ip == 0)
+ {
+ t += 255;
+ ip++;
+ NEED_IP(1);
+ }
+ t += 15 + *ip++;
+ }
+ assert(t > 0); NEED_OP(t+3); NEED_IP(t+4);
+#if defined(LZO_UNALIGNED_OK_4) || defined(LZO_ALIGNED_OK_4)
+#if !defined(LZO_UNALIGNED_OK_4)
+ if (PTR_ALIGNED2_4(op,ip))
+ {
+#endif
+ COPY4(op,ip);
+ op += 4; ip += 4;
+ if (--t > 0)
+ {
+ if (t >= 4)
+ {
+ do {
+ COPY4(op,ip);
+ op += 4; ip += 4; t -= 4;
+ } while (t >= 4);
+ if (t > 0) do *op++ = *ip++; while (--t > 0);
+ }
+ else
+ do *op++ = *ip++; while (--t > 0);
+ }
+#if !defined(LZO_UNALIGNED_OK_4)
+ }
+ else
+#endif
+#endif
+#if !defined(LZO_UNALIGNED_OK_4)
+ {
+ *op++ = *ip++; *op++ = *ip++; *op++ = *ip++;
+ do *op++ = *ip++; while (--t > 0);
+ }
+#endif
+
+first_literal_run:
+
+ t = *ip++;
+ if (t >= 16)
+ goto match;
+#if defined(COPY_DICT)
+#if defined(LZO1Z)
+ m_off = (1 + M2_MAX_OFFSET) + (t << 6) + (*ip++ >> 2);
+ last_m_off = m_off;
+#else
+ m_off = (1 + M2_MAX_OFFSET) + (t >> 2) + (*ip++ << 2);
+#endif
+ NEED_OP(3);
+ t = 3; COPY_DICT(t,m_off)
+#else
+#if defined(LZO1Z)
+ t = (1 + M2_MAX_OFFSET) + (t << 6) + (*ip++ >> 2);
+ m_pos = op - t;
+ last_m_off = t;
+#else
+ m_pos = op - (1 + M2_MAX_OFFSET);
+ m_pos -= t >> 2;
+ m_pos -= *ip++ << 2;
+#endif
+ TEST_LB(m_pos); NEED_OP(3);
+ *op++ = *m_pos++; *op++ = *m_pos++; *op++ = *m_pos;
+#endif
+ goto match_done;
+
+ do {
+match:
+ if (t >= 64)
+ {
+#if defined(COPY_DICT)
+#if defined(LZO1X)
+ m_off = 1 + ((t >> 2) & 7) + (*ip++ << 3);
+ t = (t >> 5) - 1;
+#elif defined(LZO1Y)
+ m_off = 1 + ((t >> 2) & 3) + (*ip++ << 2);
+ t = (t >> 4) - 3;
+#elif defined(LZO1Z)
+ m_off = t & 0x1f;
+ if (m_off >= 0x1c)
+ m_off = last_m_off;
+ else
+ {
+ m_off = 1 + (m_off << 6) + (*ip++ >> 2);
+ last_m_off = m_off;
+ }
+ t = (t >> 5) - 1;
+#endif
+#else
+#if defined(LZO1X)
+ m_pos = op - 1;
+ m_pos -= (t >> 2) & 7;
+ m_pos -= *ip++ << 3;
+ t = (t >> 5) - 1;
+#elif defined(LZO1Y)
+ m_pos = op - 1;
+ m_pos -= (t >> 2) & 3;
+ m_pos -= *ip++ << 2;
+ t = (t >> 4) - 3;
+#elif defined(LZO1Z)
+ {
+ lzo_uint off = t & 0x1f;
+ m_pos = op;
+ if (off >= 0x1c)
+ {
+ assert(last_m_off > 0);
+ m_pos -= last_m_off;
+ }
+ else
+ {
+ off = 1 + (off << 6) + (*ip++ >> 2);
+ m_pos -= off;
+ last_m_off = off;
+ }
+ }
+ t = (t >> 5) - 1;
+#endif
+ TEST_LB(m_pos); assert(t > 0); NEED_OP(t+3-1);
+ goto copy_match;
+#endif
+ }
+ else if (t >= 32)
+ {
+ t &= 31;
+ if (t == 0)
+ {
+ NEED_IP(1);
+ while (*ip == 0)
+ {
+ t += 255;
+ ip++;
+ NEED_IP(1);
+ }
+ t += 31 + *ip++;
+ }
+#if defined(COPY_DICT)
+#if defined(LZO1Z)
+ m_off = 1 + (ip[0] << 6) + (ip[1] >> 2);
+ last_m_off = m_off;
+#else
+ m_off = 1 + (ip[0] >> 2) + (ip[1] << 6);
+#endif
+#else
+#if defined(LZO1Z)
+ {
+ lzo_uint off = 1 + (ip[0] << 6) + (ip[1] >> 2);
+ m_pos = op - off;
+ last_m_off = off;
+ }
+#elif defined(LZO_UNALIGNED_OK_2) && defined(LZO_ABI_LITTLE_ENDIAN)
+ m_pos = op - 1;
+ m_pos -= (* (const lzo_ushortp) ip) >> 2;
+#else
+ m_pos = op - 1;
+ m_pos -= (ip[0] >> 2) + (ip[1] << 6);
+#endif
+#endif
+ ip += 2;
+ }
+ else if (t >= 16)
+ {
+#if defined(COPY_DICT)
+ m_off = (t & 8) << 11;
+#else
+ m_pos = op;
+ m_pos -= (t & 8) << 11;
+#endif
+ t &= 7;
+ if (t == 0)
+ {
+ NEED_IP(1);
+ while (*ip == 0)
+ {
+ t += 255;
+ ip++;
+ NEED_IP(1);
+ }
+ t += 7 + *ip++;
+ }
+#if defined(COPY_DICT)
+#if defined(LZO1Z)
+ m_off += (ip[0] << 6) + (ip[1] >> 2);
+#else
+ m_off += (ip[0] >> 2) + (ip[1] << 6);
+#endif
+ ip += 2;
+ if (m_off == 0)
+ goto eof_found;
+ m_off += 0x4000;
+#if defined(LZO1Z)
+ last_m_off = m_off;
+#endif
+#else
+#if defined(LZO1Z)
+ m_pos -= (ip[0] << 6) + (ip[1] >> 2);
+#elif defined(LZO_UNALIGNED_OK_2) && defined(LZO_ABI_LITTLE_ENDIAN)
+ m_pos -= (* (const lzo_ushortp) ip) >> 2;
+#else
+ m_pos -= (ip[0] >> 2) + (ip[1] << 6);
+#endif
+ ip += 2;
+ if (m_pos == op)
+ goto eof_found;
+ m_pos -= 0x4000;
+#if defined(LZO1Z)
+ last_m_off = pd((const lzo_bytep)op, m_pos);
+#endif
+#endif
+ }
+ else
+ {
+#if defined(COPY_DICT)
+#if defined(LZO1Z)
+ m_off = 1 + (t << 6) + (*ip++ >> 2);
+ last_m_off = m_off;
+#else
+ m_off = 1 + (t >> 2) + (*ip++ << 2);
+#endif
+ NEED_OP(2);
+ t = 2; COPY_DICT(t,m_off)
+#else
+#if defined(LZO1Z)
+ t = 1 + (t << 6) + (*ip++ >> 2);
+ m_pos = op - t;
+ last_m_off = t;
+#else
+ m_pos = op - 1;
+ m_pos -= t >> 2;
+ m_pos -= *ip++ << 2;
+#endif
+ TEST_LB(m_pos); NEED_OP(2);
+ *op++ = *m_pos++; *op++ = *m_pos;
+#endif
+ goto match_done;
+ }
+
+#if defined(COPY_DICT)
+
+ NEED_OP(t+3-1);
+ t += 3-1; COPY_DICT(t,m_off)
+
+#else
+
+ TEST_LB(m_pos); assert(t > 0); NEED_OP(t+3-1);
+#if defined(LZO_UNALIGNED_OK_4) || defined(LZO_ALIGNED_OK_4)
+#if !defined(LZO_UNALIGNED_OK_4)
+ if (t >= 2 * 4 - (3 - 1) && PTR_ALIGNED2_4(op,m_pos))
+ {
+ assert((op - m_pos) >= 4);
+#else
+ if (t >= 2 * 4 - (3 - 1) && (op - m_pos) >= 4)
+ {
+#endif
+ COPY4(op,m_pos);
+ op += 4; m_pos += 4; t -= 4 - (3 - 1);
+ do {
+ COPY4(op,m_pos);
+ op += 4; m_pos += 4; t -= 4;
+ } while (t >= 4);
+ if (t > 0) do *op++ = *m_pos++; while (--t > 0);
+ }
+ else
+#endif
+ {
+copy_match:
+ *op++ = *m_pos++; *op++ = *m_pos++;
+ do *op++ = *m_pos++; while (--t > 0);
+ }
+
+#endif
+
+match_done:
+#if defined(LZO1Z)
+ t = ip[-1] & 3;
+#else
+ t = ip[-2] & 3;
+#endif
+ if (t == 0)
+ break;
+
+match_next:
+ assert(t > 0); assert(t < 4); NEED_OP(t); NEED_IP(t+1);
+#if 0
+ do *op++ = *ip++; while (--t > 0);
+#else
+ *op++ = *ip++;
+ if (t > 1) { *op++ = *ip++; if (t > 2) { *op++ = *ip++; } }
+#endif
+ t = *ip++;
+ } while (TEST_IP && TEST_OP);
+ }
+
+#if defined(HAVE_TEST_IP) || defined(HAVE_TEST_OP)
+ *out_len = pd(op, out);
+ return LZO_E_EOF_NOT_FOUND;
+#endif
+
+eof_found:
+ assert(t == 1);
+ *out_len = pd(op, out);
+ return (ip == ip_end ? LZO_E_OK :
+ (ip < ip_end ? LZO_E_INPUT_NOT_CONSUMED : LZO_E_INPUT_OVERRUN));
+
+#if defined(HAVE_NEED_IP)
+input_overrun:
+ *out_len = pd(op, out);
+ return LZO_E_INPUT_OVERRUN;
+#endif
+
+#if defined(HAVE_NEED_OP)
+output_overrun:
+ *out_len = pd(op, out);
+ return LZO_E_OUTPUT_OVERRUN;
+#endif
+
+#if defined(LZO_TEST_OVERRUN_LOOKBEHIND)
+lookbehind_overrun:
+ *out_len = pd(op, out);
+ return LZO_E_LOOKBEHIND_OVERRUN;
+#endif
+}
+
+#endif
+
+#define LZO_TEST_OVERRUN
+#undef DO_DECOMPRESS
+#define DO_DECOMPRESS lzo1x_decompress_safe
+
+#if !defined(MINILZO_CFG_SKIP_LZO1X_DECOMPRESS_SAFE)
+
+#if defined(LZO_TEST_OVERRUN)
+# if !defined(LZO_TEST_OVERRUN_INPUT)
+# define LZO_TEST_OVERRUN_INPUT 2
+# endif
+# if !defined(LZO_TEST_OVERRUN_OUTPUT)
+# define LZO_TEST_OVERRUN_OUTPUT 2
+# endif
+# if !defined(LZO_TEST_OVERRUN_LOOKBEHIND)
+# define LZO_TEST_OVERRUN_LOOKBEHIND
+# endif
+#endif
+
+#undef TEST_IP
+#undef TEST_OP
+#undef TEST_LB
+#undef TEST_LBO
+#undef NEED_IP
+#undef NEED_OP
+#undef HAVE_TEST_IP
+#undef HAVE_TEST_OP
+#undef HAVE_NEED_IP
+#undef HAVE_NEED_OP
+#undef HAVE_ANY_IP
+#undef HAVE_ANY_OP
+
+#if defined(LZO_TEST_OVERRUN_INPUT)
+# if (LZO_TEST_OVERRUN_INPUT >= 1)
+# define TEST_IP (ip < ip_end)
+# endif
+# if (LZO_TEST_OVERRUN_INPUT >= 2)
+# define NEED_IP(x) \
+ if ((lzo_uint)(ip_end - ip) < (lzo_uint)(x)) goto input_overrun
+# endif
+#endif
+
+#if defined(LZO_TEST_OVERRUN_OUTPUT)
+# if (LZO_TEST_OVERRUN_OUTPUT >= 1)
+# define TEST_OP (op <= op_end)
+# endif
+# if (LZO_TEST_OVERRUN_OUTPUT >= 2)
+# undef TEST_OP
+# define NEED_OP(x) \
+ if ((lzo_uint)(op_end - op) < (lzo_uint)(x)) goto output_overrun
+# endif
+#endif
+
+#if defined(LZO_TEST_OVERRUN_LOOKBEHIND)
+# define TEST_LB(m_pos) if (m_pos < out || m_pos >= op) goto lookbehind_overrun
+# define TEST_LBO(m_pos,o) if (m_pos < out || m_pos >= op - (o)) goto lookbehind_overrun
+#else
+# define TEST_LB(m_pos) ((void) 0)
+# define TEST_LBO(m_pos,o) ((void) 0)
+#endif
+
+#if !defined(LZO_EOF_CODE) && !defined(TEST_IP)
+# define TEST_IP (ip < ip_end)
+#endif
+
+#if defined(TEST_IP)
+# define HAVE_TEST_IP
+#else
+# define TEST_IP 1
+#endif
+#if defined(TEST_OP)
+# define HAVE_TEST_OP
+#else
+# define TEST_OP 1
+#endif
+
+#if defined(NEED_IP)
+# define HAVE_NEED_IP
+#else
+# define NEED_IP(x) ((void) 0)
+#endif
+#if defined(NEED_OP)
+# define HAVE_NEED_OP
+#else
+# define NEED_OP(x) ((void) 0)
+#endif
+
+#if defined(HAVE_TEST_IP) || defined(HAVE_NEED_IP)
+# define HAVE_ANY_IP
+#endif
+#if defined(HAVE_TEST_OP) || defined(HAVE_NEED_OP)
+# define HAVE_ANY_OP
+#endif
+
+#undef __COPY4
+#define __COPY4(dst,src) * (lzo_uint32p)(dst) = * (const lzo_uint32p)(src)
+
+#undef COPY4
+#if defined(LZO_UNALIGNED_OK_4)
+# define COPY4(dst,src) __COPY4(dst,src)
+#elif defined(LZO_ALIGNED_OK_4)
+# define COPY4(dst,src) __COPY4((lzo_uintptr_t)(dst),(lzo_uintptr_t)(src))
+#endif
+
+#if defined(DO_DECOMPRESS)
+LZO_PUBLIC(int)
+DO_DECOMPRESS ( const lzo_bytep in , lzo_uint in_len,
+ lzo_bytep out, lzo_uintp out_len,
+ lzo_voidp wrkmem )
+#endif
+{
+ register lzo_bytep op;
+ register const lzo_bytep ip;
+ register lzo_uint t;
+#if defined(COPY_DICT)
+ lzo_uint m_off;
+ const lzo_bytep dict_end;
+#else
+ register const lzo_bytep m_pos;
+#endif
+
+ const lzo_bytep const ip_end = in + in_len;
+#if defined(HAVE_ANY_OP)
+ lzo_bytep const op_end = out + *out_len;
+#endif
+#if defined(LZO1Z)
+ lzo_uint last_m_off = 0;
+#endif
+
+ LZO_UNUSED(wrkmem);
+
+#if defined(COPY_DICT)
+ if (dict)
+ {
+ if (dict_len > M4_MAX_OFFSET)
+ {
+ dict += dict_len - M4_MAX_OFFSET;
+ dict_len = M4_MAX_OFFSET;
+ }
+ dict_end = dict + dict_len;
+ }
+ else
+ {
+ dict_len = 0;
+ dict_end = NULL;
+ }
+#endif
+
+ *out_len = 0;
+
+ op = out;
+ ip = in;
+
+ if (*ip > 17)
+ {
+ t = *ip++ - 17;
+ if (t < 4)
+ goto match_next;
+ assert(t > 0); NEED_OP(t); NEED_IP(t+1);
+ do *op++ = *ip++; while (--t > 0);
+ goto first_literal_run;
+ }
+
+ while (TEST_IP && TEST_OP)
+ {
+ t = *ip++;
+ if (t >= 16)
+ goto match;
+ if (t == 0)
+ {
+ NEED_IP(1);
+ while (*ip == 0)
+ {
+ t += 255;
+ ip++;
+ NEED_IP(1);
+ }
+ t += 15 + *ip++;
+ }
+ assert(t > 0); NEED_OP(t+3); NEED_IP(t+4);
+#if defined(LZO_UNALIGNED_OK_4) || defined(LZO_ALIGNED_OK_4)
+#if !defined(LZO_UNALIGNED_OK_4)
+ if (PTR_ALIGNED2_4(op,ip))
+ {
+#endif
+ COPY4(op,ip);
+ op += 4; ip += 4;
+ if (--t > 0)
+ {
+ if (t >= 4)
+ {
+ do {
+ COPY4(op,ip);
+ op += 4; ip += 4; t -= 4;
+ } while (t >= 4);
+ if (t > 0) do *op++ = *ip++; while (--t > 0);
+ }
+ else
+ do *op++ = *ip++; while (--t > 0);
+ }
+#if !defined(LZO_UNALIGNED_OK_4)
+ }
+ else
+#endif
+#endif
+#if !defined(LZO_UNALIGNED_OK_4)
+ {
+ *op++ = *ip++; *op++ = *ip++; *op++ = *ip++;
+ do *op++ = *ip++; while (--t > 0);
+ }
+#endif
+
+first_literal_run:
+
+ t = *ip++;
+ if (t >= 16)
+ goto match;
+#if defined(COPY_DICT)
+#if defined(LZO1Z)
+ m_off = (1 + M2_MAX_OFFSET) + (t << 6) + (*ip++ >> 2);
+ last_m_off = m_off;
+#else
+ m_off = (1 + M2_MAX_OFFSET) + (t >> 2) + (*ip++ << 2);
+#endif
+ NEED_OP(3);
+ t = 3; COPY_DICT(t,m_off)
+#else
+#if defined(LZO1Z)
+ t = (1 + M2_MAX_OFFSET) + (t << 6) + (*ip++ >> 2);
+ m_pos = op - t;
+ last_m_off = t;
+#else
+ m_pos = op - (1 + M2_MAX_OFFSET);
+ m_pos -= t >> 2;
+ m_pos -= *ip++ << 2;
+#endif
+ TEST_LB(m_pos); NEED_OP(3);
+ *op++ = *m_pos++; *op++ = *m_pos++; *op++ = *m_pos;
+#endif
+ goto match_done;
+
+ do {
+match:
+ if (t >= 64)
+ {
+#if defined(COPY_DICT)
+#if defined(LZO1X)
+ m_off = 1 + ((t >> 2) & 7) + (*ip++ << 3);
+ t = (t >> 5) - 1;
+#elif defined(LZO1Y)
+ m_off = 1 + ((t >> 2) & 3) + (*ip++ << 2);
+ t = (t >> 4) - 3;
+#elif defined(LZO1Z)
+ m_off = t & 0x1f;
+ if (m_off >= 0x1c)
+ m_off = last_m_off;
+ else
+ {
+ m_off = 1 + (m_off << 6) + (*ip++ >> 2);
+ last_m_off = m_off;
+ }
+ t = (t >> 5) - 1;
+#endif
+#else
+#if defined(LZO1X)
+ m_pos = op - 1;
+ m_pos -= (t >> 2) & 7;
+ m_pos -= *ip++ << 3;
+ t = (t >> 5) - 1;
+#elif defined(LZO1Y)
+ m_pos = op - 1;
+ m_pos -= (t >> 2) & 3;
+ m_pos -= *ip++ << 2;
+ t = (t >> 4) - 3;
+#elif defined(LZO1Z)
+ {
+ lzo_uint off = t & 0x1f;
+ m_pos = op;
+ if (off >= 0x1c)
+ {
+ assert(last_m_off > 0);
+ m_pos -= last_m_off;
+ }
+ else
+ {
+ off = 1 + (off << 6) + (*ip++ >> 2);
+ m_pos -= off;
+ last_m_off = off;
+ }
+ }
+ t = (t >> 5) - 1;
+#endif
+ TEST_LB(m_pos); assert(t > 0); NEED_OP(t+3-1);
+ goto copy_match;
+#endif
+ }
+ else if (t >= 32)
+ {
+ t &= 31;
+ if (t == 0)
+ {
+ NEED_IP(1);
+ while (*ip == 0)
+ {
+ t += 255;
+ ip++;
+ NEED_IP(1);
+ }
+ t += 31 + *ip++;
+ }
+#if defined(COPY_DICT)
+#if defined(LZO1Z)
+ m_off = 1 + (ip[0] << 6) + (ip[1] >> 2);
+ last_m_off = m_off;
+#else
+ m_off = 1 + (ip[0] >> 2) + (ip[1] << 6);
+#endif
+#else
+#if defined(LZO1Z)
+ {
+ lzo_uint off = 1 + (ip[0] << 6) + (ip[1] >> 2);
+ m_pos = op - off;
+ last_m_off = off;
+ }
+#elif defined(LZO_UNALIGNED_OK_2) && defined(LZO_ABI_LITTLE_ENDIAN)
+ m_pos = op - 1;
+ m_pos -= (* (const lzo_ushortp) ip) >> 2;
+#else
+ m_pos = op - 1;
+ m_pos -= (ip[0] >> 2) + (ip[1] << 6);
+#endif
+#endif
+ ip += 2;
+ }
+ else if (t >= 16)
+ {
+#if defined(COPY_DICT)
+ m_off = (t & 8) << 11;
+#else
+ m_pos = op;
+ m_pos -= (t & 8) << 11;
+#endif
+ t &= 7;
+ if (t == 0)
+ {
+ NEED_IP(1);
+ while (*ip == 0)
+ {
+ t += 255;
+ ip++;
+ NEED_IP(1);
+ }
+ t += 7 + *ip++;
+ }
+#if defined(COPY_DICT)
+#if defined(LZO1Z)
+ m_off += (ip[0] << 6) + (ip[1] >> 2);
+#else
+ m_off += (ip[0] >> 2) + (ip[1] << 6);
+#endif
+ ip += 2;
+ if (m_off == 0)
+ goto eof_found;
+ m_off += 0x4000;
+#if defined(LZO1Z)
+ last_m_off = m_off;
+#endif
+#else
+#if defined(LZO1Z)
+ m_pos -= (ip[0] << 6) + (ip[1] >> 2);
+#elif defined(LZO_UNALIGNED_OK_2) && defined(LZO_ABI_LITTLE_ENDIAN)
+ m_pos -= (* (const lzo_ushortp) ip) >> 2;
+#else
+ m_pos -= (ip[0] >> 2) + (ip[1] << 6);
+#endif
+ ip += 2;
+ if (m_pos == op)
+ goto eof_found;
+ m_pos -= 0x4000;
+#if defined(LZO1Z)
+ last_m_off = pd((const lzo_bytep)op, m_pos);
+#endif
+#endif
+ }
+ else
+ {
+#if defined(COPY_DICT)
+#if defined(LZO1Z)
+ m_off = 1 + (t << 6) + (*ip++ >> 2);
+ last_m_off = m_off;
+#else
+ m_off = 1 + (t >> 2) + (*ip++ << 2);
+#endif
+ NEED_OP(2);
+ t = 2; COPY_DICT(t,m_off)
+#else
+#if defined(LZO1Z)
+ t = 1 + (t << 6) + (*ip++ >> 2);
+ m_pos = op - t;
+ last_m_off = t;
+#else
+ m_pos = op - 1;
+ m_pos -= t >> 2;
+ m_pos -= *ip++ << 2;
+#endif
+ TEST_LB(m_pos); NEED_OP(2);
+ *op++ = *m_pos++; *op++ = *m_pos;
+#endif
+ goto match_done;
+ }
+
+#if defined(COPY_DICT)
+
+ NEED_OP(t+3-1);
+ t += 3-1; COPY_DICT(t,m_off)
+
+#else
+
+ TEST_LB(m_pos); assert(t > 0); NEED_OP(t+3-1);
+#if defined(LZO_UNALIGNED_OK_4) || defined(LZO_ALIGNED_OK_4)
+#if !defined(LZO_UNALIGNED_OK_4)
+ if (t >= 2 * 4 - (3 - 1) && PTR_ALIGNED2_4(op,m_pos))
+ {
+ assert((op - m_pos) >= 4);
+#else
+ if (t >= 2 * 4 - (3 - 1) && (op - m_pos) >= 4)
+ {
+#endif
+ COPY4(op,m_pos);
+ op += 4; m_pos += 4; t -= 4 - (3 - 1);
+ do {
+ COPY4(op,m_pos);
+ op += 4; m_pos += 4; t -= 4;
+ } while (t >= 4);
+ if (t > 0) do *op++ = *m_pos++; while (--t > 0);
+ }
+ else
+#endif
+ {
+copy_match:
+ *op++ = *m_pos++; *op++ = *m_pos++;
+ do *op++ = *m_pos++; while (--t > 0);
+ }
+
+#endif
+
+match_done:
+#if defined(LZO1Z)
+ t = ip[-1] & 3;
+#else
+ t = ip[-2] & 3;
+#endif
+ if (t == 0)
+ break;
+
+match_next:
+ assert(t > 0); assert(t < 4); NEED_OP(t); NEED_IP(t+1);
+#if 0
+ do *op++ = *ip++; while (--t > 0);
+#else
+ *op++ = *ip++;
+ if (t > 1) { *op++ = *ip++; if (t > 2) { *op++ = *ip++; } }
+#endif
+ t = *ip++;
+ } while (TEST_IP && TEST_OP);
+ }
+
+#if defined(HAVE_TEST_IP) || defined(HAVE_TEST_OP)
+ *out_len = pd(op, out);
+ return LZO_E_EOF_NOT_FOUND;
+#endif
+
+eof_found:
+ assert(t == 1);
+ *out_len = pd(op, out);
+ return (ip == ip_end ? LZO_E_OK :
+ (ip < ip_end ? LZO_E_INPUT_NOT_CONSUMED : LZO_E_INPUT_OVERRUN));
+
+#if defined(HAVE_NEED_IP)
+input_overrun:
+ *out_len = pd(op, out);
+ return LZO_E_INPUT_OVERRUN;
+#endif
+
+#if defined(HAVE_NEED_OP)
+output_overrun:
+ *out_len = pd(op, out);
+ return LZO_E_OUTPUT_OVERRUN;
+#endif
+
+#if defined(LZO_TEST_OVERRUN_LOOKBEHIND)
+lookbehind_overrun:
+ *out_len = pd(op, out);
+ return LZO_E_LOOKBEHIND_OVERRUN;
+#endif
+}
+
+#endif
+
+/***** End of minilzo.c *****/
+
diff --git a/minilzo.h b/minilzo.h
new file mode 100644
index 0000000..0aff50e
--- /dev/null
+++ b/minilzo.h
@@ -0,0 +1,106 @@
+/* minilzo.h -- mini subset of the LZO real-time data compression library
+
+ This file is part of the LZO real-time data compression library.
+
+ Copyright (C) 2008 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2007 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2006 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2005 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2004 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2003 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2002 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2001 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2000 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 1997 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 1996 Markus Franz Xaver Johannes Oberhumer
+ All Rights Reserved.
+
+ The LZO library 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.
+
+ The LZO library 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 the LZO library; see the file COPYING.
+ If not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ Markus F.X.J. Oberhumer
+
+ http://www.oberhumer.com/opensource/lzo/
+ */
+
+/*
+ * NOTE:
+ * the full LZO package can be found at
+ * http://www.oberhumer.com/opensource/lzo/
+ */
+
+
+#ifndef __MINILZO_H
+#define __MINILZO_H
+
+#define MINILZO_VERSION 0x2030
+
+#ifdef __LZOCONF_H
+# error "you cannot use both LZO and miniLZO"
+#endif
+
+#undef LZO_HAVE_CONFIG_H
+#include "lzoconf.h"
+
+#if !defined(LZO_VERSION) || (LZO_VERSION != MINILZO_VERSION)
+# error "version mismatch in header files"
+#endif
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/***********************************************************************
+//
+************************************************************************/
+
+/* Memory required for the wrkmem parameter.
+ * When the required size is 0, you can also pass a NULL pointer.
+ */
+
+#define LZO1X_MEM_COMPRESS LZO1X_1_MEM_COMPRESS
+#define LZO1X_1_MEM_COMPRESS ((lzo_uint32) (16384L * lzo_sizeof_dict_t))
+#define LZO1X_MEM_DECOMPRESS (0)
+
+
+/* compression */
+LZO_EXTERN(int)
+lzo1x_1_compress ( const lzo_bytep src, lzo_uint src_len,
+ lzo_bytep dst, lzo_uintp dst_len,
+ lzo_voidp wrkmem );
+
+/* decompression */
+LZO_EXTERN(int)
+lzo1x_decompress ( const lzo_bytep src, lzo_uint src_len,
+ lzo_bytep dst, lzo_uintp dst_len,
+ lzo_voidp wrkmem /* NOT USED */ );
+
+/* safe decompression with overrun testing */
+LZO_EXTERN(int)
+lzo1x_decompress_safe ( const lzo_bytep src, lzo_uint src_len,
+ lzo_bytep dst, lzo_uintp dst_len,
+ lzo_voidp wrkmem /* NOT USED */ );
+
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* already included */
+
diff --git a/n2n.c b/n2n.c
new file mode 100644
index 0000000..ac98ad6
--- /dev/null
+++ b/n2n.c
@@ -0,0 +1,455 @@
+/*
+ * (C) 2007-09 - Luca Deri
+ * Richard Andrews
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see
+ *
+ * Code contributions courtesy of:
+ * Massimo Torquati
+ * Matt Gilg
+ *
+ */
+
+#include "n2n.h"
+
+#include "minilzo.h"
+
+#include
+
+#if defined(DEBUG)
+# define PURGE_REGISTRATION_FREQUENCY 60
+# define REGISTRATION_TIMEOUT 120
+#else /* #if defined(DEBUG) */
+# define PURGE_REGISTRATION_FREQUENCY 60
+# define REGISTRATION_TIMEOUT (60*20)
+#endif /* #if defined(DEBUG) */
+
+
+const uint8_t broadcast_addr[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
+const uint8_t multicast_addr[6] = { 0x01, 0x00, 0x5E, 0x00, 0x00, 0x00 }; /* First 3 bytes are meaningful */
+const uint8_t ipv6_multicast_addr[6] = { 0x33, 0x33, 0x00, 0x00, 0x00, 0x00 }; /* First 2 bytes are meaningful */
+
+/* ************************************** */
+
+SOCKET open_socket(int local_port, int bind_any) {
+ SOCKET sock_fd;
+ struct sockaddr_in local_address;
+ int sockopt = 1;
+
+ if((sock_fd = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
+ traceEvent(TRACE_ERROR, "Unable to create socket [%s][%d]\n",
+ strerror(errno), sock_fd);
+ return(-1);
+ }
+
+#ifndef WIN32
+ /* fcntl(sock_fd, F_SETFL, O_NONBLOCK); */
+#endif
+
+ setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, (char *)&sockopt, sizeof(sockopt));
+
+ memset(&local_address, 0, sizeof(local_address));
+ local_address.sin_family = AF_INET;
+ local_address.sin_port = htons(local_port);
+ local_address.sin_addr.s_addr = htonl(bind_any?INADDR_ANY:INADDR_LOOPBACK);
+ if(bind(sock_fd, (struct sockaddr*) &local_address, sizeof(local_address)) == -1) {
+ traceEvent(TRACE_ERROR, "Bind error [%s]\n", strerror(errno));
+ return(-1);
+ }
+
+ return(sock_fd);
+}
+
+
+
+
+
+int traceLevel = 2 /* NORMAL */;
+int useSyslog = 0, syslog_opened = 0;
+
+#define N2N_TRACE_DATESIZE 32
+void traceEvent(int eventTraceLevel, char* file, int line, char * format, ...) {
+ va_list va_ap;
+
+ if(eventTraceLevel <= traceLevel) {
+ char buf[2048];
+ char out_buf[640];
+ char theDate[N2N_TRACE_DATESIZE];
+ char *extra_msg = "";
+ time_t theTime = time(NULL);
+#ifdef WIN32
+ int i;
+#endif
+
+ /* We have two paths - one if we're logging, one if we aren't
+ * Note that the no-log case is those systems which don't support it (WIN32),
+ * those without the headers !defined(USE_SYSLOG)
+ * those where it's parametrically off...
+ */
+
+ memset(buf, 0, sizeof(buf));
+ strftime(theDate, N2N_TRACE_DATESIZE, "%d/%b/%Y %H:%M:%S", localtime(&theTime));
+
+ va_start (va_ap, format);
+ vsnprintf(buf, sizeof(buf)-1, format, va_ap);
+ va_end(va_ap);
+
+ if(eventTraceLevel == 0 /* TRACE_ERROR */)
+ extra_msg = "ERROR: ";
+ else if(eventTraceLevel == 1 /* TRACE_WARNING */)
+ extra_msg = "WARNING: ";
+
+ while(buf[strlen(buf)-1] == '\n') buf[strlen(buf)-1] = '\0';
+
+#ifndef WIN32
+ if(useSyslog) {
+ if(!syslog_opened) {
+ openlog("n2n", LOG_PID, LOG_DAEMON);
+ syslog_opened = 1;
+ }
+
+ snprintf(out_buf, sizeof(out_buf), "%s%s", extra_msg, buf);
+ syslog(LOG_INFO, "%s", out_buf);
+ } else {
+ snprintf(out_buf, sizeof(out_buf), "%s [%11s:%4d] %s%s", theDate, file, line, extra_msg, buf);
+ printf("%s\n", out_buf);
+ fflush(stdout);
+ }
+#else
+ /* this is the WIN32 code */
+ for(i=strlen(file)-1; i>0; i--) if(file[i] == '\\') { i++; break; };
+ snprintf(out_buf, sizeof(out_buf), "%s [%11s:%4d] %s%s", theDate, &file[i], line, extra_msg, buf);
+ printf("%s\n", out_buf);
+ fflush(stdout);
+#endif
+ }
+
+}
+
+/* *********************************************** */
+
+/* addr should be in network order. Things are so much simpler that way. */
+char* intoa(uint32_t /* host order */ addr, char* buf, uint16_t buf_len) {
+ char *cp, *retStr;
+ uint8_t byteval;
+ int n;
+
+ cp = &buf[buf_len];
+ *--cp = '\0';
+
+ n = 4;
+ do {
+ byteval = addr & 0xff;
+ *--cp = byteval % 10 + '0';
+ byteval /= 10;
+ if (byteval > 0) {
+ *--cp = byteval % 10 + '0';
+ byteval /= 10;
+ if (byteval > 0)
+ *--cp = byteval + '0';
+ }
+ *--cp = '.';
+ addr >>= 8;
+ } while (--n > 0);
+
+ /* Convert the string to lowercase */
+ retStr = (char*)(cp+1);
+
+ return(retStr);
+}
+
+/* *********************************************** */
+
+char * macaddr_str( macstr_t buf,
+ const n2n_mac_t mac )
+{
+ snprintf(buf, N2N_MACSTR_SIZE, "%02X:%02X:%02X:%02X:%02X:%02X",
+ mac[0] & 0xFF, mac[1] & 0xFF, mac[2] & 0xFF,
+ mac[3] & 0xFF, mac[4] & 0xFF, mac[5] & 0xFF);
+ return(buf);
+}
+
+/* *********************************************** */
+
+uint8_t is_multi_broadcast(const uint8_t * dest_mac) {
+
+ int is_broadcast = ( memcmp(broadcast_addr, dest_mac, 6) == 0 );
+ int is_multicast = ( memcmp(multicast_addr, dest_mac, 3) == 0 );
+ int is_ipv6_multicast = ( memcmp(ipv6_multicast_addr, dest_mac, 2) == 0 );
+
+ return is_broadcast || is_multicast || is_ipv6_multicast;
+
+}
+
+/* http://www.faqs.org/rfcs/rfc908.html */
+
+
+/* *********************************************** */
+
+char* msg_type2str(uint16_t msg_type) {
+ switch(msg_type) {
+ case MSG_TYPE_REGISTER: return("MSG_TYPE_REGISTER");
+ case MSG_TYPE_DEREGISTER: return("MSG_TYPE_DEREGISTER");
+ case MSG_TYPE_PACKET: return("MSG_TYPE_PACKET");
+ case MSG_TYPE_REGISTER_ACK: return("MSG_TYPE_REGISTER_ACK");
+ case MSG_TYPE_REGISTER_SUPER: return("MSG_TYPE_REGISTER_SUPER");
+ case MSG_TYPE_REGISTER_SUPER_ACK: return("MSG_TYPE_REGISTER_SUPER_ACK");
+ case MSG_TYPE_REGISTER_SUPER_NAK: return("MSG_TYPE_REGISTER_SUPER_NAK");
+ case MSG_TYPE_FEDERATION: return("MSG_TYPE_FEDERATION");
+ default: return("???");
+ }
+
+ return("???");
+}
+
+/* *********************************************** */
+
+void hexdump(const uint8_t * buf, size_t len)
+{
+ size_t i;
+
+ if ( 0 == len ) { return; }
+
+ for(i=0; i 0) && ((i % 16) == 0)) { printf("\n"); }
+ printf("%02X ", buf[i] & 0xFF);
+ }
+
+ printf("\n");
+}
+
+/* *********************************************** */
+
+void print_n2n_version() {
+ printf("Welcome to n2n v.%s for %s\n"
+ "Built on %s\n"
+ "Copyright 2007-09 - http://www.ntop.org\n\n",
+ n2n_sw_version, n2n_sw_osName, n2n_sw_buildDate);
+}
+
+
+
+
+/** Find the peer entry in list with mac_addr equal to mac.
+ *
+ * Does not modify the list.
+ *
+ * @return NULL if not found; otherwise pointer to peer entry.
+ */
+struct peer_info * find_peer_by_mac( struct peer_info * list, const n2n_mac_t mac )
+{
+ while(list != NULL)
+ {
+ if( 0 == memcmp(mac, list->mac_addr, 6) )
+ {
+ return list;
+ }
+ list = list->next;
+ }
+
+ return NULL;
+}
+
+
+/** Return the number of elements in the list.
+ *
+ */
+size_t peer_list_size( const struct peer_info * list )
+{
+ size_t retval=0;
+
+ while ( list )
+ {
+ ++retval;
+ list = list->next;
+ }
+
+ return retval;
+}
+
+/** Add new to the head of list. If list is NULL; create it.
+ *
+ * The item new is added to the head of the list. New is modified during
+ * insertion. list takes ownership of new.
+ */
+void peer_list_add( struct peer_info * * list,
+ struct peer_info * new )
+{
+ new->next = *list;
+ new->last_seen = time(NULL);
+ *list = new;
+}
+
+
+size_t purge_expired_registrations( struct peer_info ** peer_list ) {
+ static time_t last_purge = 0;
+ time_t now = time(NULL);
+ size_t num_reg = 0;
+
+ if((now - last_purge) < PURGE_REGISTRATION_FREQUENCY) return 0;
+
+ traceEvent(TRACE_INFO, "Purging old registrations");
+
+ num_reg = purge_peer_list( peer_list, now-REGISTRATION_TIMEOUT );
+
+ last_purge = now;
+ traceEvent(TRACE_INFO, "Remove %ld registrations", num_reg);
+
+ return num_reg;
+}
+
+/** Purge old items from the peer_list and return the number of items that were removed. */
+size_t purge_peer_list( struct peer_info ** peer_list,
+ time_t purge_before )
+{
+ struct peer_info *scan;
+ struct peer_info *prev;
+ size_t retval=0;
+
+ scan = *peer_list;
+ prev = NULL;
+ while(scan != NULL)
+ {
+ if(scan->last_seen < purge_before)
+ {
+ struct peer_info *next = scan->next;
+
+ if(prev == NULL)
+ {
+ *peer_list = next;
+ }
+ else
+ {
+ prev->next = next;
+ }
+
+ ++retval;
+ free(scan);
+ scan = next;
+ }
+ else
+ {
+ prev = scan;
+ scan = scan->next;
+ }
+ }
+
+ return retval;
+}
+
+/** Purge all items from the peer_list and return the number of items that were removed. */
+size_t clear_peer_list( struct peer_info ** peer_list )
+{
+ struct peer_info *scan;
+ struct peer_info *prev;
+ size_t retval=0;
+
+ scan = *peer_list;
+ prev = NULL;
+ while(scan != NULL)
+ {
+ struct peer_info *next = scan->next;
+
+ if(prev == NULL)
+ {
+ *peer_list = next;
+ }
+ else
+ {
+ prev->next = next;
+ }
+
+ ++retval;
+ free(scan);
+ scan = next;
+ }
+
+ return retval;
+}
+
+static uint8_t hex2byte( const char * s )
+{
+ char tmp[3];
+ tmp[0]=s[0];
+ tmp[1]=s[1];
+ tmp[2]=0; /* NULL term */
+
+ return((uint8_t)strtol( s, NULL, 16 ));
+}
+
+extern int str2mac( uint8_t * outmac /* 6 bytes */, const char * s )
+{
+ size_t i;
+
+ /* break it down as one case for the first "HH", the 5 x through loop for
+ * each ":HH" where HH is a two hex nibbles in ASCII. */
+
+ *outmac=hex2byte(s);
+ ++outmac;
+ s+=2; /* don't skip colon yet - helps generalise loop. */
+
+ for (i=1; i<6; ++i )
+ {
+ s+=1;
+ *outmac=hex2byte(s);
+ ++outmac;
+ s+=2;
+ }
+
+ return 0; /* ok */
+}
+
+extern char * sock_to_cstr( n2n_sock_str_t out,
+ const n2n_sock_t * sock )
+{
+ int r;
+
+ if ( NULL == out ) { return NULL; }
+ memset(out, 0, N2N_SOCKBUF_SIZE);
+
+ if ( AF_INET6 == sock->family )
+ {
+ /* INET6 not written yet */
+ r = snprintf( out, N2N_SOCKBUF_SIZE, "XXXX:%hu", sock->port );
+ return out;
+ }
+ else
+ {
+ const uint8_t * a = sock->addr.v4;
+ r = snprintf( out, N2N_SOCKBUF_SIZE, "%hu.%hu.%hu.%hu:%hu",
+ (a[0] & 0xff), (a[1] & 0xff), (a[2] & 0xff), (a[3] & 0xff), sock->port );
+ return out;
+ }
+}
+
+/* @return zero if the two sockets are equivalent. */
+int sock_equal( const n2n_sock_t * a,
+ const n2n_sock_t * b )
+{
+ if ( a->port != b->port ) { return 1; }
+ if ( a->family != b->family ) { return 1; }
+ switch (a->family) /* they are the same */
+ {
+ case AF_INET:
+ if ( 0 != memcmp( a->addr.v4, b->addr.v4, IPV4_SIZE ) ) { return 1;};
+ break;
+ default:
+ if ( 0 != memcmp( a->addr.v6, b->addr.v6, IPV6_SIZE ) ) { return 1;};
+ break;
+ }
+
+ return 0;
+}
+
diff --git a/n2n.h b/n2n.h
new file mode 100644
index 0000000..4801bf7
--- /dev/null
+++ b/n2n.h
@@ -0,0 +1,254 @@
+/*
+ * (C) 2007-09 - Luca Deri
+ * Richard Andrews
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see
+ *
+ * Code contributions courtesy of:
+ * Babak Farrokhi [FreeBSD port]
+ * Lukasz Taczuk
+ *
+ */
+
+#ifndef _N2N_H_
+#define _N2N_H_
+
+/*
+ tunctl -t tun0
+ tunctl -t tun1
+ ifconfig tun0 1.2.3.4 up
+ ifconfig tun1 1.2.3.5 up
+ ./edge -d tun0 -l 2000 -r 127.0.0.1:3000 -c hello
+ ./edge -d tun1 -l 3000 -r 127.0.0.1:2000 -c hello
+
+
+ tunctl -u UID -t tunX
+*/
+
+#if defined(__APPLE__) && defined(__MACH__)
+#define _DARWIN_
+#endif
+
+
+/* Some capability defaults which can be reset for particular platforms. */
+#define N2N_HAVE_DAEMON 1
+#define N2N_HAVE_SETUID 1
+/* #define N2N_CAN_NAME_IFACE */
+
+/* Moved here to define _CRT_SECURE_NO_WARNINGS before all the including takes place */
+#ifdef WIN32
+#include "win32/n2n_win32.h"
+#undef N2N_HAVE_DAEMON
+#undef N2N_HAVE_SETUID
+#endif
+
+#include
+#include
+#include
+
+#ifndef WIN32
+#include
+#endif
+
+#ifndef _MSC_VER
+#include
+#endif /* #ifndef _MSC_VER */
+
+#include
+#include
+#include
+
+#ifndef WIN32
+#include
+#include
+#include
+#include
+#include
+
+#ifdef __linux__
+#include
+#include
+#define N2N_CAN_NAME_IFACE 1
+#endif /* #ifdef __linux__ */
+
+#ifdef __FreeBSD__
+#include
+#endif /* #ifdef __FreeBSD__ */
+
+#include
+#include
+
+#define ETH_ADDR_LEN 6
+struct ether_hdr
+{
+ uint8_t dhost[ETH_ADDR_LEN];
+ uint8_t shost[ETH_ADDR_LEN];
+ uint16_t type; /* higher layer protocol encapsulated */
+} __attribute__ ((__packed__));
+
+typedef struct ether_hdr ether_hdr_t;
+
+#ifdef __sun__
+#include /* MIN() and MAX() declared here */
+#undef N2N_HAVE_DAEMON
+#endif /* #ifdef __sun__ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#define closesocket(a) close(a)
+#endif /* #ifndef WIN32 */
+
+#include
+
+#include
+
+#ifdef WIN32
+#include "win32/wintap.h"
+#endif /* #ifdef WIN32 */
+
+#include "n2n_wire.h"
+
+/* N2N_IFNAMSIZ is needed on win32 even if dev_name is not used after declaration */
+#define N2N_IFNAMSIZ 16 /* 15 chars * NULL */
+#ifndef WIN32
+typedef struct tuntap_dev {
+ int fd;
+ uint8_t mac_addr[6];
+ uint32_t ip_addr, device_mask;
+ uint16_t mtu;
+ char dev_name[N2N_IFNAMSIZ];
+} tuntap_dev;
+
+#define SOCKET int
+#endif /* #ifndef WIN32 */
+
+#define QUICKLZ 1
+
+/* N2N packet header indicators. */
+#define MSG_TYPE_REGISTER 1
+#define MSG_TYPE_DEREGISTER 2
+#define MSG_TYPE_PACKET 3
+#define MSG_TYPE_REGISTER_ACK 4
+#define MSG_TYPE_REGISTER_SUPER 5
+#define MSG_TYPE_REGISTER_SUPER_ACK 6
+#define MSG_TYPE_REGISTER_SUPER_NAK 7
+#define MSG_TYPE_FEDERATION 8
+
+/* Set N2N_COMPRESSION_ENABLED to 0 to disable lzo1x compression of ethernet
+ * frames. Doing this will break compatibility with the standard n2n packet
+ * format so do it only for experimentation. All edges must be built with the
+ * same value if they are to understand each other. */
+#define N2N_COMPRESSION_ENABLED 1
+
+#define DEFAULT_MTU 1400
+
+/** Common type used to hold stringified IP addresses. */
+typedef char ipstr_t[32];
+
+/** Common type used to hold stringified MAC addresses. */
+#define N2N_MACSTR_SIZE 32
+typedef char macstr_t[N2N_MACSTR_SIZE];
+
+struct peer_info {
+ struct peer_info * next;
+ n2n_community_t community_name;
+ n2n_mac_t mac_addr;
+ n2n_sock_t sock;
+ time_t last_seen;
+};
+
+struct n2n_edge; /* defined in edge.c */
+typedef struct n2n_edge n2n_edge_t;
+
+
+/* ************************************** */
+
+#define TRACE_ERROR 0, __FILE__, __LINE__
+#define TRACE_WARNING 1, __FILE__, __LINE__
+#define TRACE_NORMAL 2, __FILE__, __LINE__
+#define TRACE_INFO 3, __FILE__, __LINE__
+#define TRACE_DEBUG 4, __FILE__, __LINE__
+
+/* ************************************** */
+
+#define SUPERNODE_IP "127.0.0.1"
+#define SUPERNODE_PORT 1234
+
+/* ************************************** */
+
+#ifndef max
+#define max(a, b) ((a < b) ? b : a)
+#endif
+
+#ifndef min
+#define min(a, b) ((a > b) ? b : a)
+#endif
+
+/* ************************************** */
+
+/* Variables */
+/* extern TWOFISH *tf; */
+extern int traceLevel;
+extern int useSyslog;
+extern const uint8_t broadcast_addr[6];
+extern const uint8_t multicast_addr[6];
+
+/* Functions */
+extern void traceEvent(int eventTraceLevel, char* file, int line, char * format, ...);
+extern int tuntap_open(tuntap_dev *device, char *dev, const char *address_mode, char *device_ip,
+ char *device_mask, const char * device_mac, int mtu);
+extern int tuntap_read(struct tuntap_dev *tuntap, unsigned char *buf, int len);
+extern int tuntap_write(struct tuntap_dev *tuntap, unsigned char *buf, int len);
+extern void tuntap_close(struct tuntap_dev *tuntap);
+extern void tuntap_get_address(struct tuntap_dev *tuntap);
+
+extern SOCKET open_socket(int local_port, int bind_any);
+
+extern char* intoa(uint32_t addr, char* buf, uint16_t buf_len);
+extern char* macaddr_str(macstr_t buf, const n2n_mac_t mac);
+extern int str2mac( uint8_t * outmac /* 6 bytes */, const char * s );
+extern char * sock_to_cstr( n2n_sock_str_t out,
+ const n2n_sock_t * sock );
+
+extern int sock_equal( const n2n_sock_t * a,
+ const n2n_sock_t * b );
+
+extern uint8_t is_multi_broadcast(const uint8_t * dest_mac);
+extern char* msg_type2str(uint16_t msg_type);
+extern void hexdump(const uint8_t * buf, size_t len);
+
+void print_n2n_version();
+
+
+/* Operations on peer_info lists. */
+struct peer_info * find_peer_by_mac( struct peer_info * list,
+ const n2n_mac_t mac );
+void peer_list_add( struct peer_info * * list,
+ struct peer_info * new );
+size_t peer_list_size( const struct peer_info * list );
+size_t purge_peer_list( struct peer_info ** peer_list,
+ time_t purge_before );
+size_t clear_peer_list( struct peer_info ** peer_list );
+size_t purge_expired_registrations( struct peer_info ** peer_list );
+
+/* version.c */
+extern char *n2n_sw_version, *n2n_sw_osName, *n2n_sw_buildDate;
+
+#endif /* _N2N_H_ */
diff --git a/n2n.spec b/n2n.spec
new file mode 100644
index 0000000..f5ee7d8
--- /dev/null
+++ b/n2n.spec
@@ -0,0 +1,52 @@
+Summary: N2N peer-to-peer virtual private network system.
+Name: n2n
+Version: 2.1.0
+Release: 1
+License: GPLv3
+Vendor: ntop.org
+Group: None
+URL: http://www.ntop.org/n2n
+Source0: %{name}-%{version}.tar.gz
+BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root
+
+%description
+N2N is a peer-to-peer virtual private network system. N2N uses the universal
+TUNTAP interface to create TAP network interfaces to an encrypted virtual
+LAN. Members of a community share encryption keys which allow exchange of
+data. The supernode is used for peer discovery and initial packet relay before
+direct peer-to-peer exchange is established. Once direct packet exchange is
+established, the supernode is not required.
+
+N2N-2 introduces additional security features and multiple supernodes.
+
+%prep
+
+%setup -q
+
+echo -e "\n *** Building ${RPM_PACKAGE_NAME}-${RPM_PACKAGE_VERSION}-${RPM_PACKAGE_RELEASE} ***\n"
+
+%build
+make
+
+%install
+make PREFIX=${RPM_BUILD_ROOT}/usr install
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+
+%files
+%defattr(-,root,root,-)
+ /usr/sbin/supernode
+ /usr/sbin/edge
+%doc /usr/share/man/man1/supernode.1.gz
+%doc /usr/share/man/man8/edge.8.gz
+%doc /usr/share/man/man7/n2n_v2.7.gz
+
+
+%changelog
+* Fri Oct 30 2009 Richard Andrews -
+- First beta for n2n-2
+* Sat May 3 2008 Richard Andrews -
+- Initial build.
+
diff --git a/n2n_keyfile.c b/n2n_keyfile.c
new file mode 100644
index 0000000..56de3a1
--- /dev/null
+++ b/n2n_keyfile.c
@@ -0,0 +1,203 @@
+/* (c) 2009 Richard Andrews */
+/* Contributions from:
+ * - Jozef Kralik
+ */
+
+#include "n2n.h"
+#include "n2n_keyfile.h"
+#include
+#include
+#include
+#include
+
+
+#ifdef WIN32
+char *strsep( char **ppsz_string, const char *psz_delimiters )
+{
+ char *p;
+ char *psz_string = *ppsz_string;
+ if( !psz_string )
+ return NULL;
+
+ p = strpbrk( psz_string, psz_delimiters );
+ if( !p )
+ {
+ *ppsz_string = NULL;
+ return psz_string;
+ }
+ *p++ = '\0';
+
+ *ppsz_string = p;
+ return psz_string;
+}
+#endif
+
+
+/* Parse hex nibbles in ascii until a non-nibble character is found. Nibble
+ * characters are 0-9, a-f and A-F.
+ *
+ * Return number of bytes parsed into keyBuf or a negative error code.
+ */
+ssize_t n2n_parse_hex( uint8_t * keyBuf,
+ size_t keyLen,
+ const char * textKey,
+ size_t textLen)
+{
+ ssize_t retval=0;
+ uint8_t * pout=keyBuf;
+ size_t octet=0;
+ const char * textEnd;
+ const char * pbeg;
+
+ textEnd = textKey+textLen;
+ pbeg=textKey;
+
+ while ( ( pbeg + 1 < textEnd ) && ( retval < (ssize_t)keyLen ) )
+ {
+ if ( 1 != sscanf( pbeg, "%02x", (unsigned int*)&octet ) )
+ {
+ retval=-1;
+ break;
+ }
+
+ *pout = (octet & 0xff);
+ ++pout;
+ ++retval;
+ pbeg += 2;
+ }
+
+ return retval;
+}
+
+
+static int parseKeyLine( n2n_cipherspec_t * spec,
+ const char * linein )
+{
+ /* parameters are separated by whitespace */
+ char line[N2N_KEYFILE_LINESIZE];
+ char * lp=line;
+ const char * token;
+ strncpy( line, linein, N2N_KEYFILE_LINESIZE );
+
+ memset( spec, 0, sizeof( n2n_cipherspec_t ) );
+
+ /* decode valid_from time */
+ token = strsep( &lp, DELIMITERS );
+ if ( !token ) { goto error; }
+ spec->valid_from = atol(token);
+
+ /* decode valid_until time */
+ token = strsep( &lp, DELIMITERS );
+ if ( !token ) { goto error; }
+ spec->valid_until = atol(token);
+
+ /* decode the transform number */
+ token = strsep( &lp, DELIMITERS );
+ if ( !token ) { goto error; }
+ spec->t = atoi(token);
+
+ /* The reset if opaque key data */
+ token = strsep( &lp, DELIMITERS );
+ if ( !token ) { goto error; }
+ strncpy( (char *)spec->opaque, token, N2N_MAX_KEYSIZE );
+ spec->opaque_size=strlen( (char *)spec->opaque);
+
+ return 0;
+
+error:
+ return -1;
+}
+
+
+#define SEP "/"
+
+
+int validCipherSpec( const n2n_cipherspec_t * k,
+ time_t now )
+{
+ if ( k->valid_until < k->valid_from ) { goto bad; }
+ if ( k->valid_from > now ) { goto bad; }
+ if ( k->valid_until < now ) { goto bad; }
+
+ return 0;
+
+bad:
+ return -1;
+}
+
+/* Read key control file and return the number of specs stored or a negative
+ * error code.
+ *
+ * As the specs are read in the from and until time values are compared to
+ * present time. Only those keys which are valid are stored.
+ */
+int n2n_read_keyfile( n2n_cipherspec_t * specs, /* fill out this array of cipherspecs */
+ size_t numspecs, /* number of slots in the array. */
+ const char * ctrlfile_path ) /* path to control file */
+{
+ /* Each line contains one cipherspec. */
+
+ int retval=0;
+ FILE * fp=NULL;
+ size_t idx=0;
+ time_t now = time(NULL);
+
+ traceEvent( TRACE_DEBUG, "Reading '%s'\n", ctrlfile_path );
+
+ fp = fopen( ctrlfile_path, "r" );
+ if ( fp )
+ {
+ /* Read the file a line a time with fgets. */
+ char line[N2N_KEYFILE_LINESIZE];
+ size_t lineNum=0;
+
+ while ( idx < numspecs )
+ {
+ n2n_cipherspec_t * k = &(specs[idx]);
+ fgets( line, N2N_KEYFILE_LINESIZE, fp );
+ ++lineNum;
+
+ if ( strlen(line) > 1 )
+ {
+ if ( 0 == parseKeyLine( k, line ) )
+ {
+ if ( k->valid_until > now )
+ {
+ traceEvent( TRACE_INFO, " --> [%u] from %lu, until %lu, transform=%hu, data=%s\n",
+ idx, k->valid_from, k->valid_until, k->t, k->opaque );
+
+ ++retval;
+ ++idx;
+ }
+ else
+ {
+ traceEvent( TRACE_INFO, " --X [%u] from %lu, until %lu, transform=%hu, data=%s\n",
+ idx, k->valid_from, k->valid_until, k->t, k->opaque );
+
+ }
+ }
+ else
+ {
+ traceEvent( TRACE_WARNING, "Failed to decode line %u\n", lineNum );
+ }
+ }
+
+ if ( feof(fp) )
+ {
+ break;
+ }
+
+ line[0]=0; /* this line has been consumed */
+ }
+
+ fclose( fp);
+ fp=NULL;
+ }
+ else
+ {
+ traceEvent( TRACE_ERROR, "Failed to open '%s'\n", ctrlfile_path );
+ retval = -1;
+ }
+
+ return retval;
+}
diff --git a/n2n_keyfile.h b/n2n_keyfile.h
new file mode 100644
index 0000000..6068df1
--- /dev/null
+++ b/n2n_keyfile.h
@@ -0,0 +1,101 @@
+/* (c) 2009 Richard Andrews */
+
+/** Key files
+ *
+ * Edge implements a very simple interface for getting instructions about
+ * rolling keys.
+ *
+ * Key definitions are written as individual files in /.key. The
+ * format of each key is a single line of hex nibbles as follows:
+ *
+ * 0102030405060708090a0b0c0d0e0f
+ *
+ * Any external key exchange mechanism can receive the key data write it into
+ * the keyfiles.
+ *
+ * To control which keys are active at what times the key control file is
+ * used. This is a single file which is periodically reread. It contains key
+ * definitions in chronological order with one line per key definition as
+ * follows:
+ *
+ *
+ *
+ * edge reads the key control file periodically to get updates in policy. edge
+ * holds a number of keys in memory. Data can be decoded if it was encoded by
+ * any of the keys still in memory. By having at least 2 keys in memory it
+ * allows for clock skew and transmission delay when encoder and decoder roll
+ * keys at slightly different times. The amount of overlap in the valid time
+ * ranges provides the tolerance to timing skews in the system.
+ *
+ * The keys have the same level of secrecy as any other user file. Existing
+ * UNIX permission systems can be used to provide access controls.
+ *
+ */
+
+/** How Edge Uses The Key Schedule
+ *
+ * Edge provides state space for a number of transform algorithms. Each
+ * transform uses its state space to store the SA information for its keys as
+ * found in the key file. When a packet is received the transform ID is in
+ * plain text. The packets is then sent to that transform for decoding. Each
+ * transform can store its SA numbers differently (or not at all). The
+ * transform code then finds the SA number, then finds the cipher (with key) in
+ * the state space and uses this to decode the packet.
+ *
+ * To support this, as edge reads each key line, it passes it to the
+ * appropriate transform to parse the line and store the SA information in its
+ * state space.
+ *
+ * When encoding a packet, edge has several transforms and potentially valid
+ * SAs to choose from. To keep track of which one to use for encoding edge does
+ * its own book-keeping as each key line is passed to the transform code: it
+ * stores a lookup of valid_from -> transform. When encoding a packet it then
+ * just calls the transform with the best valid_from in the table. The
+ * transform's own state space has all the SAs for its keys and the best of
+ * those is chosen.
+ */
+
+#if !defined( N2N_KEYFILE_H_ )
+#define N2N_KEYFILE_H_
+
+
+#include "n2n_wire.h"
+#include
+
+#define N2N_MAX_KEYSIZE 256 /* bytes */
+#define N2N_MAX_NUM_CIPHERSPECS 8
+#define N2N_KEYPATH_SIZE 256
+#define N2N_KEYFILE_LINESIZE 256
+
+/** This structure stores an encryption cipher spec. */
+struct n2n_cipherspec
+{
+ n2n_transform_t t; /* N2N_TRANSFORM_ID_xxx for this spec. */
+ time_t valid_from; /* Start using the key at this time. */
+ time_t valid_until; /* Key is valid if time < valid_until. */
+ uint16_t opaque_size; /* Size in bytes of key. */
+ uint8_t opaque[N2N_MAX_KEYSIZE];/* Key matter. */
+};
+
+typedef struct n2n_cipherspec n2n_cipherspec_t;
+
+
+static const char * const DELIMITERS=" \t\n\r";
+
+
+/** @return number of cipherspec items filled. */
+int n2n_read_keyfile( n2n_cipherspec_t * specs, /* fill out this array of cipherspecs */
+ size_t numspecs, /* number of slots in the array. */
+ const char * ctrlfile_path ); /* path to control file */
+
+int validCipherSpec( const n2n_cipherspec_t * k,
+ time_t now );
+
+ssize_t n2n_parse_hex( uint8_t * keyBuf,
+ size_t keyMax,
+ const char * textKey,
+ size_t textLen );
+
+/*----------------------------------------------------------------------------*/
+
+#endif /* #if !defined( N2N_KEYFILE_H_ ) */
diff --git a/n2n_transforms.h b/n2n_transforms.h
new file mode 100644
index 0000000..effbc50
--- /dev/null
+++ b/n2n_transforms.h
@@ -0,0 +1,78 @@
+/* (c) 2009 Richard Andrews */
+
+#if !defined(N2N_TRANSFORMS_H_)
+#define N2N_TRANSFORMS_H_
+
+#include "n2n_keyfile.h"
+#include "n2n_wire.h"
+
+
+#define N2N_TRANSFORM_ID_INVAL 0 /* marks uninitialised data */
+#define N2N_TRANSFORM_ID_NULL 1
+#define N2N_TRANSFORM_ID_TWOFISH 2
+#define N2N_TRANSFORM_ID_AESCBC 3
+#define N2N_TRANSFORM_ID_LZO 4
+#define N2N_TRANSFORM_ID_TWOFISH_LZO 5
+#define N2N_TRANSFORM_ID_AESCBC_LZO 6
+#define N2N_TRANSFORM_ID_USER_START 64
+#define N2N_TRANSFORM_ID_MAX 65535
+
+
+struct n2n_trans_op;
+typedef struct n2n_trans_op n2n_trans_op_t;
+
+struct n2n_tostat
+{
+ uint8_t can_tx; /* Does this transop have a valid SA for encoding. */
+ n2n_cipherspec_t tx_spec; /* If can_tx, the spec used to encode. */
+};
+
+typedef struct n2n_tostat n2n_tostat_t;
+
+
+typedef int (*n2n_transdeinit_f)( n2n_trans_op_t * arg );
+typedef int (*n2n_transaddspec_f)( n2n_trans_op_t * arg,
+ const n2n_cipherspec_t * cspec );
+typedef n2n_tostat_t (*n2n_transtick_f)( n2n_trans_op_t * arg,
+ time_t now );
+
+typedef int (*n2n_transform_f)( n2n_trans_op_t * arg,
+ uint8_t * outbuf,
+ size_t out_len,
+ const uint8_t * inbuf,
+ size_t in_len );
+
+/** Holds the info associated with a data transform plugin.
+ *
+ * When a packet arrives the transform ID is extracted. This defines the code
+ * to use to decode the packet content. The transform code then decodes the
+ * packet and consults its internal key lookup.
+ */
+struct n2n_trans_op
+{
+ void * priv; /* opaque data. Key schedule goes here. */
+
+ n2n_transform_t transform_id; /* link header enum to a transform */
+ size_t tx_cnt;
+ size_t rx_cnt;
+
+ n2n_transdeinit_f deinit; /* destructor function */
+ n2n_transaddspec_f addspec; /* parse opaque data from a key schedule file. */
+ n2n_transtick_f tick; /* periodic maintenance */
+ n2n_transform_f fwd; /* encode a payload */
+ n2n_transform_f rev; /* decode a payload */
+};
+
+/* Setup a single twofish SA for single-key operation. */
+int transop_twofish_setup( n2n_trans_op_t * ttt,
+ n2n_sa_t sa_num,
+ uint8_t * encrypt_pwd,
+ uint32_t encrypt_pwd_len );
+
+/* Initialise an empty transop ready to receive cipherspec elements. */
+int transop_twofish_init( n2n_trans_op_t * ttt );
+int transop_aes_init( n2n_trans_op_t * ttt );
+void transop_null_init( n2n_trans_op_t * ttt );
+
+#endif /* #if !defined(N2N_TRANSFORMS_H_) */
+
diff --git a/n2n_v2.7 b/n2n_v2.7
new file mode 100644
index 0000000..092f2d3
--- /dev/null
+++ b/n2n_v2.7
@@ -0,0 +1,156 @@
+.TH "n2n_v2" 7 "Sep 21, 2009" "revision 3909" "Background"
+.SH NAME
+N2n Version 2 \- version 2 of the n2n decentralised peer-to-peer network overlay
+VPN.
+.SH DESCRIPTION
+N2n is a peer-to-peer network overlay or VPN system that provides layer 2 over
+layer 3 encapsulation with data transform capabilities such as encryption and
+compression. This guide discusses the differences of version 2 or n2n from
+version 1.
+.SH PROTOCOLS
+N2n-2 uses a different set of messages to communicate with edges and
+supernodes. The n2n-2 messages are not compatible with n2n-1. There is no
+backward compatibility for n2n-1.
+.SH ENCRYPTION
+N2n-2 offers a new way of handling encryption compared to n2n-1. N2n-1 provided
+facility for a single community password with no expiration. In n2n-2 this
+method is preserved but a new mechanism has been added using a key schedule
+file.
+.TP
+Key Schedule
+A key schedule file lists a number of keys with the period for which each is
+valid along with the encryption type identifier and the actual key value. This
+allows the user to define up to 32 keys in advance with a pre-set time at which
+they keys will change. The key schedule file can be reloaded while the edge is
+running to allow new keys to be loaded and unused keys expunged.
+.TP
+Timing Requirements When a key rolls over to the next in the schedule, the new
+key is used for all transmitted packets; however any packets received using an
+older key can still be decoded as the keys from the key schedule are still
+known. As a result edges do not need to have accurate time synchronisation. The
+accuracy of required synchronisation depends to a large degree on the key
+schedule. Rapid key roll-overs requires more accurate time synchronisation.
+.P
+N2n-2 provides the following encryption ciphers; more can be added as required:
+.TP
+.B (1) NULL
+Data is encapsulated unchanged. Useful for testing and high-performance, low
+sensitivity applications.
+.TP
+.B (2) TF
+Twofish AES candidate.
+.P
+The following additional ciphers are specified but not yet implemented:
+.TP
+.B (3) AES-CBC
+AES in CBC mode with 256-bit key.
+.TP
+.B (4) LZO
+LZO compression of data (no encryption).
+.TP
+.B (5) TF-LZO
+TF cipher with LZO compression of data prior to encryption.
+.TP
+.B (6) AES-CBC-LZO
+AES-CBC ciper with LZO compression of data prior to encryption.
+
+.SH EXTENSIBILITY
+N2n-2 decouples the data transform system from the core of the edge
+operation. This allows for easier addition of new data transform
+operations. N2n-2 reserves 64 standard transform identifiers (such as TwoFish
+encryption) but allocates transform identifiers 64 - 65536 for user-defined
+transforms. This allows anyone to add to n2n new private transforms without
+breaking compatibility with the standard offering.
+
+.SH MULTIPLE SUPERNODES
+N2n-2 introduces the capability of multiple supernodes to be used by an
+edge. N2n-2 offers supernode in several flavours:
+.TP
+Stand-alone supernode
+
+This is the same concept as from n2n-1. Supernode is a small efficient C program
+which operates in isolation.
+.TP
+Federated supernodes
+
+This is a cluster of supernodes which share information. Edges registered to any
+of the cooperating supernodes can relay packets through the supernode federation
+and switch supernodes if required. Supernodes can send PACKET or REGISTER
+messages to other supernodes to try and find the destination edge.
+
+.P
+The n2n-2 edge implementation allows multiple supernodes to be specified on the
+command line. Edges monitor the current supernode for responses to
+REGISTER_SUPER messages. If 3 responses are missed then the edge starts looking
+for a new supernode. It cycles through the list of supernodes specified until it
+finds a working one.
+
+.SH EFFICIENCY
+The n2n-2 message formats have been made more efficient. The amount of data
+overhead has been reduced by ensuring the messages contain only the data fields
+required. Some optional fields do not consume data if they are not present.
+
+.SH DAEMON OPERATION
+The supernode and edge use daemon mode of operation by default. This sense is
+inverted from n2n-1 where they ran in the foreground by default. They can be
+made to run in the foreground so tools such a DJB's daemontools can work with
+them. See the
+.B -f
+option
+
+.SH MANAGEMENT CONSOLE
+Edge and supernode in n2n-2 provide a UDP-based management console. Both listen
+on the localhost address 127.0.0.1. Commands can be sent to the programs by
+sending to the UDP socket. Responses are returned to the socket from which
+commands were issued. This only works from the computer on which the programs
+are running. Statistics can be retrieved and commands issued. The netcat utility
+is all that is required; but more sophisticated tools could be built on the
+interface.
+
+.SH SUPERNODE AUTHENTICATION
+.B (To be implemented)
+Space has been reserved in the supernode registration messages for an
+authentication mechanism.
+
+.SH MESSAGE SUMMARY
+The following message types work within n2n-2.
+.TP
+REGISTER_SUPER
+Sent from an edge to its local supernode to register its MAC with the community.
+.TP
+REGISTER_SUPER_ACK
+Sent from a supernode to an edge to confirm registration. This also carries the
+definition of the edge socket as seen at the supernode so NAT can be detected
+and described.
+.TP
+REGISTER_SUPER_NAK
+Supernode refusing to register an edge.
+.TP
+PACKET
+Encapsulated ethernet packets sent between edges. Supernodes forward or
+broadcast these and edges send them direct in peer-to-peer mode.
+.TP
+REGISTER
+A peer-to-peer mode registration request from one edge to another. Supernodes
+forward these to facilitate NAT crossing introductions.
+.TP
+REGISTER_ACK
+Complete peer-to-peer mode setup between two edges. These messages need to
+travel direct between edges.
+.TP
+FEDERATION
+Federated supernodes exchanging community information.
+
+.SH OTHER DIFFERENCES
+.TP
+HTTP Tunneling
+This experimental feature (-t option in n2n_v1) of n2n_v1 has been removed
+entirely from n2n_v2.
+.SH AUTHORS
+.TP
+Richard Andrews andrews (at) ntop.org - main author of n2n-2
+.TP
+Luca Deri
+deri (at) ntop.org - code inherited from n2n-1
+.SH SEE ALSO
+ifconfig(8) edge(8) supernode(1)
diff --git a/n2n_wire.h b/n2n_wire.h
new file mode 100644
index 0000000..8a3dfdf
--- /dev/null
+++ b/n2n_wire.h
@@ -0,0 +1,321 @@
+/* (c) 2009 Richard Andrews
+ *
+ * Contributions by:
+ * Luca Deri
+ * Lukasz Taczuk
+ */
+
+#if !defined( N2N_WIRE_H_ )
+#define N2N_WIRE_H_
+
+#include
+
+#if defined(WIN32)
+#include "win32/n2n_win32.h"
+
+#if defined(__MINGW32__)
+#include
+#endif /* #ifdef __MINGW32__ */
+
+#else /* #if defined(WIN32) */
+#include
+#include
+#include /* AF_INET and AF_INET6 */
+#endif /* #if defined(WIN32) */
+
+#define N2N_PKT_VERSION 2
+#define N2N_DEFAULT_TTL 2 /* can be forwarded twice at most */
+#define N2N_COMMUNITY_SIZE 16
+#define N2N_MAC_SIZE 6
+#define N2N_COOKIE_SIZE 4
+#define N2N_PKT_BUF_SIZE 2048
+#define N2N_SOCKBUF_SIZE 64 /* string representation of INET or INET6 sockets */
+
+typedef uint8_t n2n_community_t[N2N_COMMUNITY_SIZE];
+typedef uint8_t n2n_mac_t[N2N_MAC_SIZE];
+typedef uint8_t n2n_cookie_t[N2N_COOKIE_SIZE];
+
+typedef char n2n_sock_str_t[N2N_SOCKBUF_SIZE]; /* tracing string buffer */
+
+enum n2n_pc
+{
+ n2n_ping=0, /* Not used */
+ n2n_register=1, /* Register edge to edge */
+ n2n_deregister=2, /* Deregister this edge */
+ n2n_packet=3, /* PACKET data content */
+ n2n_register_ack=4, /* ACK of a registration from edge to edge */
+ n2n_register_super=5, /* Register edge to supernode */
+ n2n_register_super_ack=6, /* ACK from supernode to edge */
+ n2n_register_super_nak=7, /* NAK from supernode to edge - registration refused */
+ n2n_federation=8 /* Not used by edge */
+};
+
+typedef enum n2n_pc n2n_pc_t;
+
+#define N2N_FLAGS_OPTIONS 0x0080
+#define N2N_FLAGS_SOCKET 0x0040
+#define N2N_FLAGS_FROM_SUPERNODE 0x0020
+
+/* The bits in flag that are the packet type */
+#define N2N_FLAGS_TYPE_MASK 0x001f /* 0 - 31 */
+#define N2N_FLAGS_BITS_MASK 0xffe0
+
+#define IPV4_SIZE 4
+#define IPV6_SIZE 16
+
+
+#define N2N_AUTH_TOKEN_SIZE 32 /* bytes */
+
+
+#define N2N_EUNKNOWN -1
+#define N2N_ENOTIMPL -2
+#define N2N_EINVAL -3
+#define N2N_ENOSPACE -4
+
+
+typedef uint16_t n2n_flags_t;
+typedef uint16_t n2n_transform_t; /* Encryption, compression type. */
+typedef uint32_t n2n_sa_t; /* security association number */
+
+struct n2n_sock
+{
+ uint8_t family; /* AF_INET or AF_INET6; or 0 if invalid */
+ uint16_t port; /* host order */
+ union
+ {
+ uint8_t v6[IPV6_SIZE]; /* byte sequence */
+ uint8_t v4[IPV4_SIZE]; /* byte sequence */
+ } addr;
+};
+
+typedef struct n2n_sock n2n_sock_t;
+
+struct n2n_auth
+{
+ uint16_t scheme; /* What kind of auth */
+ uint16_t toksize; /* Size of auth token */
+ uint8_t token[N2N_AUTH_TOKEN_SIZE]; /* Auth data interpreted based on scheme */
+};
+
+typedef struct n2n_auth n2n_auth_t;
+
+
+struct n2n_common
+{
+ /* int version; */
+ uint8_t ttl;
+ n2n_pc_t pc;
+ n2n_flags_t flags;
+ n2n_community_t community;
+};
+
+typedef struct n2n_common n2n_common_t;
+
+struct n2n_REGISTER
+{
+ n2n_cookie_t cookie; /* Link REGISTER and REGISTER_ACK */
+ n2n_mac_t srcMac; /* MAC of registering party */
+ n2n_mac_t dstMac; /* MAC of target edge */
+ n2n_sock_t sock; /* REVISIT: unused? */
+};
+
+typedef struct n2n_REGISTER n2n_REGISTER_t;
+
+struct n2n_REGISTER_ACK
+{
+ n2n_cookie_t cookie; /* Return cookie from REGISTER */
+ n2n_mac_t srcMac; /* MAC of acknowledging party (supernode or edge) */
+ n2n_mac_t dstMac; /* Reflected MAC of registering edge from REGISTER */
+ n2n_sock_t sock; /* Supernode's view of edge socket (IP Addr, port) */
+};
+
+typedef struct n2n_REGISTER_ACK n2n_REGISTER_ACK_t;
+
+struct n2n_PACKET
+{
+ n2n_mac_t srcMac;
+ n2n_mac_t dstMac;
+ n2n_sock_t sock;
+ n2n_transform_t transform;
+};
+
+typedef struct n2n_PACKET n2n_PACKET_t;
+
+
+/* Linked with n2n_register_super in n2n_pc_t. Only from edge to supernode. */
+struct n2n_REGISTER_SUPER
+{
+ n2n_cookie_t cookie; /* Link REGISTER_SUPER and REGISTER_SUPER_ACK */
+ n2n_mac_t edgeMac; /* MAC to register with edge sending socket */
+ n2n_auth_t auth; /* Authentication scheme and tokens */
+};
+
+typedef struct n2n_REGISTER_SUPER n2n_REGISTER_SUPER_t;
+
+
+/* Linked with n2n_register_super_ack in n2n_pc_t. Only from supernode to edge. */
+struct n2n_REGISTER_SUPER_ACK
+{
+ n2n_cookie_t cookie; /* Return cookie from REGISTER_SUPER */
+ n2n_mac_t edgeMac; /* MAC registered to edge sending socket */
+ uint16_t lifetime; /* How long the registration will live */
+ n2n_sock_t sock; /* Sending sockets associated with edgeMac */
+
+ /* The packet format provides additional supernode definitions here.
+ * uint8_t count, then for each count there is one
+ * n2n_sock_t.
+ */
+ uint8_t num_sn; /* Number of supernodes that were send
+ * even if we cannot store them all. If
+ * non-zero then sn_bak is valid. */
+ n2n_sock_t sn_bak; /* Socket of the first backup supernode */
+
+};
+
+typedef struct n2n_REGISTER_SUPER_ACK n2n_REGISTER_SUPER_ACK_t;
+
+
+/* Linked with n2n_register_super_ack in n2n_pc_t. Only from supernode to edge. */
+struct n2n_REGISTER_SUPER_NAK
+{
+ n2n_cookie_t cookie; /* Return cookie from REGISTER_SUPER */
+};
+
+typedef struct n2n_REGISTER_SUPER_NAK n2n_REGISTER_SUPER_NAK_t;
+
+
+
+struct n2n_buf
+{
+ uint8_t * data;
+ size_t size;
+};
+
+typedef struct n2n_buf n2n_buf_t;
+
+int encode_uint8( uint8_t * base,
+ size_t * idx,
+ const uint8_t v );
+
+int decode_uint8( uint8_t * out,
+ const uint8_t * base,
+ size_t * rem,
+ size_t * idx );
+
+int encode_uint16( uint8_t * base,
+ size_t * idx,
+ const uint16_t v );
+
+int decode_uint16( uint16_t * out,
+ const uint8_t * base,
+ size_t * rem,
+ size_t * idx );
+
+int encode_uint32( uint8_t * base,
+ size_t * idx,
+ const uint32_t v );
+
+int decode_uint32( uint32_t * out,
+ const uint8_t * base,
+ size_t * rem,
+ size_t * idx );
+
+int encode_buf( uint8_t * base,
+ size_t * idx,
+ const void * p,
+ size_t s);
+
+int decode_buf( uint8_t * out,
+ size_t bufsize,
+ const uint8_t * base,
+ size_t * rem,
+ size_t * idx );
+
+int encode_mac( uint8_t * base,
+ size_t * idx,
+ const n2n_mac_t m );
+
+int decode_mac( uint8_t * out, /* of size N2N_MAC_SIZE. This clearer than passing a n2n_mac_t */
+ const uint8_t * base,
+ size_t * rem,
+ size_t * idx );
+
+int encode_common( uint8_t * base,
+ size_t * idx,
+ const n2n_common_t * common );
+
+int decode_common( n2n_common_t * out,
+ const uint8_t * base,
+ size_t * rem,
+ size_t * idx );
+
+int encode_sock( uint8_t * base,
+ size_t * idx,
+ const n2n_sock_t * sock );
+
+int decode_sock( n2n_sock_t * sock,
+ const uint8_t * base,
+ size_t * rem,
+ size_t * idx );
+
+int encode_REGISTER( uint8_t * base,
+ size_t * idx,
+ const n2n_common_t * common,
+ const n2n_REGISTER_t * reg );
+
+int decode_REGISTER( n2n_REGISTER_t * pkt,
+ const n2n_common_t * cmn, /* info on how to interpret it */
+ const uint8_t * base,
+ size_t * rem,
+ size_t * idx );
+
+int encode_REGISTER_SUPER( uint8_t * base,
+ size_t * idx,
+ const n2n_common_t * common,
+ const n2n_REGISTER_SUPER_t * reg );
+
+int decode_REGISTER_SUPER( n2n_REGISTER_SUPER_t * pkt,
+ const n2n_common_t * cmn, /* info on how to interpret it */
+ const uint8_t * base,
+ size_t * rem,
+ size_t * idx );
+
+int encode_REGISTER_ACK( uint8_t * base,
+ size_t * idx,
+ const n2n_common_t * common,
+ const n2n_REGISTER_ACK_t * reg );
+
+int decode_REGISTER_ACK( n2n_REGISTER_ACK_t * pkt,
+ const n2n_common_t * cmn, /* info on how to interpret it */
+ const uint8_t * base,
+ size_t * rem,
+ size_t * idx );
+
+int encode_REGISTER_SUPER_ACK( uint8_t * base,
+ size_t * idx,
+ const n2n_common_t * cmn,
+ const n2n_REGISTER_SUPER_ACK_t * reg );
+
+int decode_REGISTER_SUPER_ACK( n2n_REGISTER_SUPER_ACK_t * reg,
+ const n2n_common_t * cmn, /* info on how to interpret it */
+ const uint8_t * base,
+ size_t * rem,
+ size_t * idx );
+
+int fill_sockaddr( struct sockaddr * addr,
+ size_t addrlen,
+ const n2n_sock_t * sock );
+
+int encode_PACKET( uint8_t * base,
+ size_t * idx,
+ const n2n_common_t * common,
+ const n2n_PACKET_t * pkt );
+
+int decode_PACKET( n2n_PACKET_t * pkt,
+ const n2n_common_t * cmn, /* info on how to interpret it */
+ const uint8_t * base,
+ size_t * rem,
+ size_t * idx );
+
+
+#endif /* #if !defined( N2N_WIRE_H_ ) */
diff --git a/openwrt/kamikaze/Makefile b/openwrt/kamikaze/Makefile
new file mode 100644
index 0000000..ddcc7c1
--- /dev/null
+++ b/openwrt/kamikaze/Makefile
@@ -0,0 +1,55 @@
+#
+# Copyright (C) 2008 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+
+
+include $(TOPDIR)/rules.mk
+
+PKG_BRANCH:=trunk
+PKG_SOURCE_URL:=https://svn.ntop.org/svn/ntop/trunk/n2n
+PKG_REV:=$(shell LC_ALL=C svn info ${PKG_SOURCE_URL} | sed -ne's/^Last Changed Rev: //p')
+
+PKG_NAME:=n2n
+PKG_VERSION:=svn$(PKG_REV)
+PKG_RELEASE:=1
+
+PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
+PKG_SOURCE:=$(PKG_SOURCE_SUBDIR).tar.gz
+PKG_SOURCE_PROTO:=svn
+PKG_SOURCE_VERSION:=$(PKG_REV)
+
+PKG_BUILD_DEPENDS:=
+
+PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION)
+PKG_INSTALL_DIR:=$(PKG_BUILD_DIR)
+
+
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/n2n
+ SECTION:=net
+ CATEGORY:=Network
+ TITLE:=VPN tunneling daemon
+ URL:=http://www.ntop.org/n2n/
+ SUBMENU:=VPN
+ DEPENDS:=libpthread
+endef
+
+
+define Build/Configure
+endef
+
+define Build/Compile
+ $(MAKE) CC="$(TARGET_CC)" -C $(PKG_BUILD_DIR)
+endef
+
+
+define Package/n2n/install
+ $(INSTALL_DIR) $(1)/usr/sbin
+ $(INSTALL_BIN) $(PKG_INSTALL_DIR)/edge $(1)/usr/sbin/
+ $(INSTALL_BIN) $(PKG_INSTALL_DIR)/supernode $(1)/usr/sbin/
+endef
+
+$(eval $(call BuildPackage,n2n))
diff --git a/scripts/mk_SRPM.sh b/scripts/mk_SRPM.sh
new file mode 100755
index 0000000..2b1b374
--- /dev/null
+++ b/scripts/mk_SRPM.sh
@@ -0,0 +1,30 @@
+#!/bin/sh
+
+# This script makes a SRPM - a source RPM file which can be built into the
+# appropriate distro specific RPM for any platform.
+#
+# To build the binary package:
+# rpm -i n2n-.src.rpm
+# rpmbuild -bb n2n.spec
+#
+# Look for the "Wrote:" line to see where the final RPM is.
+#
+# To run this script cd to the n2n directory and run it as follows
+# scripts/mk_SRPMS.sh
+#
+
+set -e
+
+set -x
+
+BASE=`pwd`
+
+TARFILE=`${BASE}/scripts/mk_tar.sh`
+
+test -f ${TARFILE}
+
+echo "Building SRPM"
+# -ts means build source RPM from tarfile
+rpmbuild -ts ${TARFILE}
+
+echo "Done"
diff --git a/scripts/mk_deb.sh b/scripts/mk_deb.sh
new file mode 100755
index 0000000..42d8691
--- /dev/null
+++ b/scripts/mk_deb.sh
@@ -0,0 +1,46 @@
+#!/bin/bash
+
+# This script makes a SRPM - a source RPM file which can be built into the
+# appropriate distro specific RPM for any platform.
+#
+# To build the binary package:
+# rpm -i n2n-.src.rpm
+# rpmbuild -bb n2n.spec
+#
+# Look for the "Wrote:" line to see where the final RPM is.
+#
+# To run this script cd to the n2n directory and run it as follows
+# scripts/mk_SRPMS.sh
+#
+
+set -e
+
+set -x
+
+BASE=`pwd`
+
+TARFILE=`${BASE}/scripts/mk_tar.sh`
+TEMPDIR="build_deb"
+
+test -f ${TARFILE}
+
+echo "Building .deb"
+
+if [ -d ${TEMPDIR} ]; then
+ echo "Removing ${TEMPDIR} directory"
+ rm -rf ${TEMPDIR} >&2
+fi
+
+mkdir ${TEMPDIR}
+
+pushd ${TEMPDIR}
+
+tar xzf ${TARFILE} #At original location
+
+cd n2n*
+
+dpkg-buildpackage -rfakeroot
+
+popd
+
+echo "Done"
diff --git a/scripts/mk_tar.sh b/scripts/mk_tar.sh
new file mode 100755
index 0000000..0e84331
--- /dev/null
+++ b/scripts/mk_tar.sh
@@ -0,0 +1,116 @@
+#!/bin/bash
+
+# This script makes a SRPM - a source RPM file which can be built into the
+# appropriate distro specific RPM for any platform.
+#
+# To build the binary package:
+# rpm -i n2n-.src.rpm
+# rpmbuild -bb n2n.spec
+#
+# Look for the "Wrote:" line to see where the final RPM is.
+#
+# To run this script cd to the n2n directory and run it as follows
+# scripts/mk_SRPMS.sh
+#
+
+set -e
+
+function exit_fail()
+{
+ echo "$1"
+ exit 1
+}
+
+PACKAGE="n2n"
+PKG_VERSION="2.1.0"
+PKG_AND_VERSION="${PACKAGE}-${PKG_VERSION}"
+
+TEMPDIR="tmp"
+
+SOURCE_MANIFEST="
+README
+edge.c
+lzoconf.h
+lzodefs.h
+Makefile
+minilzo.c
+minilzo.h
+n2n.c
+n2n.h
+n2n_keyfile.c
+n2n_keyfile.h
+n2n.spec
+n2n_transforms.h
+n2n_wire.h
+sn.c
+transform_aes.c
+transform_null.c
+transform_tf.c
+tuntap_linux.c
+tuntap_freebsd.c
+tuntap_netbsd.c
+tuntap_osx.c
+twofish.c
+twofish.h
+version.c
+wire.c
+edge.8
+supernode.1
+n2n_v2.7
+debian/changelog
+debian/compat
+debian/control
+debian/copyright
+debian/n2n-edge.docs
+debian/n2n-edge.install
+debian/n2n-supernode.install
+debian/n2n-edge.manpages
+debian/n2n-supernode.manpages
+debian/README.Debian
+debian/rules
+"
+
+BASE=`pwd`
+
+for F in ${SOURCE_MANIFEST}; do
+ test -e $F || exit_fail "Cannot find $F. Maybe you're in the wrong directory. Please execute from n2n directory."; >&2
+done
+
+echo "Found critical files. Proceeding." >&2
+
+if [ -d ${TEMPDIR} ]; then
+ echo "Removing ${TEMPDIR} directory"
+ rm -rf ${TEMPDIR} >&2
+fi
+
+mkdir ${TEMPDIR} >&2
+
+pushd ${TEMPDIR} >&2
+
+echo "Creating staging directory ${PWD}/${PKG_AND_VERSION}" >&2
+
+if [ -d ${PKG_AND_VERSION} ] ; then
+ echo "Removing ${PKG_AND_VERSION} directory"
+ rm -rf ${PKG_AND_VERSION} >&2
+fi
+
+mkdir ${PKG_AND_VERSION}
+
+pushd ${BASE} >&2
+
+echo "Copying in files" >&2
+for F in ${SOURCE_MANIFEST}; do
+ cp --parents -a $F ${TEMPDIR}/${PKG_AND_VERSION}/
+done
+
+popd >&2
+
+TARFILE="${PKG_AND_VERSION}.tar.gz"
+echo "Creating ${TARFILE}" >&2
+tar czf ${BASE}/${TARFILE} ${PKG_AND_VERSION}
+
+popd >&2
+
+rm -rf ${TEMPDIR} >&2
+
+echo ${BASE}/${TARFILE}
diff --git a/sn.c b/sn.c
new file mode 100644
index 0000000..7df4729
--- /dev/null
+++ b/sn.c
@@ -0,0 +1,793 @@
+/* Supernode for n2n-2.x */
+
+/* (c) 2009 Richard Andrews
+ *
+ * Contributions by:
+ * Lukasz Taczuk
+ * Struan Bartlett
+ */
+
+
+#include "n2n.h"
+
+
+#define N2N_SN_LPORT_DEFAULT 7654
+#define N2N_SN_PKTBUF_SIZE 2048
+
+#define N2N_SN_MGMT_PORT 5645
+
+
+struct sn_stats
+{
+ size_t errors; /* Number of errors encountered. */
+ size_t reg_super; /* Number of REGISTER_SUPER requests received. */
+ size_t reg_super_nak; /* Number of REGISTER_SUPER requests declined. */
+ size_t fwd; /* Number of messages forwarded. */
+ size_t broadcast; /* Number of messages broadcast to a community. */
+ time_t last_fwd; /* Time when last message was forwarded. */
+ time_t last_reg_super; /* Time when last REGISTER_SUPER was received. */
+};
+
+typedef struct sn_stats sn_stats_t;
+
+struct n2n_sn
+{
+ time_t start_time; /* Used to measure uptime. */
+ sn_stats_t stats;
+ int daemon; /* If non-zero then daemonise. */
+ uint16_t lport; /* Local UDP port to bind to. */
+ int sock; /* Main socket for UDP traffic with edges. */
+ int mgmt_sock; /* management socket. */
+ struct peer_info * edges; /* Link list of registered edges. */
+};
+
+typedef struct n2n_sn n2n_sn_t;
+
+
+static int try_forward( n2n_sn_t * sss,
+ const n2n_common_t * cmn,
+ const n2n_mac_t dstMac,
+ const uint8_t * pktbuf,
+ size_t pktsize );
+
+static int try_broadcast( n2n_sn_t * sss,
+ const n2n_common_t * cmn,
+ const n2n_mac_t srcMac,
+ const uint8_t * pktbuf,
+ size_t pktsize );
+
+
+
+/** Initialise the supernode structure */
+static int init_sn( n2n_sn_t * sss )
+{
+#ifdef WIN32
+ initWin32();
+#endif
+ memset( sss, 0, sizeof(n2n_sn_t) );
+
+ sss->daemon = 1; /* By defult run as a daemon. */
+ sss->lport = N2N_SN_LPORT_DEFAULT;
+ sss->sock = -1;
+ sss->mgmt_sock = -1;
+ sss->edges = NULL;
+
+ return 0; /* OK */
+}
+
+/** Deinitialise the supernode structure and deallocate any memory owned by
+ * it. */
+static void deinit_sn( n2n_sn_t * sss )
+{
+ if (sss->sock >= 0)
+ {
+ closesocket(sss->sock);
+ }
+ sss->sock=-1;
+
+ if ( sss->mgmt_sock >= 0 )
+ {
+ closesocket(sss->mgmt_sock);
+ }
+ sss->mgmt_sock=-1;
+
+ purge_peer_list( &(sss->edges), 0xffffffff );
+}
+
+
+/** Determine the appropriate lifetime for new registrations.
+ *
+ * If the supernode has been put into a pre-shutdown phase then this lifetime
+ * should not allow registrations to continue beyond the shutdown point.
+ */
+static uint16_t reg_lifetime( n2n_sn_t * sss )
+{
+ return 120;
+}
+
+
+/** Update the edge table with the details of the edge which contacted the
+ * supernode. */
+static int update_edge( n2n_sn_t * sss,
+ const n2n_mac_t edgeMac,
+ const n2n_community_t community,
+ const n2n_sock_t * sender_sock,
+ time_t now)
+{
+ macstr_t mac_buf;
+ n2n_sock_str_t sockbuf;
+ struct peer_info * scan;
+
+ traceEvent( TRACE_DEBUG, "update_edge for %s [%s]",
+ macaddr_str( mac_buf, edgeMac ),
+ sock_to_cstr( sockbuf, sender_sock ) );
+
+ scan = find_peer_by_mac( sss->edges, edgeMac );
+
+ if ( NULL == scan )
+ {
+ /* Not known */
+
+ scan = (struct peer_info*)calloc(1, sizeof(struct peer_info)); /* deallocated in purge_expired_registrations */
+
+ memcpy(scan->community_name, community, sizeof(n2n_community_t) );
+ memcpy(&(scan->mac_addr), edgeMac, sizeof(n2n_mac_t));
+ memcpy(&(scan->sock), sender_sock, sizeof(n2n_sock_t));
+
+ /* insert this guy at the head of the edges list */
+ scan->next = sss->edges; /* first in list */
+ sss->edges = scan; /* head of list points to new scan */
+
+ traceEvent( TRACE_INFO, "update_edge created %s ==> %s",
+ macaddr_str( mac_buf, edgeMac ),
+ sock_to_cstr( sockbuf, sender_sock ) );
+ }
+ else
+ {
+ /* Known */
+ if ( (0 != memcmp(community, scan->community_name, sizeof(n2n_community_t))) ||
+ (0 != sock_equal(sender_sock, &(scan->sock) )) )
+ {
+ memcpy(scan->community_name, community, sizeof(n2n_community_t) );
+ memcpy(&(scan->sock), sender_sock, sizeof(n2n_sock_t));
+
+ traceEvent( TRACE_INFO, "update_edge updated %s ==> %s",
+ macaddr_str( mac_buf, edgeMac ),
+ sock_to_cstr( sockbuf, sender_sock ) );
+ }
+ else
+ {
+ traceEvent( TRACE_DEBUG, "update_edge unchanged %s ==> %s",
+ macaddr_str( mac_buf, edgeMac ),
+ sock_to_cstr( sockbuf, sender_sock ) );
+ }
+
+ }
+
+ scan->last_seen = now;
+ return 0;
+}
+
+
+/** Send a datagram to the destination embodied in a n2n_sock_t.
+ *
+ * @return -1 on error otherwise number of bytes sent
+ */
+static ssize_t sendto_sock(n2n_sn_t * sss,
+ const n2n_sock_t * sock,
+ const uint8_t * pktbuf,
+ size_t pktsize)
+{
+ n2n_sock_str_t sockbuf;
+
+ if ( AF_INET == sock->family )
+ {
+ struct sockaddr_in udpsock;
+
+ udpsock.sin_family = AF_INET;
+ udpsock.sin_port = htons( sock->port );
+ memcpy( &(udpsock.sin_addr.s_addr), &(sock->addr.v4), IPV4_SIZE );
+
+ traceEvent( TRACE_DEBUG, "sendto_sock %lu to [%s]",
+ pktsize,
+ sock_to_cstr( sockbuf, sock ) );
+
+ return sendto( sss->sock, pktbuf, pktsize, 0,
+ (const struct sockaddr *)&udpsock, sizeof(struct sockaddr_in) );
+ }
+ else
+ {
+ /* AF_INET6 not implemented */
+ errno = EAFNOSUPPORT;
+ return -1;
+ }
+}
+
+
+
+/** Try to forward a message to a unicast MAC. If the MAC is unknown then
+ * broadcast to all edges in the destination community.
+ */
+static int try_forward( n2n_sn_t * sss,
+ const n2n_common_t * cmn,
+ const n2n_mac_t dstMac,
+ const uint8_t * pktbuf,
+ size_t pktsize )
+{
+ struct peer_info * scan;
+ macstr_t mac_buf;
+ n2n_sock_str_t sockbuf;
+
+ scan = find_peer_by_mac( sss->edges, dstMac );
+
+ if ( NULL != scan )
+ {
+ int data_sent_len;
+ data_sent_len = sendto_sock( sss, &(scan->sock), pktbuf, pktsize );
+
+ if ( data_sent_len == pktsize )
+ {
+ ++(sss->stats.fwd);
+ traceEvent(TRACE_DEBUG, "unicast %lu to [%s] %s",
+ pktsize,
+ sock_to_cstr( sockbuf, &(scan->sock) ),
+ macaddr_str(mac_buf, scan->mac_addr));
+ }
+ else
+ {
+ ++(sss->stats.errors);
+ traceEvent(TRACE_ERROR, "unicast %lu to [%s] %s FAILED (%d: %s)",
+ pktsize,
+ sock_to_cstr( sockbuf, &(scan->sock) ),
+ macaddr_str(mac_buf, scan->mac_addr),
+ errno, strerror(errno) );
+ }
+ }
+ else
+ {
+ traceEvent( TRACE_DEBUG, "try_forward unknown MAC" );
+
+ /* Not a known MAC so drop. */
+ }
+
+ return 0;
+}
+
+
+/** Try and broadcast a message to all edges in the community.
+ *
+ * This will send the exact same datagram to zero or more edges registered to
+ * the supernode.
+ */
+static int try_broadcast( n2n_sn_t * sss,
+ const n2n_common_t * cmn,
+ const n2n_mac_t srcMac,
+ const uint8_t * pktbuf,
+ size_t pktsize )
+{
+ struct peer_info * scan;
+ macstr_t mac_buf;
+ n2n_sock_str_t sockbuf;
+
+ traceEvent( TRACE_DEBUG, "try_broadcast" );
+
+ scan = sss->edges;
+ while(scan != NULL)
+ {
+ if( 0 == (memcmp(scan->community_name, cmn->community, sizeof(n2n_community_t)) )
+ && (0 != memcmp(srcMac, scan->mac_addr, sizeof(n2n_mac_t)) ) )
+ /* REVISIT: exclude if the destination socket is where the packet came from. */
+ {
+ int data_sent_len;
+
+ data_sent_len = sendto_sock(sss, &(scan->sock), pktbuf, pktsize);
+
+ if(data_sent_len != pktsize)
+ {
+ ++(sss->stats.errors);
+ traceEvent(TRACE_WARNING, "multicast %lu to [%s] %s failed %s",
+ pktsize,
+ sock_to_cstr( sockbuf, &(scan->sock) ),
+ macaddr_str(mac_buf, scan->mac_addr),
+ strerror(errno));
+ }
+ else
+ {
+ ++(sss->stats.broadcast);
+ traceEvent(TRACE_DEBUG, "multicast %lu to [%s] %s",
+ pktsize,
+ sock_to_cstr( sockbuf, &(scan->sock) ),
+ macaddr_str(mac_buf, scan->mac_addr));
+ }
+ }
+
+ scan = scan->next;
+ } /* while */
+
+ return 0;
+}
+
+
+static int process_mgmt( n2n_sn_t * sss,
+ const struct sockaddr_in * sender_sock,
+ const uint8_t * mgmt_buf,
+ size_t mgmt_size,
+ time_t now)
+{
+ char resbuf[N2N_SN_PKTBUF_SIZE];
+ size_t ressize=0;
+ ssize_t r;
+
+ traceEvent( TRACE_DEBUG, "process_mgmt" );
+
+ ressize += snprintf( resbuf+ressize, N2N_SN_PKTBUF_SIZE-ressize,
+ "----------------\n" );
+
+ ressize += snprintf( resbuf+ressize, N2N_SN_PKTBUF_SIZE-ressize,
+ "uptime %lu\n", (now - sss->start_time) );
+
+ ressize += snprintf( resbuf+ressize, N2N_SN_PKTBUF_SIZE-ressize,
+ "edges %u\n",
+ (unsigned int)peer_list_size( sss->edges ) );
+
+ ressize += snprintf( resbuf+ressize, N2N_SN_PKTBUF_SIZE-ressize,
+ "errors %u\n",
+ (unsigned int)sss->stats.errors );
+
+ ressize += snprintf( resbuf+ressize, N2N_SN_PKTBUF_SIZE-ressize,
+ "reg_sup %u\n",
+ (unsigned int)sss->stats.reg_super );
+
+ ressize += snprintf( resbuf+ressize, N2N_SN_PKTBUF_SIZE-ressize,
+ "reg_nak %u\n",
+ (unsigned int)sss->stats.reg_super_nak );
+
+ ressize += snprintf( resbuf+ressize, N2N_SN_PKTBUF_SIZE-ressize,
+ "fwd %u\n",
+ (unsigned int) sss->stats.fwd );
+
+ ressize += snprintf( resbuf+ressize, N2N_SN_PKTBUF_SIZE-ressize,
+ "broadcast %u\n",
+ (unsigned int) sss->stats.broadcast );
+
+ ressize += snprintf( resbuf+ressize, N2N_SN_PKTBUF_SIZE-ressize,
+ "last fwd %lu sec ago\n",
+ (long unsigned int)(now - sss->stats.last_fwd) );
+
+ ressize += snprintf( resbuf+ressize, N2N_SN_PKTBUF_SIZE-ressize,
+ "last reg %lu sec ago\n",
+ (long unsigned int) (now - sss->stats.last_reg_super) );
+
+
+ r = sendto( sss->mgmt_sock, resbuf, ressize, 0/*flags*/,
+ (struct sockaddr *)sender_sock, sizeof(struct sockaddr_in) );
+
+ if ( r <= 0 )
+ {
+ ++(sss->stats.errors);
+ traceEvent( TRACE_ERROR, "process_mgmt : sendto failed. %s", strerror(errno) );
+ }
+
+ return 0;
+}
+
+
+/** Examine a datagram and determine what to do with it.
+ *
+ */
+static int process_udp( n2n_sn_t * sss,
+ const struct sockaddr_in * sender_sock,
+ const uint8_t * udp_buf,
+ size_t udp_size,
+ time_t now)
+{
+ n2n_common_t cmn; /* common fields in the packet header */
+ size_t rem;
+ size_t idx;
+ size_t msg_type;
+ uint8_t from_supernode;
+ macstr_t mac_buf;
+ macstr_t mac_buf2;
+ n2n_sock_str_t sockbuf;
+
+
+ traceEvent( TRACE_DEBUG, "process_udp(%lu)", udp_size );
+
+ /* Use decode_common() to determine the kind of packet then process it:
+ *
+ * REGISTER_SUPER adds an edge and generate a return REGISTER_SUPER_ACK
+ *
+ * REGISTER, REGISTER_ACK and PACKET messages are forwarded to their
+ * destination edge. If the destination is not known then PACKETs are
+ * broadcast.
+ */
+
+ rem = udp_size; /* Counts down bytes of packet to protect against buffer overruns. */
+ idx = 0; /* marches through packet header as parts are decoded. */
+ if ( decode_common(&cmn, udp_buf, &rem, &idx) < 0 )
+ {
+ traceEvent( TRACE_ERROR, "Failed to decode common section" );
+ return -1; /* failed to decode packet */
+ }
+
+ msg_type = cmn.pc; /* packet code */
+ from_supernode= cmn.flags & N2N_FLAGS_FROM_SUPERNODE;
+
+ if ( cmn.ttl < 1 )
+ {
+ traceEvent( TRACE_WARNING, "Expired TTL" );
+ return 0; /* Don't process further */
+ }
+
+ --(cmn.ttl); /* The value copied into all forwarded packets. */
+
+ if ( msg_type == MSG_TYPE_PACKET )
+ {
+ /* PACKET from one edge to another edge via supernode. */
+
+ /* pkt will be modified in place and recoded to an output of potentially
+ * different size due to addition of the socket.*/
+ n2n_PACKET_t pkt;
+ n2n_common_t cmn2;
+ uint8_t encbuf[N2N_SN_PKTBUF_SIZE];
+ size_t encx=0;
+ int unicast; /* non-zero if unicast */
+ const uint8_t * rec_buf; /* either udp_buf or encbuf */
+
+
+ sss->stats.last_fwd=now;
+ decode_PACKET( &pkt, &cmn, udp_buf, &rem, &idx );
+
+ unicast = (0 == is_multi_broadcast(pkt.dstMac) );
+
+ traceEvent( TRACE_DEBUG, "Rx PACKET (%s) %s -> %s %s",
+ (unicast?"unicast":"multicast"),
+ macaddr_str( mac_buf, pkt.srcMac ),
+ macaddr_str( mac_buf2, pkt.dstMac ),
+ (from_supernode?"from sn":"local") );
+
+ if ( !from_supernode )
+ {
+ memcpy( &cmn2, &cmn, sizeof( n2n_common_t ) );
+
+ /* We are going to add socket even if it was not there before */
+ cmn2.flags |= N2N_FLAGS_SOCKET | N2N_FLAGS_FROM_SUPERNODE;
+
+ pkt.sock.family = AF_INET;
+ pkt.sock.port = ntohs(sender_sock->sin_port);
+ memcpy( pkt.sock.addr.v4, &(sender_sock->sin_addr.s_addr), IPV4_SIZE );
+
+ rec_buf = encbuf;
+
+ /* Re-encode the header. */
+ encode_PACKET( encbuf, &encx, &cmn2, &pkt );
+
+ /* Copy the original payload unchanged */
+ encode_buf( encbuf, &encx, (udp_buf + idx), (udp_size - idx ) );
+ }
+ else
+ {
+ /* Already from a supernode. Nothing to modify, just pass to
+ * destination. */
+
+ traceEvent( TRACE_DEBUG, "Rx PACKET fwd unmodified" );
+
+ rec_buf = udp_buf;
+ encx = udp_size;
+ }
+
+ /* Common section to forward the final product. */
+ if ( unicast )
+ {
+ try_forward( sss, &cmn, pkt.dstMac, rec_buf, encx );
+ }
+ else
+ {
+ try_broadcast( sss, &cmn, pkt.srcMac, rec_buf, encx );
+ }
+ }/* MSG_TYPE_PACKET */
+ else if ( msg_type == MSG_TYPE_REGISTER )
+ {
+ /* Forwarding a REGISTER from one edge to the next */
+
+ n2n_REGISTER_t reg;
+ n2n_common_t cmn2;
+ uint8_t encbuf[N2N_SN_PKTBUF_SIZE];
+ size_t encx=0;
+ int unicast; /* non-zero if unicast */
+ const uint8_t * rec_buf; /* either udp_buf or encbuf */
+
+ sss->stats.last_fwd=now;
+ decode_REGISTER( ®, &cmn, udp_buf, &rem, &idx );
+
+ unicast = (0 == is_multi_broadcast(reg.dstMac) );
+
+ if ( unicast )
+ {
+ traceEvent( TRACE_DEBUG, "Rx REGISTER %s -> %s %s",
+ macaddr_str( mac_buf, reg.srcMac ),
+ macaddr_str( mac_buf2, reg.dstMac ),
+ ((cmn.flags & N2N_FLAGS_FROM_SUPERNODE)?"from sn":"local") );
+
+ if ( 0 != (cmn.flags & N2N_FLAGS_FROM_SUPERNODE) )
+ {
+ memcpy( &cmn2, &cmn, sizeof( n2n_common_t ) );
+
+ /* We are going to add socket even if it was not there before */
+ cmn2.flags |= N2N_FLAGS_SOCKET | N2N_FLAGS_FROM_SUPERNODE;
+
+ reg.sock.family = AF_INET;
+ reg.sock.port = ntohs(sender_sock->sin_port);
+ memcpy( reg.sock.addr.v4, &(sender_sock->sin_addr.s_addr), IPV4_SIZE );
+
+ rec_buf = encbuf;
+
+ /* Re-encode the header. */
+ encode_REGISTER( encbuf, &encx, &cmn2, ® );
+
+ /* Copy the original payload unchanged */
+ encode_buf( encbuf, &encx, (udp_buf + idx), (udp_size - idx ) );
+ }
+ else
+ {
+ /* Already from a supernode. Nothing to modify, just pass to
+ * destination. */
+
+ rec_buf = udp_buf;
+ encx = udp_size;
+ }
+
+ try_forward( sss, &cmn, reg.dstMac, rec_buf, encx ); /* unicast only */
+ }
+ else
+ {
+ traceEvent( TRACE_ERROR, "Rx REGISTER with multicast destination" );
+ }
+
+ }
+ else if ( msg_type == MSG_TYPE_REGISTER_ACK )
+ {
+ traceEvent( TRACE_DEBUG, "Rx REGISTER_ACK (NOT IMPLEMENTED) SHould not be via supernode" );
+ }
+ else if ( msg_type == MSG_TYPE_REGISTER_SUPER )
+ {
+ n2n_REGISTER_SUPER_t reg;
+ n2n_REGISTER_SUPER_ACK_t ack;
+ n2n_common_t cmn2;
+ uint8_t ackbuf[N2N_SN_PKTBUF_SIZE];
+ size_t encx=0;
+
+ /* Edge requesting registration with us. */
+
+ sss->stats.last_reg_super=now;
+ ++(sss->stats.reg_super);
+ decode_REGISTER_SUPER( ®, &cmn, udp_buf, &rem, &idx );
+
+ cmn2.ttl = N2N_DEFAULT_TTL;
+ cmn2.pc = n2n_register_super_ack;
+ cmn2.flags = N2N_FLAGS_SOCKET | N2N_FLAGS_FROM_SUPERNODE;
+ memcpy( cmn2.community, cmn.community, sizeof(n2n_community_t) );
+
+ memcpy( &(ack.cookie), &(reg.cookie), sizeof(n2n_cookie_t) );
+ memcpy( ack.edgeMac, reg.edgeMac, sizeof(n2n_mac_t) );
+ ack.lifetime = reg_lifetime( sss );
+
+ ack.sock.family = AF_INET;
+ ack.sock.port = ntohs(sender_sock->sin_port);
+ memcpy( ack.sock.addr.v4, &(sender_sock->sin_addr.s_addr), IPV4_SIZE );
+
+ ack.num_sn=0; /* No backup */
+ memset( &(ack.sn_bak), 0, sizeof(n2n_sock_t) );
+
+ traceEvent( TRACE_DEBUG, "Rx REGISTER_SUPER for %s [%s]",
+ macaddr_str( mac_buf, reg.edgeMac ),
+ sock_to_cstr( sockbuf, &(ack.sock) ) );
+
+ update_edge( sss, reg.edgeMac, cmn.community, &(ack.sock), now );
+
+ encode_REGISTER_SUPER_ACK( ackbuf, &encx, &cmn2, &ack );
+
+ sendto( sss->sock, ackbuf, encx, 0,
+ (struct sockaddr *)sender_sock, sizeof(struct sockaddr_in) );
+
+ traceEvent( TRACE_DEBUG, "Tx REGISTER_SUPER_ACK for %s [%s]",
+ macaddr_str( mac_buf, reg.edgeMac ),
+ sock_to_cstr( sockbuf, &(ack.sock) ) );
+
+ }
+
+
+ return 0;
+}
+
+
+/** Help message to print if the command line arguments are not valid. */
+static void exit_help(int argc, char * const argv[])
+{
+ fprintf( stderr, "%s usage\n", argv[0] );
+ fprintf( stderr, "-l \tSet UDP main listen port to \n" );
+
+#if defined(N2N_HAVE_DAEMON)
+ fprintf( stderr, "-f \tRun in foreground.\n" );
+#endif /* #if defined(N2N_HAVE_DAEMON) */
+ fprintf( stderr, "-v \tIncrease verbosity. Can be used multiple times.\n" );
+ fprintf( stderr, "-h \tThis help message.\n" );
+ fprintf( stderr, "\n" );
+ exit(1);
+}
+
+static int run_loop( n2n_sn_t * sss );
+
+/* *********************************************** */
+
+static const struct option long_options[] = {
+ { "foreground", no_argument, NULL, 'f' },
+ { "local-port", required_argument, NULL, 'l' },
+ { "help" , no_argument, NULL, 'h' },
+ { "verbose", no_argument, NULL, 'v' },
+ { NULL, 0, NULL, 0 }
+};
+
+/** Main program entry point from kernel. */
+int main( int argc, char * const argv[] )
+{
+ n2n_sn_t sss;
+
+ init_sn( &sss );
+
+ {
+ int opt;
+
+ while((opt = getopt_long(argc, argv, "fl:vh", long_options, NULL)) != -1)
+ {
+ switch (opt)
+ {
+ case 'l': /* local-port */
+ sss.lport = atoi(optarg);
+ break;
+ case 'f': /* foreground */
+ sss.daemon = 0;
+ break;
+ case 'h': /* help */
+ exit_help(argc, argv);
+ break;
+ case 'v': /* verbose */
+ ++traceLevel;
+ break;
+ }
+ }
+
+ }
+
+#if defined(N2N_HAVE_DAEMON)
+ if (sss.daemon)
+ {
+ useSyslog=1; /* traceEvent output now goes to syslog. */
+ if ( -1 == daemon( 0, 0 ) )
+ {
+ traceEvent( TRACE_ERROR, "Failed to become daemon." );
+ exit(-5);
+ }
+ }
+#endif /* #if defined(N2N_HAVE_DAEMON) */
+
+ traceEvent( TRACE_DEBUG, "traceLevel is %d", traceLevel);
+
+ sss.sock = open_socket(sss.lport, 1 /*bind ANY*/ );
+ if ( -1 == sss.sock )
+ {
+ traceEvent( TRACE_ERROR, "Failed to open main socket. %s", strerror(errno) );
+ exit(-2);
+ }
+ else
+ {
+ traceEvent( TRACE_NORMAL, "supernode is listening on UDP %u (main)", sss.lport );
+ }
+
+ sss.mgmt_sock = open_socket(N2N_SN_MGMT_PORT, 0 /* bind LOOPBACK */ );
+ if ( -1 == sss.mgmt_sock )
+ {
+ traceEvent( TRACE_ERROR, "Failed to open management socket. %s", strerror(errno) );
+ exit(-2);
+ }
+ else
+ {
+ traceEvent( TRACE_NORMAL, "supernode is listening on UDP %u (management)", N2N_SN_MGMT_PORT );
+ }
+
+ traceEvent(TRACE_NORMAL, "supernode started");
+
+ return run_loop(&sss);
+}
+
+
+/** Long lived processing entry point. Split out from main to simply
+ * daemonisation on some platforms. */
+static int run_loop( n2n_sn_t * sss )
+{
+ uint8_t pktbuf[N2N_SN_PKTBUF_SIZE];
+ int keep_running=1;
+
+ sss->start_time = time(NULL);
+
+ while(keep_running)
+ {
+ int rc;
+ ssize_t bread;
+ int max_sock;
+ fd_set socket_mask;
+ struct timeval wait_time;
+ time_t now=0;
+
+ FD_ZERO(&socket_mask);
+ max_sock = MAX(sss->sock, sss->mgmt_sock);
+
+ FD_SET(sss->sock, &socket_mask);
+ FD_SET(sss->mgmt_sock, &socket_mask);
+
+ wait_time.tv_sec = 10; wait_time.tv_usec = 0;
+ rc = select(max_sock+1, &socket_mask, NULL, NULL, &wait_time);
+
+ now = time(NULL);
+
+ if(rc > 0)
+ {
+ if (FD_ISSET(sss->sock, &socket_mask))
+ {
+ struct sockaddr_in sender_sock;
+ socklen_t i;
+
+ i = sizeof(sender_sock);
+ bread = recvfrom( sss->sock, pktbuf, N2N_SN_PKTBUF_SIZE, 0/*flags*/,
+ (struct sockaddr *)&sender_sock, (socklen_t*)&i);
+
+ if ( bread < 0 ) /* For UDP bread of zero just means no data (unlike TCP). */
+ {
+ /* The fd is no good now. Maybe we lost our interface. */
+ traceEvent( TRACE_ERROR, "recvfrom() failed %d errno %d (%s)", bread, errno, strerror(errno) );
+ keep_running=0;
+ break;
+ }
+
+ /* We have a datagram to process */
+ if ( bread > 0 )
+ {
+ /* And the datagram has data (not just a header) */
+ process_udp( sss, &sender_sock, pktbuf, bread, now );
+ }
+ }
+
+ if (FD_ISSET(sss->mgmt_sock, &socket_mask))
+ {
+ struct sockaddr_in sender_sock;
+ size_t i;
+
+ i = sizeof(sender_sock);
+ bread = recvfrom( sss->mgmt_sock, pktbuf, N2N_SN_PKTBUF_SIZE, 0/*flags*/,
+ (struct sockaddr *)&sender_sock, (socklen_t*)&i);
+
+ if ( bread <= 0 )
+ {
+ traceEvent( TRACE_ERROR, "recvfrom() failed %d errno %d (%s)", bread, errno, strerror(errno) );
+ keep_running=0;
+ break;
+ }
+
+ /* We have a datagram to process */
+ process_mgmt( sss, &sender_sock, pktbuf, bread, now );
+ }
+ }
+ else
+ {
+ traceEvent( TRACE_DEBUG, "timeout" );
+ }
+
+ purge_expired_registrations( &(sss->edges) );
+
+ } /* while */
+
+ deinit_sn( sss );
+
+ return 0;
+}
+
diff --git a/supernode.1 b/supernode.1
new file mode 100644
index 0000000..26b1f70
--- /dev/null
+++ b/supernode.1
@@ -0,0 +1,43 @@
+.TH supernode 1 "Jan 3, 2009" "revision 3679" "USER COMMANDS"
+.SH NAME
+supernode \- n2n supernode daemon
+.SH SYNOPSIS
+.B supernode \-l [\-v]
+.SH DESCRIPTION
+N2N is a peer-to-peer VPN system. Supernode is a node introduction registry,
+broadcast conduit and packet relay node for the n2n system. On startup supernode
+begins listening on the specified UDP port for node registrations, and other
+packets to route. The supernode can service any number of communities and routes
+packets only between members of the same community. The supernode does not hold
+the community encryption key and so cannot snoop or inject packets into the
+community.
+.PP
+Supernode can service a number of n2n communities concurrently. Traffic does not
+cross between communities.
+.PP
+All logging goes to stdout.
+.SH OPTIONS
+.TP
+\-l
+listen on the given UDP port
+.TP
+\-v
+use verbose logging
+.TP
+\-f
+disable daemon mode (UNIX) and run in foreground.
+.SH EXAMPLES
+.TP
+.B supernode -l 7654 -v
+Start supernode listening on UDP port 7654 with verbose output.
+.PP
+.SH RESTART
+When suprenode restarts it loses all registration information from associated
+edge nodes. It can take up to five minutes for the edge nodes to re-register and
+normal traffic flow to resume.
+.SH EXIT STATUS
+supernode is a daemon and any exit is an error
+.SH AUTHOR
+Luca Deri ( deri (at) ntop.org ), Richard Andrews ( andrews (at) ntop.org ), Don Bindner
+.SH SEE ALSO
+ifconfig(8) edge(8)
diff --git a/test.c b/test.c
new file mode 100644
index 0000000..97ec91b
--- /dev/null
+++ b/test.c
@@ -0,0 +1,24 @@
+#include "n2n.h"
+#include "n2n_keyfile.h"
+#include
+#include
+#include
+
+int main(int arc, const char * argv[] )
+{
+ int e;
+ n2n_cipherspec_t specs[N2N_MAX_NUM_CIPHERSPECS];
+
+ e = n2n_read_keyfile( specs, N2N_MAX_NUM_CIPHERSPECS, "keyctrl.conf" );
+
+ if ( e < 0 )
+ {
+ perror( "Failed to read keyfile" );
+ }
+ else
+ {
+ fprintf( stderr, "Stored %d keys.\n", e );
+ }
+
+ return 0;
+}
diff --git a/transform_aes.c b/transform_aes.c
new file mode 100644
index 0000000..a8c4969
--- /dev/null
+++ b/transform_aes.c
@@ -0,0 +1,597 @@
+/* (c) 2009 Richard Andrews */
+/* Contributions from:
+ * - Jozef Kralik
+ */
+
+#include "n2n.h"
+#include "n2n_transforms.h"
+
+#if defined(N2N_HAVE_AES)
+
+
+#include "openssl/aes.h"
+#ifndef _MSC_VER
+/* Not included in Visual Studio 2008 */
+#include /* index() */
+#endif
+
+#define N2N_AES_NUM_SA 32 /* space for SAa */
+
+#define N2N_AES_TRANSFORM_VERSION 1 /* version of the transform encoding */
+#define N2N_AES_IVEC_SIZE 32 /* Enough space for biggest AES ivec */
+
+typedef unsigned char n2n_aes_ivec_t[N2N_AES_IVEC_SIZE];
+
+struct sa_aes
+{
+ n2n_cipherspec_t spec; /* cipher spec parameters */
+ n2n_sa_t sa_id; /* security association index */
+ AES_KEY enc_key; /* tx key */
+ n2n_aes_ivec_t enc_ivec; /* tx CBC state */
+ AES_KEY dec_key; /* tx key */
+ n2n_aes_ivec_t dec_ivec; /* tx CBC state */
+};
+
+typedef struct sa_aes sa_aes_t;
+
+
+/** Aes transform state data.
+ *
+ * With a key-schedule in place this will be populated with a number of
+ * SAs. Each SA has a lifetime and some opque data. The opaque data for aes
+ * consists of the SA number and key material.
+ *
+ */
+struct transop_aes
+{
+ ssize_t tx_sa;
+ size_t num_sa;
+ sa_aes_t sa[N2N_AES_NUM_SA];
+};
+
+typedef struct transop_aes transop_aes_t;
+
+static int transop_deinit_aes( n2n_trans_op_t * arg )
+{
+ transop_aes_t * priv = (transop_aes_t *)arg->priv;
+ size_t i;
+
+ if ( priv )
+ {
+ /* Memory was previously allocated */
+ for (i=0; isa[i]);
+
+ sa->sa_id=0;
+ }
+
+ priv->num_sa=0;
+ priv->tx_sa=-1;
+
+ free(priv);
+ }
+
+ arg->priv=NULL; /* return to fully uninitialised state */
+
+ return 0;
+}
+
+static size_t aes_choose_tx_sa( transop_aes_t * priv )
+{
+ return priv->tx_sa; /* set in tick */
+}
+
+#define TRANSOP_AES_VER_SIZE 1 /* Support minor variants in encoding in one module. */
+#define TRANSOP_AES_NONCE_SIZE 4
+#define TRANSOP_AES_SA_SIZE 4
+
+
+#define AES256_KEY_BYTES (256/8)
+#define AES192_KEY_BYTES (192/8)
+#define AES128_KEY_BYTES (128/8)
+
+/* Return the best acceptable AES key size (in bytes) given an input keysize.
+ *
+ * The value returned will be one of AES128_KEY_BYTES, AES192_KEY_BYTES or
+ * AES256_KEY_BYTES.
+ */
+static size_t aes_best_keysize(size_t numBytes)
+{
+ if (numBytes >= AES256_KEY_BYTES )
+ {
+ return AES256_KEY_BYTES;
+ }
+ else if (numBytes >= AES192_KEY_BYTES)
+ {
+ return AES192_KEY_BYTES;
+ }
+ else
+ {
+ return AES128_KEY_BYTES;
+ }
+}
+
+/** The aes packet format consists of:
+ *
+ * - a 8-bit aes encoding version in clear text
+ * - a 32-bit SA number in clear text
+ * - ciphertext encrypted from a 32-bit nonce followed by the payload.
+ *
+ * [V|SSSS|nnnnDDDDDDDDDDDDDDDDDDDDD]
+ * |<------ encrypted ------>|
+ */
+static int transop_encode_aes( n2n_trans_op_t * arg,
+ uint8_t * outbuf,
+ size_t out_len,
+ const uint8_t * inbuf,
+ size_t in_len )
+{
+ int len2=-1;
+ transop_aes_t * priv = (transop_aes_t *)arg->priv;
+ uint8_t assembly[N2N_PKT_BUF_SIZE];
+ uint32_t * pnonce;
+
+ if ( (in_len + TRANSOP_AES_NONCE_SIZE) <= N2N_PKT_BUF_SIZE )
+ {
+ if ( (in_len + TRANSOP_AES_NONCE_SIZE + TRANSOP_AES_SA_SIZE + TRANSOP_AES_VER_SIZE) <= out_len )
+ {
+ int len=-1;
+ size_t idx=0;
+ sa_aes_t * sa;
+ size_t tx_sa_num = 0;
+
+ /* The transmit sa is periodically updated */
+ tx_sa_num = aes_choose_tx_sa( priv );
+
+ sa = &(priv->sa[tx_sa_num]); /* Proper Tx SA index */
+
+ traceEvent( TRACE_DEBUG, "encode_aes %lu with SA %lu.", in_len, sa->sa_id );
+
+ /* Encode the aes format version. */
+ encode_uint8( outbuf, &idx, N2N_AES_TRANSFORM_VERSION );
+
+ /* Encode the security association (SA) number */
+ encode_uint32( outbuf, &idx, sa->sa_id );
+
+ /* Encrypt the assembly contents and write the ciphertext after the SA. */
+ len = in_len + TRANSOP_AES_NONCE_SIZE;
+
+ /* The assembly buffer is a source for encrypting data. The nonce is
+ * written in first followed by the packet payload. The whole
+ * contents of assembly are encrypted. */
+ pnonce = (uint32_t *)assembly;
+ *pnonce = rand();
+ memcpy( assembly + TRANSOP_AES_NONCE_SIZE, inbuf, in_len );
+
+ /* Need at least one encrypted byte at the end for the padding. */
+ len2 = ( (len / AES_BLOCK_SIZE) + 1) * AES_BLOCK_SIZE; /* Round up to next whole AES adding at least one byte. */
+ assembly[ len2-1 ]=(len2-len);
+ traceEvent( TRACE_DEBUG, "padding = %u", assembly[ len2-1 ] );
+
+ memset( &(sa->enc_ivec), 0, sizeof(N2N_AES_IVEC_SIZE) );
+ AES_cbc_encrypt( assembly, /* source */
+ outbuf + TRANSOP_AES_VER_SIZE + TRANSOP_AES_SA_SIZE, /* dest */
+ len2, /* enc size */
+ &(sa->enc_key), sa->enc_ivec, 1 /* encrypt */ );
+
+ len2 += TRANSOP_AES_VER_SIZE + TRANSOP_AES_SA_SIZE; /* size of data carried in UDP. */
+ }
+ else
+ {
+ traceEvent( TRACE_ERROR, "encode_aes outbuf too small." );
+ }
+ }
+ else
+ {
+ traceEvent( TRACE_ERROR, "encode_aes inbuf too big to encrypt." );
+ }
+
+ return len2;
+}
+
+
+/* Search through the array of SAs to find the one with the required ID.
+ *
+ * @return array index where found or -1 if not found
+ */
+static ssize_t aes_find_sa( const transop_aes_t * priv, const n2n_sa_t req_id )
+{
+ size_t i;
+
+ for (i=0; i < priv->num_sa; ++i)
+ {
+ const sa_aes_t * sa=NULL;
+
+ sa = &(priv->sa[i]);
+ if (req_id == sa->sa_id)
+ {
+ return i;
+ }
+ }
+
+ return -1;
+}
+
+
+/** The aes packet format consists of:
+ *
+ * - a 8-bit aes encoding version in clear text
+ * - a 32-bit SA number in clear text
+ * - ciphertext encrypted from a 32-bit nonce followed by the payload.
+ *
+ * [V|SSSS|nnnnDDDDDDDDDDDDDDDDDDDDD]
+ * |<------ encrypted ------>|
+ */
+static int transop_decode_aes( n2n_trans_op_t * arg,
+ uint8_t * outbuf,
+ size_t out_len,
+ const uint8_t * inbuf,
+ size_t in_len )
+{
+ int len=0;
+ transop_aes_t * priv = (transop_aes_t *)arg->priv;
+ uint8_t assembly[N2N_PKT_BUF_SIZE];
+
+ if ( ( (in_len - (TRANSOP_AES_VER_SIZE + TRANSOP_AES_SA_SIZE)) <= N2N_PKT_BUF_SIZE ) /* Cipher text fits in assembly */
+ && (in_len >= (TRANSOP_AES_VER_SIZE + TRANSOP_AES_SA_SIZE + TRANSOP_AES_NONCE_SIZE) ) /* Has at least version, SA and nonce */
+ )
+ {
+ n2n_sa_t sa_rx;
+ ssize_t sa_idx=-1;
+ size_t rem=in_len;
+ size_t idx=0;
+ uint8_t aes_enc_ver=0;
+
+ /* Get the encoding version to make sure it is supported */
+ decode_uint8( &aes_enc_ver, inbuf, &rem, &idx );
+
+ if ( N2N_AES_TRANSFORM_VERSION == aes_enc_ver )
+ {
+ /* Get the SA number and make sure we are decrypting with the right one. */
+ decode_uint32( &sa_rx, inbuf, &rem, &idx );
+
+ sa_idx = aes_find_sa(priv, sa_rx);
+ if ( sa_idx >= 0 )
+ {
+ sa_aes_t * sa = &(priv->sa[sa_idx]);
+
+ traceEvent( TRACE_DEBUG, "decode_aes %lu with SA %lu.", in_len, sa_rx, sa->sa_id );
+
+ len = (in_len - (TRANSOP_AES_VER_SIZE + TRANSOP_AES_SA_SIZE));
+
+ if ( 0 == (len % AES_BLOCK_SIZE ) )
+ {
+ uint8_t padding;
+
+ memset( &(sa->dec_ivec), 0, sizeof(N2N_AES_IVEC_SIZE) );
+ AES_cbc_encrypt( (inbuf + TRANSOP_AES_VER_SIZE + TRANSOP_AES_SA_SIZE),
+ assembly, /* destination */
+ len,
+ &(sa->dec_key),
+ sa->dec_ivec, 0 /* decrypt */ );
+
+ /* last byte is how much was padding: max value should be
+ * AES_BLOCKSIZE-1 */
+ padding = assembly[ len-1 ] & 0xff;
+
+ if ( len >= (padding + TRANSOP_AES_NONCE_SIZE))
+ {
+ /* strictly speaking for this to be an ethernet packet
+ * it is going to need to be even bigger; but this is
+ * enough to prevent segfaults. */
+ traceEvent( TRACE_DEBUG, "padding = %u", padding );
+ len -= padding;
+
+ len -= TRANSOP_AES_NONCE_SIZE; /* size of ethernet packet */
+
+ /* Step over 4-byte random nonce value */
+ memcpy( outbuf,
+ assembly + TRANSOP_AES_NONCE_SIZE,
+ len );
+ }
+ else
+ {
+ traceEvent( TRACE_WARNING, "UDP payload decryption failed." );
+ }
+ }
+ else
+ {
+ traceEvent( TRACE_WARNING, "Encrypted length %d is not a multiple of AES_BLOCK_SIZE (%d)", len, AES_BLOCK_SIZE );
+ len = 0;
+ }
+
+ }
+ else
+ {
+ /* Wrong security association; drop the packet as it is undecodable. */
+ traceEvent( TRACE_ERROR, "decode_aes SA number %lu not found.", sa_rx );
+
+ /* REVISIT: should be able to load a new SA at this point to complete the decoding. */
+ }
+ }
+ else
+ {
+ /* Wrong security association; drop the packet as it is undecodable. */
+ traceEvent( TRACE_ERROR, "decode_aes unsupported aes version %u.", aes_enc_ver );
+
+ /* REVISIT: should be able to load a new SA at this point to complete the decoding. */
+ }
+ }
+ else
+ {
+ traceEvent( TRACE_ERROR, "decode_aes inbuf wrong size (%ul) to decrypt.", in_len );
+ }
+
+ return len;
+}
+
+static int transop_addspec_aes( n2n_trans_op_t * arg, const n2n_cipherspec_t * cspec )
+{
+ int retval = 1;
+ ssize_t pstat=-1;
+ transop_aes_t * priv = (transop_aes_t *)arg->priv;
+ uint8_t keybuf[N2N_MAX_KEYSIZE];
+
+ if ( priv->num_sa < N2N_AES_NUM_SA )
+ {
+ const char * op = (const char *)cspec->opaque;
+ const char * sep = index( op, '_' );
+
+ if ( sep )
+ {
+ char tmp[256];
+ size_t s;
+
+ s = sep - op;
+ memcpy( tmp, cspec->opaque, s );
+ tmp[s]=0;
+
+ s = strlen(sep+1); /* sep is the _ which might be immediately followed by NULL */
+
+ priv->sa[priv->num_sa].spec = *cspec;
+ priv->sa[priv->num_sa].sa_id = strtoul(tmp, NULL, 10);
+
+ memset( keybuf, 0, N2N_MAX_KEYSIZE );
+ pstat = n2n_parse_hex( keybuf, N2N_MAX_KEYSIZE, sep+1, s );
+ if ( pstat > 0 )
+ {
+ /* pstat is number of bytes read into keybuf. */
+ sa_aes_t * sa = &(priv->sa[priv->num_sa]);
+ size_t aes_keysize_bytes;
+ size_t aes_keysize_bits;
+
+ /* Clear out any old possibly longer key matter. */
+ memset( &(sa->enc_key), 0, sizeof(AES_KEY) );
+ memset( &(sa->dec_key), 0, sizeof(AES_KEY) );
+
+ memset( &(sa->enc_ivec), 0, sizeof(N2N_AES_IVEC_SIZE) );
+ memset( &(sa->dec_ivec), 0, sizeof(N2N_AES_IVEC_SIZE) );
+
+ aes_keysize_bytes = aes_best_keysize(pstat);
+ aes_keysize_bits = 8 * aes_keysize_bytes;
+
+ /* Use N2N_MAX_KEYSIZE because the AES key needs to be of fixed
+ * size. If fewer bits specified then the rest will be
+ * zeroes. AES acceptable key sizes are 128, 192 and 256
+ * bits. */
+ AES_set_encrypt_key( keybuf, aes_keysize_bits, &(sa->enc_key));
+ AES_set_decrypt_key( keybuf, aes_keysize_bits, &(sa->dec_key));
+ /* Leave ivecs set to all zeroes */
+
+ traceEvent( TRACE_DEBUG, "transop_addspec_aes sa_id=%u, %u bits data=%s.\n",
+ priv->sa[priv->num_sa].sa_id, aes_keysize_bits, sep+1);
+
+ ++(priv->num_sa);
+ retval = 0;
+ }
+ }
+ else
+ {
+ traceEvent( TRACE_ERROR, "transop_addspec_aes : bad key data - missing '_'.\n");
+ }
+ }
+ else
+ {
+ traceEvent( TRACE_ERROR, "transop_addspec_aes : full.\n");
+ }
+
+ return retval;
+}
+
+
+static n2n_tostat_t transop_tick_aes( n2n_trans_op_t * arg, time_t now )
+{
+ transop_aes_t * priv = (transop_aes_t *)arg->priv;
+ size_t i;
+ int found=0;
+ n2n_tostat_t r;
+
+ memset( &r, 0, sizeof(r) );
+
+ traceEvent( TRACE_DEBUG, "transop_aes tick num_sa=%u now=%lu", priv->num_sa, now );
+
+ for ( i=0; i < priv->num_sa; ++i )
+ {
+ if ( 0 == validCipherSpec( &(priv->sa[i].spec), now ) )
+ {
+ time_t remaining = priv->sa[i].spec.valid_until - now;
+
+ traceEvent( TRACE_INFO, "transop_aes choosing tx_sa=%u (valid for %lu sec)", priv->sa[i].sa_id, remaining );
+ priv->tx_sa=i;
+ found=1;
+ break;
+ }
+ else
+ {
+ traceEvent( TRACE_DEBUG, "transop_aes tick rejecting sa=%u %lu -> %lu",
+ priv->sa[i].sa_id, priv->sa[i].spec.valid_from, priv->sa[i].spec.valid_until );
+ }
+ }
+
+ if ( 0==found)
+ {
+ traceEvent( TRACE_INFO, "transop_aes no keys are currently valid. Keeping tx_sa=%u", priv->tx_sa );
+ }
+ else
+ {
+ r.can_tx = 1;
+ r.tx_spec.t = N2N_TRANSFORM_ID_AESCBC;
+ r.tx_spec = priv->sa[priv->tx_sa].spec;
+ }
+
+ return r;
+}
+
+
+int transop_aes_init( n2n_trans_op_t * ttt )
+{
+ int retval = 1;
+ transop_aes_t * priv = NULL;
+
+ if ( ttt->priv )
+ {
+ transop_deinit_aes( ttt );
+ }
+
+ memset( ttt, 0, sizeof( n2n_trans_op_t ) );
+
+ priv = (transop_aes_t *) malloc( sizeof(transop_aes_t) );
+
+ if ( NULL != priv )
+ {
+ size_t i;
+ sa_aes_t * sa=NULL;
+
+ /* install the private structure. */
+ ttt->priv = priv;
+ priv->num_sa=0;
+ priv->tx_sa=0; /* We will use this sa index for encoding. */
+
+ ttt->transform_id = N2N_TRANSFORM_ID_AESCBC;
+ ttt->addspec = transop_addspec_aes;
+ ttt->tick = transop_tick_aes; /* chooses a new tx_sa */
+ ttt->deinit = transop_deinit_aes;
+ ttt->fwd = transop_encode_aes;
+ ttt->rev = transop_decode_aes;
+
+ for(i=0; isa[i]);
+ sa->sa_id=0;
+ memset( &(sa->spec), 0, sizeof(n2n_cipherspec_t) );
+ memset( &(sa->enc_key), 0, sizeof(AES_KEY) );
+ memset( &(sa->enc_ivec), 0, sizeof(N2N_AES_IVEC_SIZE) );
+ memset( &(sa->dec_key), 0, sizeof(AES_KEY) );
+ memset( &(sa->dec_ivec), 0, sizeof(N2N_AES_IVEC_SIZE) );
+ }
+
+ retval = 0;
+ }
+ else
+ {
+ memset( ttt, 0, sizeof(n2n_trans_op_t) );
+ traceEvent( TRACE_ERROR, "Failed to allocate priv for aes" );
+ }
+
+ return retval;
+}
+
+#else /* #if defined(N2N_HAVE_AES) */
+
+struct transop_aes
+{
+ ssize_t tx_sa;
+};
+
+typedef struct transop_aes transop_aes_t;
+
+
+static int transop_deinit_aes( n2n_trans_op_t * arg )
+{
+ transop_aes_t * priv = (transop_aes_t *)arg->priv;
+
+ if ( priv )
+ {
+ free(priv);
+ }
+
+ arg->priv=NULL; /* return to fully uninitialised state */
+
+ return 0;
+}
+
+static int transop_encode_aes( n2n_trans_op_t * arg,
+ uint8_t * outbuf,
+ size_t out_len,
+ const uint8_t * inbuf,
+ size_t in_len )
+{
+ return -1;
+}
+
+static int transop_decode_aes( n2n_trans_op_t * arg,
+ uint8_t * outbuf,
+ size_t out_len,
+ const uint8_t * inbuf,
+ size_t in_len )
+{
+ return -1;
+}
+
+static int transop_addspec_aes( n2n_trans_op_t * arg, const n2n_cipherspec_t * cspec )
+{
+ traceEvent( TRACE_DEBUG, "transop_addspec_aes AES not built into edge.\n");
+
+ return -1;
+}
+
+static n2n_tostat_t transop_tick_aes( n2n_trans_op_t * arg, time_t now )
+{
+ n2n_tostat_t r;
+
+ memset( &r, 0, sizeof(r) );
+
+ return r;
+}
+
+int transop_aes_init( n2n_trans_op_t * ttt )
+{
+ int retval = 1;
+ transop_aes_t * priv = NULL;
+
+ if ( ttt->priv )
+ {
+ transop_deinit_aes( ttt );
+ }
+
+ memset( ttt, 0, sizeof( n2n_trans_op_t ) );
+
+ priv = (transop_aes_t *) malloc( sizeof(transop_aes_t) );
+
+ if ( NULL != priv )
+ {
+ /* install the private structure. */
+ ttt->priv = priv;
+ priv->tx_sa=0; /* We will use this sa index for encoding. */
+
+ ttt->transform_id = N2N_TRANSFORM_ID_AESCBC;
+ ttt->addspec = transop_addspec_aes;
+ ttt->tick = transop_tick_aes; /* chooses a new tx_sa */
+ ttt->deinit = transop_deinit_aes;
+ ttt->fwd = transop_encode_aes;
+ ttt->rev = transop_decode_aes;
+
+ retval = 0;
+ }
+ else
+ {
+ memset( ttt, 0, sizeof(n2n_trans_op_t) );
+ traceEvent( TRACE_ERROR, "Failed to allocate priv for aes" );
+ }
+
+ return retval;
+}
+
+#endif /* #if defined(N2N_HAVE_AES) */
+
diff --git a/transform_null.c b/transform_null.c
new file mode 100644
index 0000000..b486989
--- /dev/null
+++ b/transform_null.c
@@ -0,0 +1,84 @@
+/* (c) 2009 Richard Andrews */
+
+#include "n2n.h"
+#include "n2n_transforms.h"
+
+static int transop_deinit_null( n2n_trans_op_t * arg )
+{
+ /* nothing to deallocate, nothing to release. */
+ return 0;
+}
+
+static int transop_encode_null( n2n_trans_op_t * arg,
+ uint8_t * outbuf,
+ size_t out_len,
+ const uint8_t * inbuf,
+ size_t in_len )
+{
+ int retval = -1;
+
+ traceEvent( TRACE_DEBUG, "encode_null %lu", in_len );
+ if ( out_len >= in_len )
+ {
+ memcpy( outbuf, inbuf, in_len );
+ retval = in_len;
+ }
+ else
+ {
+ traceEvent( TRACE_DEBUG, "encode_null %lu too big for packet buffer", in_len );
+ }
+
+ return retval;
+}
+
+static int transop_decode_null( n2n_trans_op_t * arg,
+ uint8_t * outbuf,
+ size_t out_len,
+ const uint8_t * inbuf,
+ size_t in_len )
+{
+ int retval = -1;
+
+ traceEvent( TRACE_DEBUG, "decode_null %lu", in_len );
+ if ( out_len >= in_len )
+ {
+ memcpy( outbuf, inbuf, in_len );
+ retval = in_len;
+ }
+ else
+ {
+ traceEvent( TRACE_DEBUG, "decode_null %lu too big for packet buffer", in_len );
+ }
+
+ return retval;
+}
+
+static int transop_addspec_null( n2n_trans_op_t * arg, const n2n_cipherspec_t * cspec )
+{
+ return 0;
+}
+
+static n2n_tostat_t transop_tick_null( n2n_trans_op_t * arg, time_t now )
+{
+ n2n_tostat_t r;
+
+ r.can_tx=1;
+ r.tx_spec.t = N2N_TRANSFORM_ID_NULL;
+ r.tx_spec.valid_from = 0;
+ r.tx_spec.valid_until = (time_t)(-1);
+ r.tx_spec.opaque_size=0;
+
+ return r;
+}
+
+void transop_null_init( n2n_trans_op_t * ttt )
+{
+ memset(ttt, 0, sizeof(n2n_trans_op_t) );
+
+ ttt->transform_id = N2N_TRANSFORM_ID_NULL;
+ ttt->deinit = transop_deinit_null;
+ ttt->addspec = transop_addspec_null;
+ ttt->tick = transop_tick_null;
+ ttt->fwd = transop_encode_null;
+ ttt->rev = transop_decode_null;
+}
diff --git a/transform_tf.c b/transform_tf.c
new file mode 100644
index 0000000..1ae5bc5
--- /dev/null
+++ b/transform_tf.c
@@ -0,0 +1,487 @@
+/* (c) 2009 Richard Andrews */
+
+#include "n2n.h"
+#include "n2n_transforms.h"
+#include "twofish.h"
+#ifndef _MSC_VER
+/* Not included in Visual Studio 2008 */
+#include /* index() */
+#endif
+
+#define N2N_TWOFISH_NUM_SA 32 /* space for SAa */
+
+#define N2N_TWOFISH_TRANSFORM_VERSION 1 /* version of the transform encoding */
+
+struct sa_twofish
+{
+ n2n_cipherspec_t spec; /* cipher spec parameters */
+ n2n_sa_t sa_id; /* security association index */
+ TWOFISH * enc_tf; /* tx state */
+ TWOFISH * dec_tf; /* rx state */
+};
+
+typedef struct sa_twofish sa_twofish_t;
+
+
+/** Twofish transform state data.
+ *
+ * With a key-schedule in place this will be populated with a number of
+ * SAs. Each SA has a lifetime and some opque data. The opaque data for twofish
+ * consists of the SA number and key material.
+ *
+ */
+struct transop_tf
+{
+ ssize_t tx_sa;
+ size_t num_sa;
+ sa_twofish_t sa[N2N_TWOFISH_NUM_SA];
+};
+
+typedef struct transop_tf transop_tf_t;
+
+static int transop_deinit_twofish( n2n_trans_op_t * arg )
+{
+ transop_tf_t * priv = (transop_tf_t *)arg->priv;
+ size_t i;
+
+ if ( priv )
+ {
+ /* Memory was previously allocated */
+ for (i=0; isa[i]);
+
+ TwoFishDestroy(sa->enc_tf); /* deallocate TWOFISH */
+ sa->enc_tf=NULL;
+
+ TwoFishDestroy(sa->dec_tf); /* deallocate TWOFISH */
+ sa->dec_tf=NULL;
+
+ sa->sa_id=0;
+ }
+
+ priv->num_sa=0;
+ priv->tx_sa=-1;
+
+ free(priv);
+ }
+
+ arg->priv=NULL; /* return to fully uninitialised state */
+
+ return 0;
+}
+
+static size_t tf_choose_tx_sa( transop_tf_t * priv )
+{
+ return priv->tx_sa; /* set in tick */
+}
+
+#define TRANSOP_TF_VER_SIZE 1 /* Support minor variants in encoding in one module. */
+#define TRANSOP_TF_NONCE_SIZE 4
+#define TRANSOP_TF_SA_SIZE 4
+
+/** The twofish packet format consists of:
+ *
+ * - a 8-bit twofish encoding version in clear text
+ * - a 32-bit SA number in clear text
+ * - ciphertext encrypted from a 32-bit nonce followed by the payload.
+ *
+ * [V|SSSS|nnnnDDDDDDDDDDDDDDDDDDDDD]
+ * |<------ encrypted ------>|
+ */
+static int transop_encode_twofish( n2n_trans_op_t * arg,
+ uint8_t * outbuf,
+ size_t out_len,
+ const uint8_t * inbuf,
+ size_t in_len )
+{
+ int len=-1;
+ transop_tf_t * priv = (transop_tf_t *)arg->priv;
+ uint8_t assembly[N2N_PKT_BUF_SIZE];
+ uint32_t * pnonce;
+
+ if ( (in_len + TRANSOP_TF_NONCE_SIZE) <= N2N_PKT_BUF_SIZE )
+ {
+ if ( (in_len + TRANSOP_TF_NONCE_SIZE + TRANSOP_TF_SA_SIZE + TRANSOP_TF_VER_SIZE) <= out_len )
+ {
+ size_t idx=0;
+ sa_twofish_t * sa;
+ size_t tx_sa_num = 0;
+
+ /* The transmit sa is periodically updated */
+ tx_sa_num = tf_choose_tx_sa( priv );
+
+ sa = &(priv->sa[tx_sa_num]); /* Proper Tx SA index */
+
+ traceEvent( TRACE_DEBUG, "encode_twofish %lu with SA %lu.", in_len, sa->sa_id );
+
+ /* Encode the twofish format version. */
+ encode_uint8( outbuf, &idx, N2N_TWOFISH_TRANSFORM_VERSION );
+
+ /* Encode the security association (SA) number */
+ encode_uint32( outbuf, &idx, sa->sa_id );
+
+ /* The assembly buffer is a source for encrypting data. The nonce is
+ * written in first followed by the packet payload. The whole
+ * contents of assembly are encrypted. */
+ pnonce = (uint32_t *)assembly;
+ *pnonce = rand();
+ memcpy( assembly + TRANSOP_TF_NONCE_SIZE, inbuf, in_len );
+
+ /* Encrypt the assembly contents and write the ciphertext after the SA. */
+ len = TwoFishEncryptRaw( assembly, /* source */
+ outbuf + TRANSOP_TF_VER_SIZE + TRANSOP_TF_SA_SIZE,
+ in_len + TRANSOP_TF_NONCE_SIZE, /* enc size */
+ sa->enc_tf);
+ if ( len > 0 )
+ {
+ len += TRANSOP_TF_VER_SIZE + TRANSOP_TF_SA_SIZE; /* size of data carried in UDP. */
+ }
+ else
+ {
+ traceEvent( TRACE_ERROR, "encode_twofish encryption failed." );
+ }
+
+ }
+ else
+ {
+ traceEvent( TRACE_ERROR, "encode_twofish outbuf too small." );
+ }
+ }
+ else
+ {
+ traceEvent( TRACE_ERROR, "encode_twofish inbuf too big to encrypt." );
+ }
+
+ return len;
+}
+
+
+/* Search through the array of SAs to find the one with the required ID.
+ *
+ * @return array index where found or -1 if not found
+ */
+static ssize_t twofish_find_sa( const transop_tf_t * priv, const n2n_sa_t req_id )
+{
+ size_t i;
+
+ for (i=0; i < priv->num_sa; ++i)
+ {
+ const sa_twofish_t * sa=NULL;
+
+ sa = &(priv->sa[i]);
+ if (req_id == sa->sa_id)
+ {
+ return i;
+ }
+ }
+
+ return -1;
+}
+
+
+/** The twofish packet format consists of:
+ *
+ * - a 8-bit twofish encoding version in clear text
+ * - a 32-bit SA number in clear text
+ * - ciphertext encrypted from a 32-bit nonce followed by the payload.
+ *
+ * [V|SSSS|nnnnDDDDDDDDDDDDDDDDDDDDD]
+ * |<------ encrypted ------>|
+ */
+static int transop_decode_twofish( n2n_trans_op_t * arg,
+ uint8_t * outbuf,
+ size_t out_len,
+ const uint8_t * inbuf,
+ size_t in_len )
+{
+ int len=0;
+ transop_tf_t * priv = (transop_tf_t *)arg->priv;
+ uint8_t assembly[N2N_PKT_BUF_SIZE];
+
+ if ( ( (in_len - (TRANSOP_TF_VER_SIZE + TRANSOP_TF_SA_SIZE)) <= N2N_PKT_BUF_SIZE ) /* Cipher text fits in assembly */
+ && (in_len >= (TRANSOP_TF_VER_SIZE + TRANSOP_TF_SA_SIZE + TRANSOP_TF_NONCE_SIZE) ) /* Has at least version, SA and nonce */
+ )
+ {
+ n2n_sa_t sa_rx;
+ ssize_t sa_idx=-1;
+ size_t rem=in_len;
+ size_t idx=0;
+ uint8_t tf_enc_ver=0;
+
+ /* Get the encoding version to make sure it is supported */
+ decode_uint8( &tf_enc_ver, inbuf, &rem, &idx );
+
+ if ( N2N_TWOFISH_TRANSFORM_VERSION == tf_enc_ver )
+ {
+ /* Get the SA number and make sure we are decrypting with the right one. */
+ decode_uint32( &sa_rx, inbuf, &rem, &idx );
+
+ sa_idx = twofish_find_sa(priv, sa_rx);
+ if ( sa_idx >= 0 )
+ {
+ sa_twofish_t * sa = &(priv->sa[sa_idx]);
+
+ traceEvent( TRACE_DEBUG, "decode_twofish %lu with SA %lu.", in_len, sa_rx, sa->sa_id );
+
+ len = TwoFishDecryptRaw( (void *)(inbuf + TRANSOP_TF_VER_SIZE + TRANSOP_TF_SA_SIZE),
+ assembly, /* destination */
+ (in_len - (TRANSOP_TF_VER_SIZE + TRANSOP_TF_SA_SIZE)),
+ sa->dec_tf);
+
+ if ( len > 0 )
+ {
+ /* Step over 4-byte random nonce value */
+ len -= TRANSOP_TF_NONCE_SIZE; /* size of ethernet packet */
+
+ memcpy( outbuf,
+ assembly + TRANSOP_TF_NONCE_SIZE,
+ len );
+ }
+ else
+ {
+ traceEvent( TRACE_ERROR, "decode_twofish decryption failed." );
+ }
+
+ }
+ else
+ {
+ /* Wrong security association; drop the packet as it is undecodable. */
+ traceEvent( TRACE_ERROR, "decode_twofish SA number %lu not found.", sa_rx );
+
+ /* REVISIT: should be able to load a new SA at this point to complete the decoding. */
+ }
+ }
+ else
+ {
+ /* Wrong security association; drop the packet as it is undecodable. */
+ traceEvent( TRACE_ERROR, "decode_twofish unsupported twofish version %u.", tf_enc_ver );
+
+ /* REVISIT: should be able to load a new SA at this point to complete the decoding. */
+ }
+ }
+ else
+ {
+ traceEvent( TRACE_ERROR, "decode_twofish inbuf wrong size (%ul) to decrypt.", in_len );
+ }
+
+ return len;
+}
+
+static int transop_addspec_twofish( n2n_trans_op_t * arg, const n2n_cipherspec_t * cspec )
+{
+ int retval = 1;
+ ssize_t pstat=-1;
+ transop_tf_t * priv = (transop_tf_t *)arg->priv;
+ uint8_t keybuf[N2N_MAX_KEYSIZE];
+
+ if ( priv->num_sa < N2N_TWOFISH_NUM_SA )
+ {
+ const char * op = (const char *)cspec->opaque;
+ const char * sep = index( op, '_' );
+
+ if ( sep )
+ {
+ char tmp[256];
+ size_t s;
+
+ s = sep - op;
+ memcpy( tmp, cspec->opaque, s );
+ tmp[s]=0;
+
+ s = strlen(sep+1); /* sep is the _ which might be immediately followed by NULL */
+
+ priv->sa[priv->num_sa].spec = *cspec;
+ priv->sa[priv->num_sa].sa_id = strtoul(tmp, NULL, 10);
+
+ pstat = n2n_parse_hex( keybuf, N2N_MAX_KEYSIZE, sep+1, s );
+ if ( pstat > 0 )
+ {
+ priv->sa[priv->num_sa].enc_tf = TwoFishInit( keybuf, pstat);
+ priv->sa[priv->num_sa].dec_tf = TwoFishInit( keybuf, pstat);
+
+ traceEvent( TRACE_DEBUG, "transop_addspec_twofish sa_id=%u data=%s.\n",
+ priv->sa[priv->num_sa].sa_id, sep+1);
+
+ ++(priv->num_sa);
+ retval = 0;
+ }
+ }
+ else
+ {
+ traceEvent( TRACE_ERROR, "transop_addspec_twofish : bad key data - missing '_'.\n");
+ }
+ }
+ else
+ {
+ traceEvent( TRACE_ERROR, "transop_addspec_twofish : full.\n");
+ }
+
+ return retval;
+}
+
+
+static n2n_tostat_t transop_tick_twofish( n2n_trans_op_t * arg, time_t now )
+{
+ transop_tf_t * priv = (transop_tf_t *)arg->priv;
+ size_t i;
+ int found=0;
+ n2n_tostat_t r;
+
+ memset( &r, 0, sizeof(r) );
+
+ traceEvent( TRACE_DEBUG, "transop_tf tick num_sa=%u", priv->num_sa );
+
+ for ( i=0; i < priv->num_sa; ++i )
+ {
+ if ( 0 == validCipherSpec( &(priv->sa[i].spec), now ) )
+ {
+ time_t remaining = priv->sa[i].spec.valid_until - now;
+
+ traceEvent( TRACE_INFO, "transop_tf choosing tx_sa=%u (valid for %lu sec)", priv->sa[i].sa_id, remaining );
+ priv->tx_sa=i;
+ found=1;
+ break;
+ }
+ else
+ {
+ traceEvent( TRACE_DEBUG, "transop_tf tick rejecting sa=%u %lu -> %lu",
+ priv->sa[i].sa_id, priv->sa[i].spec.valid_from, priv->sa[i].spec.valid_until );
+ }
+ }
+
+ if ( 0==found)
+ {
+ traceEvent( TRACE_INFO, "transop_tf no keys are currently valid. Keeping tx_sa=%u", priv->tx_sa );
+ }
+ else
+ {
+ r.can_tx = 1;
+ r.tx_spec.t = N2N_TRANSFORM_ID_TWOFISH;
+ r.tx_spec = priv->sa[priv->tx_sa].spec;
+ }
+
+ return r;
+}
+
+
+int transop_twofish_setup( n2n_trans_op_t * ttt,
+ n2n_sa_t sa_num,
+ uint8_t * encrypt_pwd,
+ uint32_t encrypt_pwd_len )
+{
+ int retval = 1;
+ transop_tf_t * priv = NULL;
+
+ if ( ttt->priv )
+ {
+ transop_deinit_twofish( ttt );
+ }
+
+ memset( ttt, 0, sizeof( n2n_trans_op_t ) );
+
+ priv = (transop_tf_t *) malloc( sizeof(transop_tf_t) );
+
+ if ( NULL != priv )
+ {
+ size_t i;
+ sa_twofish_t * sa=NULL;
+
+ /* install the private structure. */
+ ttt->priv = priv;
+
+ for(i=0; isa[i]);
+ sa->sa_id=0;
+ memset( &(sa->spec), 0, sizeof(n2n_cipherspec_t) );
+ sa->enc_tf=NULL;
+ sa->dec_tf=NULL;
+ }
+
+ priv->num_sa=1; /* There is one SA in the array. */
+ priv->tx_sa=0;
+ sa = &(priv->sa[priv->tx_sa]);
+ sa->sa_id=sa_num;
+ sa->spec.valid_until = 0x7fffffff;
+
+ /* This is a preshared key setup. Both Tx and Rx are using the same security association. */
+
+ sa->enc_tf = TwoFishInit(encrypt_pwd, encrypt_pwd_len);
+ sa->dec_tf = TwoFishInit(encrypt_pwd, encrypt_pwd_len);
+
+ if ( (sa->enc_tf) && (sa->dec_tf) )
+ {
+ ttt->transform_id = N2N_TRANSFORM_ID_TWOFISH;
+ ttt->deinit = transop_deinit_twofish;
+ ttt->addspec = transop_addspec_twofish;
+ ttt->tick = transop_tick_twofish; /* chooses a new tx_sa */
+ ttt->fwd = transop_encode_twofish;
+ ttt->rev = transop_decode_twofish;
+
+ retval = 0;
+ }
+ else
+ {
+ traceEvent( TRACE_ERROR, "TwoFishInit failed" );
+ }
+ }
+ else
+ {
+ memset( ttt, 0, sizeof(n2n_trans_op_t) );
+ traceEvent( TRACE_ERROR, "Failed to allocate priv for twofish" );
+ }
+
+ return retval;
+}
+
+int transop_twofish_init( n2n_trans_op_t * ttt )
+{
+ int retval = 1;
+ transop_tf_t * priv = NULL;
+
+ if ( ttt->priv )
+ {
+ transop_deinit_twofish( ttt );
+ }
+
+ memset( ttt, 0, sizeof( n2n_trans_op_t ) );
+
+ priv = (transop_tf_t *) malloc( sizeof(transop_tf_t) );
+
+ if ( NULL != priv )
+ {
+ size_t i;
+ sa_twofish_t * sa=NULL;
+
+ /* install the private structure. */
+ ttt->priv = priv;
+ priv->num_sa=0;
+ priv->tx_sa=0; /* We will use this sa index for encoding. */
+
+ ttt->transform_id = N2N_TRANSFORM_ID_TWOFISH;
+ ttt->addspec = transop_addspec_twofish;
+ ttt->tick = transop_tick_twofish; /* chooses a new tx_sa */
+ ttt->deinit = transop_deinit_twofish;
+ ttt->fwd = transop_encode_twofish;
+ ttt->rev = transop_decode_twofish;
+
+ for(i=0; isa[i]);
+ sa->sa_id=0;
+ memset( &(sa->spec), 0, sizeof(n2n_cipherspec_t) );
+ sa->enc_tf=NULL;
+ sa->dec_tf=NULL;
+ }
+
+ retval = 0;
+ }
+ else
+ {
+ memset( ttt, 0, sizeof(n2n_trans_op_t) );
+ traceEvent( TRACE_ERROR, "Failed to allocate priv for twofish" );
+ }
+
+ return retval;
+}
diff --git a/tuntap_freebsd.c b/tuntap_freebsd.c
new file mode 100644
index 0000000..7d9096a
--- /dev/null
+++ b/tuntap_freebsd.c
@@ -0,0 +1,132 @@
+/*
+ * (C) 2007-09 - Luca Deri
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not see see
+ */
+
+#include "n2n.h"
+
+#ifdef __FreeBSD__
+
+void tun_close(tuntap_dev *device);
+
+/* ********************************** */
+
+#define N2N_FREEBSD_TAPDEVICE_SIZE 32
+int tuntap_open(tuntap_dev *device /* ignored */,
+ char *dev,
+ const char *address_mode, /* static or dhcp */
+ char *device_ip,
+ char *device_mask,
+ const char * device_mac,
+ int mtu) {
+ int i;
+ char tap_device[N2N_FREEBSD_TAPDEVICE_SIZE];
+
+ for (i = 0; i < 255; i++) {
+ snprintf(tap_device, sizeof(tap_device), "/dev/tap%d", i);
+
+ device->fd = open(tap_device, O_RDWR);
+ if(device->fd > 0) {
+ traceEvent(TRACE_NORMAL, "Succesfully open %s", tap_device);
+ break;
+ }
+ }
+
+ if(device->fd < 0) {
+ traceEvent(TRACE_ERROR, "Unable to open tap device");
+ return(-1);
+ } else {
+ char buf[256];
+ FILE *fd;
+
+ device->ip_addr = inet_addr(device_ip);
+
+ if ( device_mac && device_mac[0] != '\0' )
+ {
+ /* FIXME - This is not tested. Might be wrong syntax for OS X */
+
+ /* Set the hw address before bringing the if up. */
+ snprintf(buf, sizeof(buf), "ifconfig tap%d ether %s",
+ i, device_mac);
+ system(buf);
+ }
+
+ snprintf(buf, sizeof(buf), "ifconfig tap%d %s netmask %s mtu %d up",
+ i, device_ip, device_mask, mtu);
+ system(buf);
+
+ traceEvent(TRACE_NORMAL, "Interface tap%d up and running (%s/%s)",
+ i, device_ip, device_mask);
+
+ /* Read MAC address */
+
+ snprintf(buf, sizeof(buf), "ifconfig tap%d |grep ether|cut -c 8-24", i);
+ /* traceEvent(TRACE_INFO, "%s", buf); */
+
+ fd = popen(buf, "r");
+ if(fd < 0) {
+ tun_close(device);
+ return(-1);
+ } else {
+ int a, b, c, d, e, f;
+
+ buf[0] = 0;
+ fgets(buf, sizeof(buf), fd);
+ pclose(fd);
+
+ if(buf[0] == '\0') {
+ traceEvent(TRACE_ERROR, "Unable to read tap%d interface MAC address");
+ exit(0);
+ }
+
+ traceEvent(TRACE_NORMAL, "Interface tap%d mac %s", i, buf);
+ if(sscanf(buf, "%02x:%02x:%02x:%02x:%02x:%02x", &a, &b, &c, &d, &e, &f) == 6) {
+ device->mac_addr[0] = a, device->mac_addr[1] = b;
+ device->mac_addr[2] = c, device->mac_addr[3] = d;
+ device->mac_addr[4] = e, device->mac_addr[5] = f;
+ }
+ }
+ }
+
+
+ /* read_mac(dev, device->mac_addr); */
+ return(device->fd);
+}
+
+/* ********************************** */
+
+int tuntap_read(struct tuntap_dev *tuntap, unsigned char *buf, int len) {
+ return(read(tuntap->fd, buf, len));
+}
+
+/* ********************************** */
+
+int tuntap_write(struct tuntap_dev *tuntap, unsigned char *buf, int len) {
+ return(write(tuntap->fd, buf, len));
+}
+
+/* ********************************** */
+
+void tuntap_close(struct tuntap_dev *tuntap) {
+ close(tuntap->fd);
+}
+
+/* Fill out the ip_addr value from the interface. Called to pick up dynamic
+ * address changes. */
+void tuntap_get_address(struct tuntap_dev *tuntap)
+{
+}
+
+#endif /* #ifdef __FreeBSD__ */
diff --git a/tuntap_linux.c b/tuntap_linux.c
new file mode 100644
index 0000000..66b3dd8
--- /dev/null
+++ b/tuntap_linux.c
@@ -0,0 +1,165 @@
+/*
+ * (C) 2007-09 - Luca Deri
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see
+*/
+
+#include "n2n.h"
+
+#ifdef __linux__
+
+static void read_mac(char *ifname, n2n_mac_t mac_addr) {
+ int _sock, res;
+ struct ifreq ifr;
+ macstr_t mac_addr_buf;
+
+ memset (&ifr,0,sizeof(struct ifreq));
+
+ /* Dummy socket, just to make ioctls with */
+ _sock=socket(PF_INET, SOCK_DGRAM, 0);
+ strcpy(ifr.ifr_name, ifname);
+ res = ioctl(_sock,SIOCGIFHWADDR,&ifr);
+ if (res<0) {
+ perror ("Get hw addr");
+ } else
+ memcpy(mac_addr, ifr.ifr_ifru.ifru_hwaddr.sa_data, 6);
+
+ traceEvent(TRACE_NORMAL, "Interface %s has MAC %s",
+ ifname,
+ macaddr_str(mac_addr_buf, mac_addr ));
+ close(_sock);
+}
+
+/* ********************************** */
+
+/** @brief Open and configure the TAP device for packet read/write.
+ *
+ * This routine creates the interface via the tuntap driver then uses ifconfig
+ * to configure address/mask and MTU.
+ *
+ * @param device - [inout] a device info holder object
+ * @param dev - user-defined name for the new iface,
+ * if NULL system will assign a name
+ * @param device_ip - address of iface
+ * @param device_mask - netmask for device_ip
+ * @param mtu - MTU for device_ip
+ *
+ * @return - negative value on error
+ * - non-negative file-descriptor on success
+ */
+int tuntap_open(tuntap_dev *device,
+ char *dev, /* user-definable interface name, eg. edge0 */
+ const char *address_mode, /* static or dhcp */
+ char *device_ip,
+ char *device_mask,
+ const char * device_mac,
+ int mtu) {
+ char *tuntap_device = "/dev/net/tun";
+#define N2N_LINUX_SYSTEMCMD_SIZE 128
+ char buf[N2N_LINUX_SYSTEMCMD_SIZE];
+ struct ifreq ifr;
+ int rc;
+
+ device->fd = open(tuntap_device, O_RDWR);
+ if(device->fd < 0) {
+ printf("ERROR: ioctl() [%s][%d]\n", strerror(errno), errno);
+ return -1;
+ }
+
+ memset(&ifr, 0, sizeof(ifr));
+ ifr.ifr_flags = IFF_TAP|IFF_NO_PI; /* Want a TAP device for layer 2 frames. */
+ strncpy(ifr.ifr_name, dev, IFNAMSIZ);
+ rc = ioctl(device->fd, TUNSETIFF, (void *)&ifr);
+
+ if(rc < 0) {
+ traceEvent(TRACE_ERROR, "ioctl() [%s][%d]\n", strerror(errno), rc);
+ close(device->fd);
+ return -1;
+ }
+
+ /* Store the device name for later reuse */
+ strncpy(device->dev_name, ifr.ifr_name, MIN(IFNAMSIZ, N2N_IFNAMSIZ) );
+
+ if ( device_mac && device_mac[0] != '\0' )
+ {
+ /* Set the hw address before bringing the if up. */
+ snprintf(buf, sizeof(buf), "/sbin/ifconfig %s hw ether %s",
+ ifr.ifr_name, device_mac );
+ system(buf);
+ traceEvent(TRACE_INFO, "Setting MAC: %s", buf);
+ }
+
+ if ( 0 == strncmp( "dhcp", address_mode, 5 ) )
+ {
+ snprintf(buf, sizeof(buf), "/sbin/ifconfig %s %s mtu %d up",
+ ifr.ifr_name, device_ip, mtu);
+ }
+ else
+ {
+ snprintf(buf, sizeof(buf), "/sbin/ifconfig %s %s netmask %s mtu %d up",
+ ifr.ifr_name, device_ip, device_mask, mtu);
+ }
+
+ system(buf);
+ traceEvent(TRACE_INFO, "Bringing up: %s", buf);
+
+ device->ip_addr = inet_addr(device_ip);
+ device->device_mask = inet_addr(device_mask);
+ read_mac(dev, device->mac_addr);
+ return(device->fd);
+}
+
+int tuntap_read(struct tuntap_dev *tuntap, unsigned char *buf, int len) {
+ return(read(tuntap->fd, buf, len));
+}
+
+int tuntap_write(struct tuntap_dev *tuntap, unsigned char *buf, int len) {
+ return(write(tuntap->fd, buf, len));
+}
+
+void tuntap_close(struct tuntap_dev *tuntap) {
+ close(tuntap->fd);
+}
+
+/* Fill out the ip_addr value from the interface. Called to pick up dynamic
+ * address changes. */
+void tuntap_get_address(struct tuntap_dev *tuntap)
+{
+ FILE * fp=NULL;
+ ssize_t nread=0;
+ char buf[N2N_LINUX_SYSTEMCMD_SIZE];
+
+ /* Would rather have a more direct way to get the inet address but a netlink
+ * socket is overkill and probably less portable than ifconfig and sed. */
+
+ /* If the interface has no address (0.0.0.0) there will be no inet addr
+ * line and the returned string will be empty. */
+ snprintf( buf, sizeof(buf), "/sbin/ifconfig %s | /bin/sed -e '/inet addr:/!d' -e 's/^.*inet addr://' -e 's/ .*$//'",
+ tuntap->dev_name );
+ fp=popen(buf, "r");
+ if (fp )
+ {
+ memset(buf,0,N2N_LINUX_SYSTEMCMD_SIZE); /* make sure buf is NULL terminated. */
+ nread=fread(buf, 1, 15, fp);
+ fclose(fp);
+ fp=NULL;
+
+ traceEvent(TRACE_INFO, "ifconfig address = %s", buf);
+
+ tuntap->ip_addr = inet_addr(buf);
+ }
+}
+
+
+#endif /* #ifdef __linux__ */
diff --git a/tuntap_netbsd.c b/tuntap_netbsd.c
new file mode 100644
index 0000000..011f7df
--- /dev/null
+++ b/tuntap_netbsd.c
@@ -0,0 +1,146 @@
+/*
+ * (C) 2007-09 - Luca Deri
+ * (C) 2009 - Alaric Snell-Pym
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not see see
+ */
+
+#include "n2n.h"
+
+#ifdef __NetBSD__
+
+#include
+#include
+#include
+
+void tun_close(tuntap_dev *device);
+
+/* ********************************** */
+
+#define N2N_NETBSD_TAPDEVICE_SIZE 32
+int tuntap_open(tuntap_dev *device /* ignored */,
+ char *dev,
+ const char *address_mode, /* static or dhcp */
+ char *device_ip,
+ char *device_mask,
+ const char * device_mac,
+ int mtu) {
+ char tap_device[N2N_NETBSD_TAPDEVICE_SIZE];
+ struct ifreq req;
+
+ if (dev) {
+ snprintf(tap_device, sizeof(tap_device), "/dev/%s", dev);
+ device->fd = open(tap_device, O_RDWR);
+ snprintf(tap_device, sizeof(tap_device), "%s", dev);
+ }
+ else {
+ device->fd = open("/dev/tap", O_RDWR);
+ if(device->fd >= 0) {
+ if (ioctl(device->fd, TAPGIFNAME, &req) == -1) {
+ traceEvent(TRACE_ERROR, "Unable to obtain name of tap device (%s)", strerror(errno));
+ close(device->fd);
+ return(-1);
+ }
+ else {
+ snprintf(tap_device, sizeof(tap_device), req.ifr_name);
+ }
+ }
+ }
+
+ if(device->fd < 0) {
+ traceEvent(TRACE_ERROR, "Unable to open tap device (%s)", strerror(errno));
+ return(-1);
+ } else {
+ char buf[256];
+ FILE *fd;
+
+ traceEvent(TRACE_NORMAL, "Succesfully open %s", tap_device);
+
+ device->ip_addr = inet_addr(device_ip);
+
+ if ( device_mac && device_mac[0] != '\0' )
+ {
+ /* Set the hw address before bringing the if up. */
+ snprintf(buf, sizeof(buf), "ifconfig %s link %s active",
+ tap_device, device_mac);
+ system(buf);
+ }
+
+ snprintf(buf, sizeof(buf), "ifconfig %s %s netmask %s mtu %d up",
+ tap_device, device_ip, device_mask, mtu);
+ system(buf);
+
+ traceEvent(TRACE_NORMAL, "Interface %s up and running (%s/%s)",
+ tap_device, device_ip, device_mask);
+
+ /* Read MAC address */
+
+ snprintf(buf, sizeof(buf), "ifconfig %s |grep address|cut -c 11-28", tap_device);
+ /* traceEvent(TRACE_INFO, "%s", buf); */
+
+ fd = popen(buf, "r");
+ if(fd < 0) {
+ tun_close(device);
+ return(-1);
+ } else {
+ int a, b, c, d, e, f;
+
+ buf[0] = 0;
+ fgets(buf, sizeof(buf), fd);
+ pclose(fd);
+
+ if(buf[0] == '\0') {
+ traceEvent(TRACE_ERROR, "Unable to read %s interface MAC address", tap_device);
+ exit(0);
+ }
+
+ traceEvent(TRACE_NORMAL, "Interface %s mac %s", tap_device, buf);
+ if(sscanf(buf, "%02x:%02x:%02x:%02x:%02x:%02x", &a, &b, &c, &d, &e, &f) == 6) {
+ device->mac_addr[0] = a, device->mac_addr[1] = b;
+ device->mac_addr[2] = c, device->mac_addr[3] = d;
+ device->mac_addr[4] = e, device->mac_addr[5] = f;
+ }
+ }
+ }
+
+
+ /* read_mac(dev, device->mac_addr); */
+ return(device->fd);
+}
+
+/* ********************************** */
+
+int tuntap_read(struct tuntap_dev *tuntap, unsigned char *buf, int len) {
+ return(read(tuntap->fd, buf, len));
+}
+
+/* ********************************** */
+
+int tuntap_write(struct tuntap_dev *tuntap, unsigned char *buf, int len) {
+ return(write(tuntap->fd, buf, len));
+}
+
+/* ********************************** */
+
+void tuntap_close(struct tuntap_dev *tuntap) {
+ close(tuntap->fd);
+}
+
+/* Fill out the ip_addr value from the interface. Called to pick up dynamic
+ * address changes. */
+void tuntap_get_address(struct tuntap_dev *tuntap)
+{
+}
+
+#endif /* #ifdef __NetBSD__ */
diff --git a/tuntap_osx.c b/tuntap_osx.c
new file mode 100644
index 0000000..6b37b1f
--- /dev/null
+++ b/tuntap_osx.c
@@ -0,0 +1,132 @@
+/*
+ * (C) 2007-09 - Luca Deri
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not see see
+ */
+
+#include "n2n.h"
+
+#ifdef _DARWIN_
+
+void tun_close(tuntap_dev *device);
+
+/* ********************************** */
+
+#define N2N_OSX_TAPDEVICE_SIZE 32
+int tuntap_open(tuntap_dev *device /* ignored */,
+ char *dev,
+ const char *address_mode, /* static or dhcp */
+ char *device_ip,
+ char *device_mask,
+ const char * device_mac,
+ int mtu) {
+ int i;
+ char tap_device[N2N_OSX_TAPDEVICE_SIZE];
+
+ for (i = 0; i < 255; i++) {
+ snprintf(tap_device, sizeof(tap_device), "/dev/tap%d", i);
+
+ device->fd = open(tap_device, O_RDWR);
+ if(device->fd > 0) {
+ traceEvent(TRACE_NORMAL, "Succesfully open %s", tap_device);
+ break;
+ }
+ }
+
+ if(device->fd < 0) {
+ traceEvent(TRACE_ERROR, "Unable to open tap device");
+ return(-1);
+ } else {
+ char buf[256];
+ FILE *fd;
+
+ device->ip_addr = inet_addr(device_ip);
+
+ if ( device_mac && device_mac[0] != '\0' )
+ {
+ /* FIXME - This is not tested. Might be wrong syntax for OS X */
+
+ /* Set the hw address before bringing the if up. */
+ snprintf(buf, sizeof(buf), "ifconfig tap%d ether %s",
+ i, device_mac);
+ system(buf);
+ }
+
+ snprintf(buf, sizeof(buf), "ifconfig tap%d %s netmask %s mtu %d up",
+ i, device_ip, device_mask, mtu);
+ system(buf);
+
+ traceEvent(TRACE_NORMAL, "Interface tap%d up and running (%s/%s)",
+ i, device_ip, device_mask);
+
+ /* Read MAC address */
+
+ snprintf(buf, sizeof(buf), "ifconfig tap%d |grep ether|cut -c 8-24", i);
+ /* traceEvent(TRACE_INFO, "%s", buf); */
+
+ fd = popen(buf, "r");
+ if(fd < 0) {
+ tun_close(device);
+ return(-1);
+ } else {
+ int a, b, c, d, e, f;
+
+ buf[0] = 0;
+ fgets(buf, sizeof(buf), fd);
+ pclose(fd);
+
+ if(buf[0] == '\0') {
+ traceEvent(TRACE_ERROR, "Unable to read tap%d interface MAC address");
+ exit(0);
+ }
+
+ traceEvent(TRACE_NORMAL, "Interface tap%d [MTU %d] mac %s", i, mtu, buf);
+ if(sscanf(buf, "%02x:%02x:%02x:%02x:%02x:%02x", &a, &b, &c, &d, &e, &f) == 6) {
+ device->mac_addr[0] = a, device->mac_addr[1] = b;
+ device->mac_addr[2] = c, device->mac_addr[3] = d;
+ device->mac_addr[4] = e, device->mac_addr[5] = f;
+ }
+ }
+ }
+
+
+ /* read_mac(dev, device->mac_addr); */
+ return(device->fd);
+}
+
+/* ********************************** */
+
+int tuntap_read(struct tuntap_dev *tuntap, unsigned char *buf, int len) {
+ return(read(tuntap->fd, buf, len));
+}
+
+/* ********************************** */
+
+int tuntap_write(struct tuntap_dev *tuntap, unsigned char *buf, int len) {
+ return(write(tuntap->fd, buf, len));
+}
+
+/* ********************************** */
+
+void tuntap_close(struct tuntap_dev *tuntap) {
+ close(tuntap->fd);
+}
+
+/* Fill out the ip_addr value from the interface. Called to pick up dynamic
+ * address changes. */
+void tuntap_get_address(struct tuntap_dev *tuntap)
+{
+}
+
+#endif /* _DARWIN_ */
diff --git a/twofish.c b/twofish.c
new file mode 100644
index 0000000..57661d7
--- /dev/null
+++ b/twofish.c
@@ -0,0 +1,1031 @@
+/* $Id: twofish.c,v 2.0 2002/08/11 22:32:25 fknobbe Exp $
+ *
+ *
+ * Copyright (C) 1997-2000 The Cryptix Foundation Limited.
+ * Copyright (C) 2000 Farm9.
+ * Copyright (C) 2001 Frank Knobbe.
+ * All rights reserved.
+ *
+ * For Cryptix code:
+ * Use, modification, copying and distribution of this software is subject
+ * the terms and conditions of the Cryptix General Licence. You should have
+ * received a copy of the Cryptix General Licence along with this library;
+ * if not, you can download a copy from http://www.cryptix.org/ .
+ *
+ * For Farm9:
+ * --- jojo@farm9.com, August 2000, converted from Java to C++, added CBC mode and
+ * ciphertext stealing technique, added AsciiTwofish class for easy encryption
+ * decryption of text strings
+ *
+ * Frank Knobbe :
+ * --- April 2001, converted from C++ to C, prefixed global variables
+ * with TwoFish, substituted some defines, changed functions to make use of
+ * variables supplied in a struct, modified and added routines for modular calls.
+ * Cleaned up the code so that defines are used instead of fixed 16's and 32's.
+ * Created two general purpose crypt routines for one block and multiple block
+ * encryption using Joh's CBC code.
+ * Added crypt routines that use a header (with a magic and data length).
+ * (Basically a major rewrite).
+ *
+ * Note: Routines labeled _TwoFish are private and should not be used
+ * (or with extreme caution).
+ *
+ */
+
+#ifndef __TWOFISH_LIBRARY_SOURCE__
+#define __TWOFISH_LIBRARY_SOURCE__
+
+#include
+#include
+#include
+#include
+#include
+#include "twofish.h"
+
+
+bool TwoFish_srand=TRUE; /* if TRUE, first call of TwoFishInit will seed rand(); */
+/* of TwoFishInit */
+
+/* Fixed 8x8 permutation S-boxes */
+static const uint8_t TwoFish_P[2][256] =
+ {
+ { /* p0 */
+ 0xA9, 0x67, 0xB3, 0xE8, 0x04, 0xFD, 0xA3, 0x76, 0x9A, 0x92, 0x80, 0x78,
+ 0xE4, 0xDD, 0xD1, 0x38, 0x0D, 0xC6, 0x35, 0x98, 0x18, 0xF7, 0xEC, 0x6C,
+ 0x43, 0x75, 0x37, 0x26, 0xFA, 0x13, 0x94, 0x48, 0xF2, 0xD0, 0x8B, 0x30,
+ 0x84, 0x54, 0xDF, 0x23, 0x19, 0x5B, 0x3D, 0x59, 0xF3, 0xAE, 0xA2, 0x82,
+ 0x63, 0x01, 0x83, 0x2E, 0xD9, 0x51, 0x9B, 0x7C, 0xA6, 0xEB, 0xA5, 0xBE,
+ 0x16, 0x0C, 0xE3, 0x61, 0xC0, 0x8C, 0x3A, 0xF5, 0x73, 0x2C, 0x25, 0x0B,
+ 0xBB, 0x4E, 0x89, 0x6B, 0x53, 0x6A, 0xB4, 0xF1, 0xE1, 0xE6, 0xBD, 0x45,
+ 0xE2, 0xF4, 0xB6, 0x66, 0xCC, 0x95, 0x03, 0x56, 0xD4, 0x1C, 0x1E, 0xD7,
+ 0xFB, 0xC3, 0x8E, 0xB5, 0xE9, 0xCF, 0xBF, 0xBA, 0xEA, 0x77, 0x39, 0xAF,
+ 0x33, 0xC9, 0x62, 0x71, 0x81, 0x79, 0x09, 0xAD, 0x24, 0xCD, 0xF9, 0xD8,
+ 0xE5, 0xC5, 0xB9, 0x4D, 0x44, 0x08, 0x86, 0xE7, 0xA1, 0x1D, 0xAA, 0xED,
+ 0x06, 0x70, 0xB2, 0xD2, 0x41, 0x7B, 0xA0, 0x11, 0x31, 0xC2, 0x27, 0x90,
+ 0x20, 0xF6, 0x60, 0xFF, 0x96, 0x5C, 0xB1, 0xAB, 0x9E, 0x9C, 0x52, 0x1B,
+ 0x5F, 0x93, 0x0A, 0xEF, 0x91, 0x85, 0x49, 0xEE, 0x2D, 0x4F, 0x8F, 0x3B,
+ 0x47, 0x87, 0x6D, 0x46, 0xD6, 0x3E, 0x69, 0x64, 0x2A, 0xCE, 0xCB, 0x2F,
+ 0xFC, 0x97, 0x05, 0x7A, 0xAC, 0x7F, 0xD5, 0x1A, 0x4B, 0x0E, 0xA7, 0x5A,
+ 0x28, 0x14, 0x3F, 0x29, 0x88, 0x3C, 0x4C, 0x02, 0xB8, 0xDA, 0xB0, 0x17,
+ 0x55, 0x1F, 0x8A, 0x7D, 0x57, 0xC7, 0x8D, 0x74, 0xB7, 0xC4, 0x9F, 0x72,
+ 0x7E, 0x15, 0x22, 0x12, 0x58, 0x07, 0x99, 0x34, 0x6E, 0x50, 0xDE, 0x68,
+ 0x65, 0xBC, 0xDB, 0xF8, 0xC8, 0xA8, 0x2B, 0x40, 0xDC, 0xFE, 0x32, 0xA4,
+ 0xCA, 0x10, 0x21, 0xF0, 0xD3, 0x5D, 0x0F, 0x00, 0x6F, 0x9D, 0x36, 0x42,
+ 0x4A, 0x5E, 0xC1, 0xE0
+ },
+ { /* p1 */
+ 0x75, 0xF3, 0xC6, 0xF4, 0xDB, 0x7B, 0xFB, 0xC8, 0x4A, 0xD3, 0xE6, 0x6B,
+ 0x45, 0x7D, 0xE8, 0x4B, 0xD6, 0x32, 0xD8, 0xFD, 0x37, 0x71, 0xF1, 0xE1,
+ 0x30, 0x0F, 0xF8, 0x1B, 0x87, 0xFA, 0x06, 0x3F, 0x5E, 0xBA, 0xAE, 0x5B,
+ 0x8A, 0x00, 0xBC, 0x9D, 0x6D, 0xC1, 0xB1, 0x0E, 0x80, 0x5D, 0xD2, 0xD5,
+ 0xA0, 0x84, 0x07, 0x14, 0xB5, 0x90, 0x2C, 0xA3, 0xB2, 0x73, 0x4C, 0x54,
+ 0x92, 0x74, 0x36, 0x51, 0x38, 0xB0, 0xBD, 0x5A, 0xFC, 0x60, 0x62, 0x96,
+ 0x6C, 0x42, 0xF7, 0x10, 0x7C, 0x28, 0x27, 0x8C, 0x13, 0x95, 0x9C, 0xC7,
+ 0x24, 0x46, 0x3B, 0x70, 0xCA, 0xE3, 0x85, 0xCB, 0x11, 0xD0, 0x93, 0xB8,
+ 0xA6, 0x83, 0x20, 0xFF, 0x9F, 0x77, 0xC3, 0xCC, 0x03, 0x6F, 0x08, 0xBF,
+ 0x40, 0xE7, 0x2B, 0xE2, 0x79, 0x0C, 0xAA, 0x82, 0x41, 0x3A, 0xEA, 0xB9,
+ 0xE4, 0x9A, 0xA4, 0x97, 0x7E, 0xDA, 0x7A, 0x17, 0x66, 0x94, 0xA1, 0x1D,
+ 0x3D, 0xF0, 0xDE, 0xB3, 0x0B, 0x72, 0xA7, 0x1C, 0xEF, 0xD1, 0x53, 0x3E,
+ 0x8F, 0x33, 0x26, 0x5F, 0xEC, 0x76, 0x2A, 0x49, 0x81, 0x88, 0xEE, 0x21,
+ 0xC4, 0x1A, 0xEB, 0xD9, 0xC5, 0x39, 0x99, 0xCD, 0xAD, 0x31, 0x8B, 0x01,
+ 0x18, 0x23, 0xDD, 0x1F, 0x4E, 0x2D, 0xF9, 0x48, 0x4F, 0xF2, 0x65, 0x8E,
+ 0x78, 0x5C, 0x58, 0x19, 0x8D, 0xE5, 0x98, 0x57, 0x67, 0x7F, 0x05, 0x64,
+ 0xAF, 0x63, 0xB6, 0xFE, 0xF5, 0xB7, 0x3C, 0xA5, 0xCE, 0xE9, 0x68, 0x44,
+ 0xE0, 0x4D, 0x43, 0x69, 0x29, 0x2E, 0xAC, 0x15, 0x59, 0xA8, 0x0A, 0x9E,
+ 0x6E, 0x47, 0xDF, 0x34, 0x35, 0x6A, 0xCF, 0xDC, 0x22, 0xC9, 0xC0, 0x9B,
+ 0x89, 0xD4, 0xED, 0xAB, 0x12, 0xA2, 0x0D, 0x52, 0xBB, 0x02, 0x2F, 0xA9,
+ 0xD7, 0x61, 0x1E, 0xB4, 0x50, 0x04, 0xF6, 0xC2, 0x16, 0x25, 0x86, 0x56,
+ 0x55, 0x09, 0xBE, 0x91
+ }
+ };
+
+static bool TwoFish_MDSready=FALSE;
+static uint32_t TwoFish_MDS[4][256]; /* TwoFish_MDS matrix */
+
+
+#define TwoFish_LFSR1(x) (((x)>>1)^(((x)&0x01)?TwoFish_MDS_GF_FDBK/2:0))
+#define TwoFish_LFSR2(x) (((x)>>2)^(((x)&0x02)?TwoFish_MDS_GF_FDBK/2:0)^(((x)&0x01)?TwoFish_MDS_GF_FDBK/4:0))
+
+#define TwoFish_Mx_1(x) ((uint32_t)(x)) /* force result to dword so << will work */
+#define TwoFish_Mx_X(x) ((uint32_t)((x)^TwoFish_LFSR2(x))) /* 5B */
+#define TwoFish_Mx_Y(x) ((uint32_t)((x)^TwoFish_LFSR1(x)^TwoFish_LFSR2(x))) /* EF */
+#define TwoFish_RS_rem(x) { uint8_t b=(uint8_t)(x>>24); uint32_t g2=((b<<1)^((b&0x80)?TwoFish_RS_GF_FDBK:0))&0xFF; uint32_t g3=((b>>1)&0x7F)^((b&1)?TwoFish_RS_GF_FDBK>>1:0)^g2; x=(x<<8)^(g3<<24)^(g2<<16)^(g3<<8)^b; }
+
+/*#define TwoFish__b(x,N) (((uint8_t *)&x)[((N)&3)^TwoFish_ADDR_XOR])*/ /* pick bytes out of a dword */
+
+#define TwoFish_b0(x) TwoFish__b(x,0) /* extract LSB of uint32_t */
+#define TwoFish_b1(x) TwoFish__b(x,1)
+#define TwoFish_b2(x) TwoFish__b(x,2)
+#define TwoFish_b3(x) TwoFish__b(x,3) /* extract MSB of uint32_t */
+
+uint8_t TwoFish__b(uint32_t x,int n)
+{ n&=3;
+ while(n-->0)
+ x>>=8;
+ return (uint8_t)x;
+}
+
+
+/* TwoFish Initialization
+ *
+ * This routine generates a global data structure for use with TwoFish,
+ * initializes important values (such as subkeys, sBoxes), generates subkeys
+ * and precomputes the MDS matrix if not already done.
+ *
+ * Input: User supplied password (will be appended by default password of 'SnortHas2FishEncryptionRoutines!')
+ *
+ * Output: Pointer to TWOFISH structure. This data structure contains key dependent data.
+ * This pointer is used with all other crypt functions.
+ */
+
+TWOFISH *TwoFishInit(const uint8_t *userkey, uint32_t keysize)
+{ TWOFISH *tfdata;
+ int i,x,m;
+ uint8_t tkey[TwoFish_KEY_LENGTH+40];
+
+ memset( tkey, 0, TwoFish_KEY_LENGTH+40 );
+ tfdata=(TWOFISH *)malloc(sizeof(TWOFISH)); /* allocate the TwoFish structure */
+ if(tfdata!=NULL)
+ {
+
+ /* Changes here prevented a dangerous random key segment for keys of length < TwoFish_KEY_LENGTH */
+ if(keysize > 0)
+ {
+ memcpy( tkey, userkey, keysize ); /* The rest will be zeros */
+ }
+ else
+ {
+ memcpy( tkey, TwoFish_DEFAULT_PW, TwoFish_DEFAULT_PW_LEN ); /* if no key defined, use default password */
+ }
+
+ /* This loop is awful - surely a loop on memcpy() would be clearer and more efficient */
+ for(i=0,x=0,m=keysize;ikey[i]=tkey[x++]; /* fill the whole keyspace with repeating key. */
+ if(x==m)
+ x=0;
+ }
+
+ if(!TwoFish_MDSready)
+ _TwoFish_PrecomputeMDSmatrix(); /* "Wake Up, Neo" */
+ _TwoFish_MakeSubKeys(tfdata); /* generate subkeys */
+ _TwoFish_ResetCBC(tfdata); /* reset the CBC */
+ tfdata->output=NULL; /* nothing to output yet */
+ tfdata->dontflush=FALSE; /* reset decrypt skip block flag */
+ if(TwoFish_srand)
+ {
+ TwoFish_srand=FALSE;
+ /* REVISIT: BbMaj7 : Should choose something with less predictability
+ * particularly for embedded targets with no real-time clock. */
+ srand((unsigned int)time(NULL));
+ }
+ }
+ return tfdata; /* return the data pointer */
+}
+
+
+void TwoFishDestroy(TWOFISH *tfdata)
+{ if(tfdata!=NULL)
+ free(tfdata);
+}
+
+
+/* en/decryption with CBC mode */
+uint32_t _TwoFish_CryptRawCBC(uint8_t *in,uint8_t *out,uint32_t len,bool decrypt,TWOFISH *tfdata)
+{ uint32_t rl;
+
+ rl=len; /* remember how much data to crypt. */
+ while(len>TwoFish_BLOCK_SIZE) /* and now we process block by block. */
+ { _TwoFish_BlockCrypt(in,out,TwoFish_BLOCK_SIZE,decrypt,tfdata); /* de/encrypt it. */
+ in+=TwoFish_BLOCK_SIZE; /* adjust pointers. */
+ out+=TwoFish_BLOCK_SIZE;
+ len-=TwoFish_BLOCK_SIZE;
+ }
+ if(len>0) /* if we have less than a block left... */
+ _TwoFish_BlockCrypt(in,out,len,decrypt,tfdata); /* ...then we de/encrypt that too. */
+ if(tfdata->qBlockDefined && !tfdata->dontflush) /* in case len was exactly one block... */
+ _TwoFish_FlushOutput(tfdata->qBlockCrypt,TwoFish_BLOCK_SIZE,tfdata); /* ...we need to write the... */
+ /* ...remaining bytes of the buffer */
+ return rl;
+}
+
+/* en/decryption on one block only */
+uint32_t _TwoFish_CryptRaw16(uint8_t *in,uint8_t *out,uint32_t len,bool decrypt,TWOFISH *tfdata)
+{ /* qBlockPlain already zero'ed through ResetCBC */
+ memcpy(tfdata->qBlockPlain,in,len); /* toss the data into it. */
+ _TwoFish_BlockCrypt16(tfdata->qBlockPlain,tfdata->qBlockCrypt,decrypt,tfdata); /* encrypt just that block without CBC. */
+ memcpy(out,tfdata->qBlockCrypt,TwoFish_BLOCK_SIZE); /* and return what we got */
+ return TwoFish_BLOCK_SIZE;
+}
+
+/* en/decryption without reset of CBC and output assignment */
+uint32_t _TwoFish_CryptRaw(uint8_t *in,uint8_t *out,uint32_t len,bool decrypt,TWOFISH *tfdata)
+{
+ if(in!=NULL && out!=NULL && len>0 && tfdata!=NULL) /* if we have valid data, then... */
+ { if(len>TwoFish_BLOCK_SIZE) /* ...check if we have more than one block. */
+ return _TwoFish_CryptRawCBC(in,out,len,decrypt,tfdata); /* if so, use the CBC routines... */
+ else
+ return _TwoFish_CryptRaw16(in,out,len,decrypt,tfdata); /* ...otherwise just do one block. */
+ }
+ return 0;
+}
+
+
+/* TwoFish Raw Encryption
+ *
+ * Does not use header, but does use CBC (if more than one block has to be encrypted).
+ *
+ * Input: Pointer to the buffer of the plaintext to be encrypted.
+ * Pointer to the buffer receiving the ciphertext.
+ * The length of the plaintext buffer.
+ * The TwoFish structure.
+ *
+ * Output: The amount of bytes encrypted if successful, otherwise 0.
+ */
+
+uint32_t TwoFishEncryptRaw(uint8_t *in,
+ uint8_t *out,
+ uint32_t len,
+ TWOFISH *tfdata)
+{ _TwoFish_ResetCBC(tfdata); /* reset CBC flag. */
+ tfdata->output=out; /* output straight into output buffer. */
+ return _TwoFish_CryptRaw(in,out,len,FALSE,tfdata); /* and go for it. */
+}
+
+/* TwoFish Raw Decryption
+ *
+ * Does not use header, but does use CBC (if more than one block has to be decrypted).
+ *
+ * Input: Pointer to the buffer of the ciphertext to be decrypted.
+ * Pointer to the buffer receiving the plaintext.
+ * The length of the ciphertext buffer (at least one cipher block).
+ * The TwoFish structure.
+ *
+ * Output: The amount of bytes decrypted if successful, otherwise 0.
+ */
+
+uint32_t TwoFishDecryptRaw(uint8_t *in,
+ uint8_t *out,
+ uint32_t len,
+ TWOFISH *tfdata)
+{ _TwoFish_ResetCBC(tfdata); /* reset CBC flag. */
+ tfdata->output=out; /* output straight into output buffer. */
+ return _TwoFish_CryptRaw(in,out,len,TRUE,tfdata); /* and go for it. */
+}
+
+/* TwoFish Free
+ *
+ * Free's the allocated buffer.
+ *
+ * Input: Pointer to the TwoFish structure
+ *
+ * Output: (none)
+ */
+
+void TwoFishFree(TWOFISH *tfdata)
+{ if(tfdata->output!=NULL) /* if a valid buffer is present... */
+ { free(tfdata->output); /* ...then we free it for you... */
+ tfdata->output=NULL; /* ...and mark as such. */
+ }
+}
+
+/* TwoFish Set Output
+ *
+ * If you want to allocate the output buffer yourself,
+ * then you can set it with this function.
+ *
+ * Input: Pointer to your output buffer
+ * Pointer to the TwoFish structure
+ *
+ * Output: (none)
+ */
+
+void TwoFishSetOutput(uint8_t *outp,TWOFISH *tfdata)
+{ tfdata->output=outp; /* (do we really need a function for this?) */
+}
+
+/* TwoFish Alloc
+ *
+ * Allocates enough memory for the output buffer that would be required
+ *
+ * Input: Length of the plaintext.
+ * Boolean flag for BinHex Output.
+ * Pointer to the TwoFish structure.
+ *
+ * Output: Returns a pointer to the memory allocated.
+ */
+
+void *TwoFishAlloc(uint32_t len,bool binhex,bool decrypt,TWOFISH *tfdata)
+{
+ /* TwoFishFree(tfdata); */ /* (don't for now) discard whatever was allocated earlier. */
+ if(decrypt) /* if decrypting... */
+ { if(binhex) /* ...and input is binhex encoded... */
+ len/=2; /* ...use half as much for output. */
+ len-=TwoFish_BLOCK_SIZE; /* Also, subtract the size of the header. */
+ }
+ else
+ { len+=TwoFish_BLOCK_SIZE; /* the size is just increased by the header... */
+ if(binhex)
+ len*=2; /* ...and doubled if output is to be binhexed. */
+ }
+ tfdata->output=malloc(len+TwoFish_BLOCK_SIZE);/* grab some memory...plus some extra (it's running over somewhere, crashes without extra padding) */
+
+ return tfdata->output; /* ...and return to caller. */
+}
+
+/* bin2hex and hex2bin conversion */
+void _TwoFish_BinHex(uint8_t *buf,uint32_t len,bool bintohex)
+{ uint8_t *pi,*po,c;
+
+ if(bintohex)
+ { for(pi=buf+len-1,po=buf+(2*len)-1;len>0;pi--,po--,len--) /* let's start from the end of the bin block. */
+ { c=*pi; /* grab value. */
+ c&=15; /* use lower 4 bits. */
+ if(c>9) /* convert to ascii. */
+ c+=('a'-10);
+ else
+ c+='0';
+ *po--=c; /* set the lower nibble. */
+ c=*pi; /* grab value again. */
+ c>>=4; /* right shift 4 bits. */
+ c&=15; /* make sure we only have 4 bits. */
+ if(c>9) /* convert to ascii. */
+ c+=('a'-10);
+ else
+ c+='0';
+ *po=c; /* set the higher nibble. */
+ } /* and keep going. */
+ }
+ else
+ { for(pi=buf,po=buf;len>0;pi++,po++,len-=2) /* let's start from the beginning of the hex block. */
+ { c=tolower(*pi++)-'0'; /* grab higher nibble. */
+ if(c>9) /* convert to value. */
+ c-=('0'-9);
+ *po=c<<4; /* left shit 4 bits. */
+ c=tolower(*pi)-'0'; /* grab lower nibble. */
+ if(c>9) /* convert to value. */
+ c-=('0'-9);
+ *po|=c; /* and add to value. */
+ }
+ }
+}
+
+
+/* TwoFish Encryption
+ *
+ * Uses header and CBC. If the output area has not been intialized with TwoFishAlloc,
+ * this routine will alloc the memory. In addition, it will include a small 'header'
+ * containing the magic and some salt. That way the decrypt routine can check if the
+ * packet got decrypted successfully, and return 0 instead of garbage.
+ *
+ * Input: Pointer to the buffer of the plaintext to be encrypted.
+ * Pointer to the pointer to the buffer receiving the ciphertext.
+ * The pointer either points to user allocated output buffer space, or to NULL, in which case
+ * this routine will set the pointer to the buffer allocated through the struct.
+ * The length of the plaintext buffer.
+ * Can be -1 if the input is a null terminated string, in which case we'll count for you.
+ * Boolean flag for BinHex Output (if used, output will be twice as large as input).
+ * Note: BinHex conversion overwrites (converts) input buffer!
+ * The TwoFish structure.
+ *
+ * Output: The amount of bytes encrypted if successful, otherwise 0.
+ */
+
+uint32_t TwoFishEncrypt(uint8_t *in,
+ uint8_t **out,
+ signed long len,
+ bool binhex,
+ TWOFISH *tfdata)
+{ uint32_t ilen,olen;
+
+
+#if 0
+/* This is so broken it doesn't deserve to live. */
+ if(len== -1) /* if we got -1 for len, we'll assume IN is a... */
+ ilen=strlen(in); /* ...\0 terminated string and figure len out ourselves... */
+ else
+ ilen=len; /* ...otherwise we trust you supply a correct length. */
+#endif
+
+ ilen = len;
+
+ if(in!=NULL && out!=NULL && ilen>0 && tfdata!=NULL) /* if we got usable stuff, we'll do it. */
+ { if(*out==NULL) /* if OUT points to a NULL pointer... */
+ *out=TwoFishAlloc(ilen,binhex,FALSE,tfdata); /* ...we'll (re-)allocate buffer space. */
+ if(*out!=NULL)
+ { tfdata->output=*out; /* set output buffer. */
+ tfdata->header.salt=rand()*65536+rand(); /* toss in some salt. */
+ tfdata->header.length[0]= (uint8_t)(ilen);
+ tfdata->header.length[1]= (uint8_t)(ilen>>8);
+ tfdata->header.length[2]= (uint8_t)(ilen>>16);
+ tfdata->header.length[3]= (uint8_t)(ilen>>24);
+ memcpy(tfdata->header.magic,TwoFish_MAGIC,TwoFish_MAGIC_LEN); /* set the magic. */
+ olen=TwoFish_BLOCK_SIZE; /* set output counter. */
+ _TwoFish_ResetCBC(tfdata); /* reset the CBC flag */
+ _TwoFish_BlockCrypt((uint8_t *)&(tfdata->header),*out,olen,FALSE,tfdata); /* encrypt first block (without flush on 16 byte boundary). */
+ olen+=_TwoFish_CryptRawCBC(in,*out+TwoFish_BLOCK_SIZE,ilen,FALSE,tfdata); /* and encrypt the rest (we do not reset the CBC flag). */
+ if(binhex) /* if binhex... */
+ { _TwoFish_BinHex(*out,olen,TRUE); /* ...convert output to binhex... */
+ olen*=2; /* ...and size twice as large. */
+ }
+ tfdata->output=*out;
+ return olen;
+ }
+ }
+ return 0;
+}
+
+/* TwoFish Decryption
+ *
+ * Uses header and CBC. If the output area has not been intialized with TwoFishAlloc,
+ * this routine will alloc the memory. In addition, it will check the small 'header'
+ * containing the magic. If magic does not match we return 0. Otherwise we return the
+ * amount of bytes decrypted (should be the same as the length in the header).
+ *
+ * Input: Pointer to the buffer of the ciphertext to be decrypted.
+ * Pointer to the pointer to the buffer receiving the plaintext.
+ * The pointer either points to user allocated output buffer space, or to NULL, in which case
+ * this routine will set the pointer to the buffer allocated through the struct.
+ * The length of the ciphertext buffer.
+ * Can be -1 if the input is a null terminated binhex string, in which case we'll count for you.
+ * Boolean flag for BinHex Input (if used, plaintext will be half as large as input).
+ * Note: BinHex conversion overwrites (converts) input buffer!
+ * The TwoFish structure.
+ *
+ * Output: The amount of bytes decrypted if successful, otherwise 0.
+ */
+
+uint32_t TwoFishDecrypt(uint8_t *in,
+ uint8_t **out,
+ signed long len,
+ bool binhex,
+ TWOFISH *tfdata)
+{ uint32_t ilen,elen,olen;
+ const uint8_t cmagic[TwoFish_MAGIC_LEN]=TwoFish_MAGIC;
+ uint8_t *tbuf;
+
+
+
+#if 0
+/* This is so broken it doesn't deserve to live. */
+ if(len== -1) /* if we got -1 for len, we'll assume IN is a... */
+ ilen=strlen(in); /* ...\0 terminated string and figure len out ourselves... */
+ else
+ ilen=len; /* ...otherwise we trust you supply a correct length. */
+#endif
+
+ ilen = len;
+
+ if(in!=NULL && out!=NULL && ilen>0 && tfdata!=NULL) /* if we got usable stuff, we'll do it. */
+ { if(*out==NULL) /* if OUT points to a NULL pointer... */
+ *out=TwoFishAlloc(ilen,binhex,TRUE,tfdata); /* ...we'll (re-)allocate buffer space. */
+ if(*out!=NULL)
+ { if(binhex) /* if binhex... */
+ { _TwoFish_BinHex(in,ilen,FALSE); /* ...convert input to values... */
+ ilen/=2; /* ...and size half as much. */
+ }
+ _TwoFish_ResetCBC(tfdata); /* reset the CBC flag. */
+
+ tbuf=(uint8_t *)malloc(ilen+TwoFish_BLOCK_SIZE); /* get memory for data and header. */
+ if(tbuf==NULL)
+ return 0;
+ tfdata->output=tbuf; /* set output to temp buffer. */
+
+ olen=_TwoFish_CryptRawCBC(in,tbuf,ilen,TRUE,tfdata)-TwoFish_BLOCK_SIZE; /* decrypt the whole thing. */
+ memcpy(&(tfdata->header),tbuf,TwoFish_BLOCK_SIZE); /* copy first block into header. */
+ tfdata->output=*out;
+ for(elen=0;elenheader.magic[elen]!=cmagic[elen])
+ break;
+ if(elen==TwoFish_MAGIC_LEN) /* if magic matches then... */
+ { elen=(tfdata->header.length[0]) |
+ (tfdata->header.length[1])<<8 |
+ (tfdata->header.length[2])<<16 |
+ (tfdata->header.length[3])<<24; /* .. we know how much to expect. */
+ if(elen>olen) /* adjust if necessary. */
+ elen=olen;
+ memcpy(*out,tbuf+TwoFish_BLOCK_SIZE,elen); /* copy data into intended output. */
+ free(tbuf);
+ return elen;
+ }
+ free(tbuf);
+ }
+ }
+ return 0;
+}
+
+void _TwoFish_PrecomputeMDSmatrix(void) /* precompute the TwoFish_MDS matrix */
+{ uint32_t m1[2];
+ uint32_t mX[2];
+ uint32_t mY[2];
+ uint32_t i, j;
+
+ for (i = 0; i < 256; i++)
+ { j = TwoFish_P[0][i] & 0xFF; /* compute all the matrix elements */
+ m1[0] = j;
+ mX[0] = TwoFish_Mx_X( j ) & 0xFF;
+ mY[0] = TwoFish_Mx_Y( j ) & 0xFF;
+
+ j = TwoFish_P[1][i] & 0xFF;
+ m1[1] = j;
+ mX[1] = TwoFish_Mx_X( j ) & 0xFF;
+ mY[1] = TwoFish_Mx_Y( j ) & 0xFF;
+
+ TwoFish_MDS[0][i] = m1[TwoFish_P_00] | /* fill matrix w/ above elements */
+ mX[TwoFish_P_00] << 8 |
+ mY[TwoFish_P_00] << 16 |
+ mY[TwoFish_P_00] << 24;
+ TwoFish_MDS[1][i] = mY[TwoFish_P_10] |
+ mY[TwoFish_P_10] << 8 |
+ mX[TwoFish_P_10] << 16 |
+ m1[TwoFish_P_10] << 24;
+ TwoFish_MDS[2][i] = mX[TwoFish_P_20] |
+ mY[TwoFish_P_20] << 8 |
+ m1[TwoFish_P_20] << 16 |
+ mY[TwoFish_P_20] << 24;
+ TwoFish_MDS[3][i] = mX[TwoFish_P_30] |
+ m1[TwoFish_P_30] << 8 |
+ mY[TwoFish_P_30] << 16 |
+ mX[TwoFish_P_30] << 24;
+ }
+ TwoFish_MDSready=TRUE;
+}
+
+
+void _TwoFish_MakeSubKeys(TWOFISH *tfdata) /* Expand a user-supplied key material into a session key. */
+{ uint32_t k64Cnt = TwoFish_KEY_LENGTH / 8;
+ uint32_t k32e[4]; /* even 32-bit entities */
+ uint32_t k32o[4]; /* odd 32-bit entities */
+ uint32_t sBoxKey[4];
+ uint32_t offset,i,j;
+ uint32_t A, B, q=0;
+ uint32_t k0,k1,k2,k3;
+ uint32_t b0,b1,b2,b3;
+
+ /* split user key material into even and odd 32-bit entities and */
+ /* compute S-box keys using (12, 8) Reed-Solomon code over GF(256) */
+
+
+ for (offset=0,i=0,j=k64Cnt-1;i<4 && offsetkey[offset++];
+ k32e[i]|= tfdata->key[offset++]<<8;
+ k32e[i]|= tfdata->key[offset++]<<16;
+ k32e[i]|= tfdata->key[offset++]<<24;
+ k32o[i] = tfdata->key[offset++];
+ k32o[i]|= tfdata->key[offset++]<<8;
+ k32o[i]|= tfdata->key[offset++]<<16;
+ k32o[i]|= tfdata->key[offset++]<<24;
+ sBoxKey[j] = _TwoFish_RS_MDS_Encode( k32e[i], k32o[i] ); /* reverse order */
+ }
+
+ /* compute the round decryption subkeys for PHT. these same subkeys */
+ /* will be used in encryption but will be applied in reverse order. */
+ i=0;
+ while(i < TwoFish_TOTAL_SUBKEYS)
+ { A = _TwoFish_F32( k64Cnt, q, k32e ); /* A uses even key entities */
+ q += TwoFish_SK_BUMP;
+
+ B = _TwoFish_F32( k64Cnt, q, k32o ); /* B uses odd key entities */
+ q += TwoFish_SK_BUMP;
+
+ B = B << 8 | B >> 24;
+
+ A += B;
+ tfdata->subKeys[i++] = A; /* combine with a PHT */
+
+ A += B;
+ tfdata->subKeys[i++] = A << TwoFish_SK_ROTL | A >> (32-TwoFish_SK_ROTL);
+ }
+
+ /* fully expand the table for speed */
+ k0 = sBoxKey[0];
+ k1 = sBoxKey[1];
+ k2 = sBoxKey[2];
+ k3 = sBoxKey[3];
+
+ for (i = 0; i < 256; i++)
+ { b0 = b1 = b2 = b3 = i;
+ switch (k64Cnt & 3)
+ { case 1: /* 64-bit keys */
+ tfdata->sBox[ 2*i ] = TwoFish_MDS[0][(TwoFish_P[TwoFish_P_01][b0]) ^ TwoFish_b0(k0)];
+ tfdata->sBox[ 2*i+1] = TwoFish_MDS[1][(TwoFish_P[TwoFish_P_11][b1]) ^ TwoFish_b1(k0)];
+ tfdata->sBox[0x200+2*i ] = TwoFish_MDS[2][(TwoFish_P[TwoFish_P_21][b2]) ^ TwoFish_b2(k0)];
+ tfdata->sBox[0x200+2*i+1] = TwoFish_MDS[3][(TwoFish_P[TwoFish_P_31][b3]) ^ TwoFish_b3(k0)];
+ break;
+ case 0: /* 256-bit keys (same as 4) */
+ b0 = (TwoFish_P[TwoFish_P_04][b0]) ^ TwoFish_b0(k3);
+ b1 = (TwoFish_P[TwoFish_P_14][b1]) ^ TwoFish_b1(k3);
+ b2 = (TwoFish_P[TwoFish_P_24][b2]) ^ TwoFish_b2(k3);
+ b3 = (TwoFish_P[TwoFish_P_34][b3]) ^ TwoFish_b3(k3);
+ case 3: /* 192-bit keys */
+ b0 = (TwoFish_P[TwoFish_P_03][b0]) ^ TwoFish_b0(k2);
+ b1 = (TwoFish_P[TwoFish_P_13][b1]) ^ TwoFish_b1(k2);
+ b2 = (TwoFish_P[TwoFish_P_23][b2]) ^ TwoFish_b2(k2);
+ b3 = (TwoFish_P[TwoFish_P_33][b3]) ^ TwoFish_b3(k2);
+ case 2: /* 128-bit keys */
+ tfdata->sBox[ 2*i ]=
+ TwoFish_MDS[0][(TwoFish_P[TwoFish_P_01][(TwoFish_P[TwoFish_P_02][b0]) ^
+ TwoFish_b0(k1)]) ^ TwoFish_b0(k0)];
+
+ tfdata->sBox[ 2*i+1]=
+ TwoFish_MDS[1][(TwoFish_P[TwoFish_P_11][(TwoFish_P[TwoFish_P_12][b1]) ^
+ TwoFish_b1(k1)]) ^ TwoFish_b1(k0)];
+
+ tfdata->sBox[0x200+2*i ]=
+ TwoFish_MDS[2][(TwoFish_P[TwoFish_P_21][(TwoFish_P[TwoFish_P_22][b2]) ^
+ TwoFish_b2(k1)]) ^ TwoFish_b2(k0)];
+
+ tfdata->sBox[0x200+2*i+1]=
+ TwoFish_MDS[3][(TwoFish_P[TwoFish_P_31][(TwoFish_P[TwoFish_P_32][b3]) ^
+ TwoFish_b3(k1)]) ^ TwoFish_b3(k0)];
+ }
+ }
+}
+
+
+/**
+ * Encrypt or decrypt exactly one block of plaintext in CBC mode.
+ * Use "ciphertext stealing" technique described on pg. 196
+ * of "Applied Cryptography" to encrypt the final partial
+ * (i.e. <16 byte) block if necessary.
+ *
+ * jojo: the "ciphertext stealing" requires we read ahead and have
+ * special handling for the last two blocks. Because of this, the
+ * output from the TwoFish algorithm is handled internally here.
+ * It would be better to have a higher level handle this as well as
+ * CBC mode. Unfortunately, I've mixed the two together, which is
+ * pretty crappy... The Java version separates these out correctly.
+ *
+ * fknobbe: I have reduced the CBC mode to work on memory buffer only.
+ * Higher routines should use an intermediate buffer and handle
+ * their output seperately (mainly so the data can be flushed
+ * in one chunk, not seperate 16 byte blocks...)
+ *
+ * @param in The plaintext.
+ * @param out The ciphertext
+ * @param size how much to encrypt
+ * @param tfdata: Pointer to the global data structure containing session keys.
+ * @return none
+ */
+void _TwoFish_BlockCrypt(uint8_t *in,uint8_t *out,uint32_t size,int decrypt,TWOFISH *tfdata)
+{ uint8_t PnMinusOne[TwoFish_BLOCK_SIZE];
+ uint8_t CnMinusOne[TwoFish_BLOCK_SIZE];
+ uint8_t CBCplusCprime[TwoFish_BLOCK_SIZE];
+ uint8_t Pn[TwoFish_BLOCK_SIZE];
+ uint8_t *p,*pout;
+ uint32_t i;
+
+ /* here is where we implement CBC mode and cipher block stealing */
+ if(size==TwoFish_BLOCK_SIZE)
+ { /* if we are encrypting, CBC means we XOR the plain text block with the */
+ /* previous cipher text block before encrypting */
+ if(!decrypt && tfdata->qBlockDefined)
+ { for(p=in,i=0;iqBlockCrypt[i]; /* FK: I'm copying the xor'ed input into Pn... */
+ }
+ else
+ memcpy(Pn,in,TwoFish_BLOCK_SIZE); /* FK: same here. we work of Pn all the time. */
+
+ /* TwoFish block level encryption or decryption */
+ _TwoFish_BlockCrypt16(Pn,out,decrypt,tfdata);
+
+ /* if we are decrypting, CBC means we XOR the result of the decryption */
+ /* with the previous cipher text block to get the resulting plain text */
+ if(decrypt && tfdata->qBlockDefined)
+ { for (p=out,i=0;iqBlockPlain[i];
+ }
+
+ /* save the input and output blocks, since CBC needs these for XOR */
+ /* operations */
+ _TwoFish_qBlockPush(Pn,out,tfdata);
+ }
+ else
+ { /* cipher block stealing, we are at Pn, */
+ /* but since Cn-1 must now be replaced with CnC' */
+ /* we pop it off, and recalculate Cn-1 */
+
+ if(decrypt)
+ { /* We are on an odd block, and had to do cipher block stealing, */
+ /* so the PnMinusOne has to be derived differently. */
+
+ /* First we decrypt it into CBC and C' */
+ _TwoFish_qBlockPop(CnMinusOne,PnMinusOne,tfdata);
+ _TwoFish_BlockCrypt16(CnMinusOne,CBCplusCprime,decrypt,tfdata);
+
+ /* we then xor the first few bytes with the "in" bytes (Cn) */
+ /* to recover Pn, which we put in out */
+ for(p=in,pout=out,i=0;iprevCipher[i];
+
+ /* So at this point, out has PnMinusOne */
+ _TwoFish_qBlockPush(CnMinusOne,PnMinusOne,tfdata);
+ _TwoFish_FlushOutput(tfdata->qBlockCrypt,TwoFish_BLOCK_SIZE,tfdata);
+ _TwoFish_FlushOutput(out,size,tfdata);
+ }
+ else
+ { _TwoFish_qBlockPop(PnMinusOne,CnMinusOne,tfdata);
+ memset(Pn,0,TwoFish_BLOCK_SIZE);
+ memcpy(Pn,in,size);
+ for(i=0;iqBlockCrypt,TwoFish_BLOCK_SIZE,tfdata);
+ _TwoFish_FlushOutput(CnMinusOne,size,tfdata); /* old Cn-1 becomes new partial Cn */
+ }
+ tfdata->qBlockDefined=FALSE;
+ }
+}
+
+void _TwoFish_qBlockPush(uint8_t *p,uint8_t *c,TWOFISH *tfdata)
+{ if(tfdata->qBlockDefined)
+ _TwoFish_FlushOutput(tfdata->qBlockCrypt,TwoFish_BLOCK_SIZE,tfdata);
+ memcpy(tfdata->prevCipher,tfdata->qBlockPlain,TwoFish_BLOCK_SIZE);
+ memcpy(tfdata->qBlockPlain,p,TwoFish_BLOCK_SIZE);
+ memcpy(tfdata->qBlockCrypt,c,TwoFish_BLOCK_SIZE);
+ tfdata->qBlockDefined=TRUE;
+}
+
+void _TwoFish_qBlockPop(uint8_t *p,uint8_t *c,TWOFISH *tfdata)
+{ memcpy(p,tfdata->qBlockPlain,TwoFish_BLOCK_SIZE );
+ memcpy(c,tfdata->qBlockCrypt,TwoFish_BLOCK_SIZE );
+ tfdata->qBlockDefined=FALSE;
+}
+
+/* Reset's the CBC flag and zero's PrevCipher (through qBlockPlain) (important) */
+void _TwoFish_ResetCBC(TWOFISH *tfdata)
+{ tfdata->qBlockDefined=FALSE;
+ memset(tfdata->qBlockPlain,0,TwoFish_BLOCK_SIZE);
+}
+
+void _TwoFish_FlushOutput(uint8_t *b,uint32_t len,TWOFISH *tfdata)
+{ uint32_t i;
+
+ for(i=0;idontflush;i++)
+ *tfdata->output++ = *b++;
+ tfdata->dontflush=FALSE;
+}
+
+void _TwoFish_BlockCrypt16(uint8_t *in,uint8_t *out,bool decrypt,TWOFISH *tfdata)
+{ uint32_t x0,x1,x2,x3;
+ uint32_t k,t0,t1,R;
+
+
+ x0=*in++;
+ x0|=(*in++ << 8 );
+ x0|=(*in++ << 16);
+ x0|=(*in++ << 24);
+ x1=*in++;
+ x1|=(*in++ << 8 );
+ x1|=(*in++ << 16);
+ x1|=(*in++ << 24);
+ x2=*in++;
+ x2|=(*in++ << 8 );
+ x2|=(*in++ << 16);
+ x2|=(*in++ << 24);
+ x3=*in++;
+ x3|=(*in++ << 8 );
+ x3|=(*in++ << 16);
+ x3|=(*in++ << 24);
+
+ if(decrypt)
+ { x0 ^= tfdata->subKeys[4]; /* swap input and output whitening keys when decrypting */
+ x1 ^= tfdata->subKeys[5];
+ x2 ^= tfdata->subKeys[6];
+ x3 ^= tfdata->subKeys[7];
+
+ k = 7+(TwoFish_ROUNDS*2);
+ for (R = 0; R < TwoFish_ROUNDS; R += 2)
+ { t0 = _TwoFish_Fe320( tfdata->sBox, x0);
+ t1 = _TwoFish_Fe323( tfdata->sBox, x1);
+ x3 ^= t0 + (t1<<1) + tfdata->subKeys[k--];
+ x3 = x3 >> 1 | x3 << 31;
+ x2 = x2 << 1 | x2 >> 31;
+ x2 ^= t0 + t1 + tfdata->subKeys[k--];
+
+ t0 = _TwoFish_Fe320( tfdata->sBox, x2);
+ t1 = _TwoFish_Fe323( tfdata->sBox, x3);
+ x1 ^= t0 + (t1<<1) + tfdata->subKeys[k--];
+ x1 = x1 >> 1 | x1 << 31;
+ x0 = x0 << 1 | x0 >> 31;
+ x0 ^= t0 + t1 + tfdata->subKeys[k--];
+ }
+
+ x2 ^= tfdata->subKeys[0];
+ x3 ^= tfdata->subKeys[1];
+ x0 ^= tfdata->subKeys[2];
+ x1 ^= tfdata->subKeys[3];
+ }
+ else
+ { x0 ^= tfdata->subKeys[0];
+ x1 ^= tfdata->subKeys[1];
+ x2 ^= tfdata->subKeys[2];
+ x3 ^= tfdata->subKeys[3];
+
+ k = 8;
+ for (R = 0; R < TwoFish_ROUNDS; R += 2)
+ { t0 = _TwoFish_Fe320( tfdata->sBox, x0);
+ t1 = _TwoFish_Fe323( tfdata->sBox, x1);
+ x2 ^= t0 + t1 + tfdata->subKeys[k++];
+ x2 = x2 >> 1 | x2 << 31;
+ x3 = x3 << 1 | x3 >> 31;
+ x3 ^= t0 + (t1<<1) + tfdata->subKeys[k++];
+
+ t0 = _TwoFish_Fe320( tfdata->sBox, x2);
+ t1 = _TwoFish_Fe323( tfdata->sBox, x3);
+ x0 ^= t0 + t1 + tfdata->subKeys[k++];
+ x0 = x0 >> 1 | x0 << 31;
+ x1 = x1 << 1 | x1 >> 31;
+ x1 ^= t0 + (t1<<1) + tfdata->subKeys[k++];
+ }
+
+ x2 ^= tfdata->subKeys[4];
+ x3 ^= tfdata->subKeys[5];
+ x0 ^= tfdata->subKeys[6];
+ x1 ^= tfdata->subKeys[7];
+ }
+
+ *out++ = (uint8_t)(x2 );
+ *out++ = (uint8_t)(x2 >> 8);
+ *out++ = (uint8_t)(x2 >> 16);
+ *out++ = (uint8_t)(x2 >> 24);
+
+ *out++ = (uint8_t)(x3 );
+ *out++ = (uint8_t)(x3 >> 8);
+ *out++ = (uint8_t)(x3 >> 16);
+ *out++ = (uint8_t)(x3 >> 24);
+
+ *out++ = (uint8_t)(x0 );
+ *out++ = (uint8_t)(x0 >> 8);
+ *out++ = (uint8_t)(x0 >> 16);
+ *out++ = (uint8_t)(x0 >> 24);
+
+ *out++ = (uint8_t)(x1 );
+ *out++ = (uint8_t)(x1 >> 8);
+ *out++ = (uint8_t)(x1 >> 16);
+ *out++ = (uint8_t)(x1 >> 24);
+}
+
+/**
+ * Use (12, 8) Reed-Solomon code over GF(256) to produce a key S-box
+ * 32-bit entity from two key material 32-bit entities.
+ *
+ * @param k0 1st 32-bit entity.
+ * @param k1 2nd 32-bit entity.
+ * @return Remainder polynomial generated using RS code
+ */
+uint32_t _TwoFish_RS_MDS_Encode(uint32_t k0,uint32_t k1)
+{ uint32_t i,r;
+
+ for(r=k1,i=0;i<4;i++) /* shift 1 byte at a time */
+ TwoFish_RS_rem(r);
+ r ^= k0;
+ for(i=0;i<4;i++)
+ TwoFish_RS_rem(r);
+
+ return r;
+}
+
+uint32_t _TwoFish_F32(uint32_t k64Cnt,uint32_t x,uint32_t *k32)
+{ uint8_t b0,b1,b2,b3;
+ uint32_t k0,k1,k2,k3,result = 0;
+
+ b0=TwoFish_b0(x);
+ b1=TwoFish_b1(x);
+ b2=TwoFish_b2(x);
+ b3=TwoFish_b3(x);
+ k0=k32[0];
+ k1=k32[1];
+ k2=k32[2];
+ k3=k32[3];
+
+ switch (k64Cnt & 3)
+ { case 1: /* 64-bit keys */
+ result =
+ TwoFish_MDS[0][(TwoFish_P[TwoFish_P_01][b0] & 0xFF) ^ TwoFish_b0(k0)] ^
+ TwoFish_MDS[1][(TwoFish_P[TwoFish_P_11][b1] & 0xFF) ^ TwoFish_b1(k0)] ^
+ TwoFish_MDS[2][(TwoFish_P[TwoFish_P_21][b2] & 0xFF) ^ TwoFish_b2(k0)] ^
+ TwoFish_MDS[3][(TwoFish_P[TwoFish_P_31][b3] & 0xFF) ^ TwoFish_b3(k0)];
+ break;
+ case 0: /* 256-bit keys (same as 4) */
+ b0 = (TwoFish_P[TwoFish_P_04][b0] & 0xFF) ^ TwoFish_b0(k3);
+ b1 = (TwoFish_P[TwoFish_P_14][b1] & 0xFF) ^ TwoFish_b1(k3);
+ b2 = (TwoFish_P[TwoFish_P_24][b2] & 0xFF) ^ TwoFish_b2(k3);
+ b3 = (TwoFish_P[TwoFish_P_34][b3] & 0xFF) ^ TwoFish_b3(k3);
+
+ case 3: /* 192-bit keys */
+ b0 = (TwoFish_P[TwoFish_P_03][b0] & 0xFF) ^ TwoFish_b0(k2);
+ b1 = (TwoFish_P[TwoFish_P_13][b1] & 0xFF) ^ TwoFish_b1(k2);
+ b2 = (TwoFish_P[TwoFish_P_23][b2] & 0xFF) ^ TwoFish_b2(k2);
+ b3 = (TwoFish_P[TwoFish_P_33][b3] & 0xFF) ^ TwoFish_b3(k2);
+ case 2: /* 128-bit keys (optimize for this case) */
+ result =
+ TwoFish_MDS[0][(TwoFish_P[TwoFish_P_01][(TwoFish_P[TwoFish_P_02][b0] & 0xFF) ^ TwoFish_b0(k1)] & 0xFF) ^ TwoFish_b0(k0)] ^
+ TwoFish_MDS[1][(TwoFish_P[TwoFish_P_11][(TwoFish_P[TwoFish_P_12][b1] & 0xFF) ^ TwoFish_b1(k1)] & 0xFF) ^ TwoFish_b1(k0)] ^
+ TwoFish_MDS[2][(TwoFish_P[TwoFish_P_21][(TwoFish_P[TwoFish_P_22][b2] & 0xFF) ^ TwoFish_b2(k1)] & 0xFF) ^ TwoFish_b2(k0)] ^
+ TwoFish_MDS[3][(TwoFish_P[TwoFish_P_31][(TwoFish_P[TwoFish_P_32][b3] & 0xFF) ^ TwoFish_b3(k1)] & 0xFF) ^ TwoFish_b3(k0)];
+ break;
+ }
+ return result;
+}
+
+uint32_t _TwoFish_Fe320(uint32_t *lsBox,uint32_t x)
+{ return lsBox[ TwoFish_b0(x)<<1 ]^
+ lsBox[ ((TwoFish_b1(x)<<1)|1)]^
+ lsBox[0x200+ (TwoFish_b2(x)<<1) ]^
+ lsBox[0x200+((TwoFish_b3(x)<<1)|1)];
+}
+
+uint32_t _TwoFish_Fe323(uint32_t *lsBox,uint32_t x)
+{ return lsBox[ (TwoFish_b3(x)<<1) ]^
+ lsBox[ ((TwoFish_b0(x)<<1)|1)]^
+ lsBox[0x200+ (TwoFish_b1(x)<<1) ]^
+ lsBox[0x200+((TwoFish_b2(x)<<1)|1)];
+}
+
+uint32_t _TwoFish_Fe32(uint32_t *lsBox,uint32_t x,uint32_t R)
+{ return lsBox[ 2*TwoFish__b(x,R ) ]^
+ lsBox[ 2*TwoFish__b(x,R+1)+1]^
+ lsBox[0x200+2*TwoFish__b(x,R+2) ]^
+ lsBox[0x200+2*TwoFish__b(x,R+3)+1];
+}
+
+
+#endif
+
+/* ******************************************* */
+#if defined TWOFISH_UNIT_TEST
+#include
+
+#define TEST_DATA_SIZE 327
+
+int main(int argc, char* argv[])
+{
+ int i;
+ int n;
+
+ char outbuf[4096];
+ char * outp = outbuf;
+
+ uint8_t key[] = { 0xfc, 0x77, 0x1a, 0xda, 0xaa };
+ TWOFISH *tfa = TwoFishInit( key, 5 );
+ TWOFISH *tfb = TwoFishInit( key, 5 );
+
+ uint8_t out[2048], out2[2048];
+ uint8_t in[TEST_DATA_SIZE];
+
+ for ( i=0; i:
+ * --- April 2001, converted from C++ to C, prefixed global variables
+ * with TwoFish, substituted some defines, changed functions to make use of
+ * variables supplied in a struct, modified and added routines for modular calls.
+ * Cleaned up the code so that defines are used instead of fixed 16's and 32's.
+ * Created two general purpose crypt routines for one block and multiple block
+ * encryption using Joh's CBC code.
+ * Added crypt routines that use a header (with a magic and data length).
+ * (Basically a major rewrite).
+ *
+ * Note: Routines labeled _TwoFish are private and should not be used
+ * (or with extreme caution).
+ *
+ */
+
+#ifndef __TWOFISH_LIBRARY_HEADER__
+#define __TWOFISH_LIBRARY_HEADER__
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+#ifndef TRUE
+#define TRUE !FALSE
+#endif
+#ifndef bool
+#define bool int
+#endif
+
+#ifdef WIN32
+#include "win32/n2n_win32.h"
+#endif
+
+#ifndef _MSC_VER
+/* Not shipped with Visual Studio (as stated by the stdint.h wikipedia page) */
+#include