summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorlijia <[email protected]>2021-09-14 15:50:53 +0800
committerlijia <[email protected]>2021-09-14 15:50:53 +0800
commitf6f399f69a950ab1c45ea0e8c0787a476ff58754 (patch)
tree3cca11bd40a8209a534855a53525ea83763620b0
create new project.v1.0.0
除sapp和插件之外, 其他模块也经常有从某个层跳转到某个层的需求, 从sapp中剥离此部分代码, 独立成为一个公共库.
-rw-r--r--.gitignore5
-rw-r--r--.gitlab-ci.yml114
-rw-r--r--CMakeLists.txt56
-rw-r--r--autorevision.sh1268
-rw-r--r--ci/get-nprocessors.sh48
-rw-r--r--ci/perpare_pulp3_netrc.sh3
-rw-r--r--ci/travis.sh70
-rw-r--r--cmake/.gitignore5
-rw-r--r--cmake/Package.cmake54
-rw-r--r--cmake/Version.cmake54
-rw-r--r--inc/MESA_jump_layer.h30
-rw-r--r--src/MESA_jump_layer.cpp1501
-rw-r--r--src/Makefile10
-rw-r--r--src/deal_ipv6.h113
-rw-r--r--src/mesa_net.h885
-rw-r--r--test/Makefile2
-rw-r--r--test/test_jump_layer.c153
17 files changed, 4371 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..b9ffdf6
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,5 @@
+build
+__view
+*.o
+*.so
+*.a
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
new file mode 100644
index 0000000..d98f134
--- /dev/null
+++ b/.gitlab-ci.yml
@@ -0,0 +1,114 @@
+image: "git.mesalab.cn:7443/mesa_platform/build-env:master"
+variables:
+ GIT_STRATEGY: "clone"
+ BUILD_PADDING_PREFIX: /tmp/padding_for_CPACK_RPM_BUILD_SOURCE_DIRS_PREFIX_PREFIX_PREFIX_PREFIX_PREFIX_PREFIX/
+ INSTALL_PREFIX: "/opt/MESA/lib/"
+ INSTALL_DEPENDENCY_LIBRARY: sapp-devel framework_env libpcap libpcap-devel
+
+stages:
+- build
+
+.build_by_travis:
+ before_script:
+ - mkdir -p $BUILD_PADDING_PREFIX/$CI_PROJECT_NAMESPACE/
+ - ln -s $CI_PROJECT_DIR $BUILD_PADDING_PREFIX/$CI_PROJECT_PATH
+ - cd $BUILD_PADDING_PREFIX/$CI_PROJECT_PATH
+ - chmod +x ./ci/travis.sh
+ script:
+ - yum makecache
+ - ./ci/travis.sh
+ - cd build
+ tags:
+ - share
+
+branch_build_debug:
+ stage: build
+ extends: .build_by_travis
+ variables:
+ BUILD_TYPE: Debug
+ except:
+ - /^develop.*$/i
+ - /^master.*$/i
+ - tags
+
+branch_build_release:
+ stage: build
+ variables:
+ BUILD_TYPE: RelWithDebInfo
+ extends: .build_by_travis
+ except:
+ - /^develop.*$/i
+ - /^master.*$/i
+ - tags
+
+develop_build_debug:
+ stage: build
+ extends: .build_by_travis
+ variables:
+ BUILD_TYPE: Debug
+ PACKAGE: 1
+ UPLOAD_RPM: 1
+ ASAN_OPTION: ADDRESS
+ TESTING_VERSION_BUILD: 1
+ PULP3_REPO_NAME: framework-testing-x86_64.el7
+ PULP3_DIST_NAME: framework-testing-x86_64.el7
+ artifacts:
+ name: MESA_jump_layer-$CI_COMMIT_REF_NAME-debug"
+ paths:
+ - build/*.rpm
+ only:
+ - /^develop.*$/i
+ - /^master.*$/i
+
+develop_build_release:
+ stage: build
+ extends: .build_by_travis
+ variables:
+ BUILD_TYPE: RelWithDebInfo
+ PACKAGE: 1
+ UPLOAD_RPM: 1
+ ASAN_OPTION: "OFF"
+ TESTING_VERSION_BUILD: 1
+ PULP3_REPO_NAME: framework-testing-x86_64.el7
+ PULP3_DIST_NAME: framework-testing-x86_64.el7
+ artifacts:
+ name: MESA_jump_layer-$CI_COMMIT_REF_NAME-release"
+ paths:
+ - build/*.rpm
+ only:
+ - /^develop.*$/i
+ - /^master.*$/i
+
+release_build_debug:
+ stage: build
+ variables:
+ BUILD_TYPE: Debug
+ PACKAGE: 1
+ UPLOAD_RPM: 1
+ PULP3_REPO_NAME: framework-stable-x86_64.el7
+ PULP3_DIST_NAME: framework-stable-x86_64.el7
+ extends: .build_by_travis
+ artifacts:
+ name: MESA_jump_layer-$CI_COMMIT_REF_NAME-release"
+ paths:
+ - build/*.rpm
+ only:
+ - tags
+
+release_build_release:
+ stage: build
+ variables:
+ BUILD_TYPE: RelWithDebInfo
+ PACKAGE: 1
+ UPLOAD_RPM: 1
+ UPLOAD_SYMBOL_FILES: 1
+ SYMBOL_TARGET: libMESA_jump_layer
+ PULP3_REPO_NAME: framework-stable-x86_64.el7
+ PULP3_DIST_NAME: framework-stable-x86_64.el7
+ extends: .build_by_travis
+ artifacts:
+ name: MESA_jump_layer-$CI_COMMIT_REF_NAME-release"
+ paths:
+ - build/*.rpm
+ only:
+ - tags
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000..fb84b10
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,56 @@
+cmake_minimum_required (VERSION 2.8)
+
+set(lib_name MESA_jump_layer)
+
+project (${lib_name})
+
+set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake)
+include(Version)
+
+set(CMAKE_MACOSX_RPATH 0)
+set(CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} -Wall)
+set(CMAKE_INSTALL_PREFIX /opt/MESA)
+
+set(MESA_SDK_PREFIX "/opt/MESA/")
+include_directories(${CMAKE_SOURCE_DIR}/inc)
+include_directories(${MESA_SDK_PREFIX}/include)
+include_directories(${MESA_SDK_PREFIX}/include/MESA)
+
+#for ASAN
+set(ASAN_OPTION "OFF" CACHE STRING " set asan type chosen by the user, using OFF as default")
+set_property(CACHE ASAN_OPTION PROPERTY STRINGS OFF ADDRESS THREAD)
+message(STATUS "ASAN_OPTION='${ASAN_OPTION}'")
+
+if(ASAN_OPTION MATCHES "ADDRESS")
+ set(CMAKE_C_FLAGS "${CMAKADDRESS} -g -DCMAKE_BUILD_TYPE=Debug -fsanitize=address -fno-omit-frame-pointer")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -DCMAKE_BUILD_TYPE=Debug -fsanitize=address -fno-omit-frame-pointer")
+ set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -lasan")
+ set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -lasan")
+elseif(ASAN_OPTION MATCHES "THREAD")
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -DCMAKE_BUILD_TYPE=Debug -fsanitize=thread -fno-omit-frame-pointer")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -DCMAKE_BUILD_TYPE=Debug -fsanitize=thread -fno-omit-frame-pointer")
+ set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -lasan")
+ set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -lasan")
+endif()
+# end of for ASAN
+
+include_directories(${PROJECT_SOURCE_DIR}/include/)
+
+file(GLOB SRC
+ "src/*.c"
+ "src/*.cpp"
+)
+
+# Shared Library Output
+add_library(${lib_name}_shared SHARED ${SRC})
+target_link_libraries(${lib_name}_shared m)
+if(DEFINED MESA_SHARED_INSTALL_DIR)
+ set_target_properties(${lib_name}_shared PROPERTIES OUTPUT_NAME ${lib_name} LIBRARY_OUTPUT_DIRECTORY ${MESA_SHARED_INSTALL_DIR})
+else()
+ set_target_properties(${lib_name}_shared PROPERTIES OUTPUT_NAME ${lib_name})
+endif()
+
+install(TARGETS ${lib_name}_shared LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/lib COMPONENT LIBRARY)
+install(FILES inc/MESA_jump_layer.h DESTINATION ${CMAKE_INSTALL_PREFIX}/include/MESA COMPONENT HEADER)
+
+include(Package)
diff --git a/autorevision.sh b/autorevision.sh
new file mode 100644
index 0000000..3baa179
--- /dev/null
+++ b/autorevision.sh
@@ -0,0 +1,1268 @@
+#!/bin/sh
+
+# Copyright (c) 2012 - 2016 dak180 and contributors. See
+# https://opensource.org/licenses/mit-license.php or the included
+# COPYING.md for licence terms.
+#
+# autorevision - extracts metadata about the head version from your
+# repository.
+
+# Usage message.
+arUsage() {
+ cat > "/dev/stderr" << EOF
+usage: autorevision {-t output-type | -s symbol} [-o cache-file [-f] ] [-V]
+ Options include:
+ -t output-type = specify output type
+ -s symbol = specify symbol output
+ -o cache-file = specify cache file location
+ -f = force the use of cache data
+ -U = check for untracked files in svn
+ -V = emit version and exit
+ -? = help message
+
+The following are valid output types:
+ clojure = clojure file
+ c = C/C++ file
+ h = Header for use with c/c++
+ hpp = Alternate C++ header strings with namespace
+ ini = INI file
+ java = Java file
+ javaprop = Java properties file
+ js = javascript file
+ json = JSON file
+ lua = Lua file
+ m4 = m4 file
+ matlab = matlab file
+ octave = octave file
+ php = PHP file
+ pl = Perl file
+ py = Python file
+ rpm = rpm file
+ scheme = scheme file
+ sh = Bash sytax
+ swift = Swift file
+ tex = (La)TeX file
+ xcode = Header useful for populating info.plist files
+ cmake = CMake file
+
+
+The following are valid symbols:
+ VCS_TYPE
+ VCS_BASENAME
+ VCS_UUID
+ VCS_NUM
+ VCS_DATE
+ VCS_BRANCH
+ VCS_TAG
+ VCS_TICK
+ VCS_EXTRA
+ VCS_FULL_HASH
+ VCS_SHORT_HASH
+ VCS_WC_MODIFIED
+ VCS_ACTION_STAMP
+EOF
+ exit 1
+}
+
+# Config
+ARVERSION="&&ARVERSION&&"
+TARGETFILE="/dev/stdout"
+while getopts ":t:o:s:VfU" OPTION; do
+ case "${OPTION}" in
+ t)
+ AFILETYPE="${OPTARG}"
+ ;;
+ o)
+ CACHEFILE="${OPTARG}"
+ ;;
+ f)
+ CACHEFORCE="1"
+ ;;
+ s)
+ VAROUT="${OPTARG}"
+ ;;
+ U)
+ UNTRACKEDFILES="1"
+ ;;
+ V)
+ echo "autorevision ${ARVERSION}"
+ exit 0
+ ;;
+ ?)
+ # If an unknown flag is used (or -?):
+ arUsage
+ ;;
+ esac
+done
+
+if [ ! -z "${VAROUT}" ] && [ ! -z "${AFILETYPE}" ]; then
+ # If both -s and -t are specified:
+ echo "error: Improper argument combination." 1>&2
+ exit 1
+elif [ -z "${VAROUT}" ] && [ -z "${AFILETYPE}" ]; then
+ # If neither -s or -t are specified:
+ arUsage
+elif [ -z "${CACHEFILE}" ] && [ "${CACHEFORCE}" = "1" ]; then
+ # If -f is specified without -o:
+ arUsage
+elif [ ! -f "${CACHEFILE}" ] && [ "${CACHEFORCE}" = "1" ]; then
+ # If we are forced to use the cache but it does not exist.
+ echo "error: Cache forced but no cache found." 1>&2
+ exit 1
+fi
+
+# Make sure that the path we are given is one we can source
+# (dash, we are looking at you).
+if [ ! -z "${CACHEFILE}" ] && ! echo "${CACHEFILE}" | grep -q '^\.*/'; then
+ CACHEFILE="./${CACHEFILE}"
+fi
+
+GENERATED_HEADER="Generated by autorevision - do not hand-hack!"
+
+# Functions to extract data from different repo types.
+# For git repos
+# shellcheck disable=SC2039,SC2164,SC2155
+gitRepo() {
+ local oldPath="${PWD}"
+
+ cd "$(git rev-parse --show-toplevel)"
+
+ VCS_TYPE="git"
+
+ VCS_BASENAME="$(basename "${PWD}")"
+
+ VCS_UUID="$(git rev-list --max-parents=0 --date-order --reverse HEAD 2>/dev/null | sed -n 1p)"
+ if [ -z "${VCS_UUID}" ]; then
+ VCS_UUID="$(git rev-list --topo-order HEAD | tail -n 1)"
+ fi
+
+ # Is the working copy clean?
+ test -z "$(git status --untracked-files=normal --porcelain)"
+ VCS_WC_MODIFIED="${?}"
+
+ # Enumeration of changesets
+ VCS_NUM="$(git rev-list --count HEAD 2>/dev/null)"
+ if [ -z "${VCS_NUM}" ]; then
+ echo "warning: Counting the number of revisions may be slower due to an outdated git version less than 1.7.2.3. If something breaks, please update it." 1>&2
+ VCS_NUM="$(git rev-list HEAD | wc -l)"
+ fi
+
+ # This may be a git-svn remote. If so, report the Subversion revision.
+ if [ -z "$(git config svn-remote.svn.url 2>/dev/null)" ]; then
+ # The full revision hash
+ VCS_FULL_HASH="$(git rev-parse HEAD)"
+
+ # The short hash
+ VCS_SHORT_HASH="$(echo "${VCS_FULL_HASH}" | cut -b 1-7)"
+ else
+ # The git-svn revision number
+ VCS_FULL_HASH="$(git svn find-rev HEAD)"
+ VCS_SHORT_HASH="${VCS_FULL_HASH}"
+ fi
+
+ # Current branch
+ VCS_BRANCH="$(git rev-parse --symbolic-full-name --verify "$(git name-rev --name-only --no-undefined HEAD 2>/dev/null)" 2>/dev/null | sed -e 's:refs/heads/::' | sed -e 's:refs/::')"
+
+ # Cache the description
+ local DESCRIPTION="$(git describe --long --tags 2>/dev/null)"
+
+ # Current or last tag ancestor (empty if no tags)
+ VCS_TAG="$(echo "${DESCRIPTION}" | sed -e "s:-g${VCS_SHORT_HASH}\$::" -e 's:-[0-9]*$::')"
+
+ # Distance to last tag or an alias of VCS_NUM if there is no tag
+ if [ ! -z "${DESCRIPTION}" ]; then
+ VCS_TICK="$(echo "${DESCRIPTION}" | sed -e "s:${VCS_TAG}-::" -e "s:-g${VCS_SHORT_HASH}::")"
+ else
+ VCS_TICK="${VCS_NUM}"
+ fi
+
+ # Date of the current commit
+ VCS_DATE="$(TZ=UTC git show -s --date=iso-strict-local --pretty=format:%ad | sed -e 's|+00:00|Z|')"
+ if [ -z "${VCS_DATE}" ]; then
+ echo "warning: Action stamps require git version 2.7+." 1>&2
+ VCS_DATE="$(git log -1 --pretty=format:%ci | sed -e 's: :T:' -e 's: ::' -e 's|+00:00|Z|')"
+ local ASdis="1"
+ fi
+
+ # Action Stamp
+ if [ -z "${ASdis}" ]; then
+ VCS_ACTION_STAMP="${VCS_DATE}!$(git show -s --pretty=format:%cE)"
+ else
+ VCS_ACTION_STAMP=""
+ fi
+
+ cd "${oldPath}"
+}
+
+# For hg repos
+# shellcheck disable=SC2039,SC2164
+hgRepo() {
+ local oldPath="${PWD}"
+
+ cd "$(hg root)"
+
+ VCS_TYPE="hg"
+
+ VCS_BASENAME="$(basename "${PWD}")"
+
+ VCS_UUID="$(hg log -r "0" -l 1 --template '{node}\n')"
+
+ # Is the working copy clean?
+ test -z "$(hg status -duram)"
+ VCS_WC_MODIFIED="${?}"
+
+ # Enumeration of changesets
+ VCS_NUM="$(hg id -n | tr -d '+')"
+
+ # The full revision hash
+ VCS_FULL_HASH="$(hg log -r "${VCS_NUM}" -l 1 --template '{node}\n')"
+
+ # The short hash
+ VCS_SHORT_HASH="$(hg id -i | tr -d '+')"
+
+ # Current bookmark (bookmarks are roughly equivalent to git's branches)
+ # or branch if no bookmark
+ VCS_BRANCH="$(hg id -B | cut -d ' ' -f 1)"
+ # Fall back to the branch if there are no bookmarks
+ if [ -z "${VCS_BRANCH}" ]; then
+ VCS_BRANCH="$(hg id -b)"
+ fi
+
+ # Current or last tag ancestor (excluding auto tags, empty if no tags)
+ VCS_TAG="$(hg log -r "${VCS_NUM}" -l 1 --template '{latesttag}\n' 2>/dev/null | sed -e 's:qtip::' -e 's:tip::' -e 's:qbase::' -e 's:qparent::' -e "s:$(hg --config 'extensions.color=' --config 'extensions.mq=' --color never qtop 2>/dev/null)::" | cut -d ' ' -f 1)"
+
+ # Distance to last tag or an alias of VCS_NUM if there is no tag
+ if [ ! -z "${VCS_TAG}" ]; then
+ VCS_TICK="$(hg log -r "${VCS_NUM}" -l 1 --template '{latesttagdistance}\n' 2>/dev/null)"
+ else
+ VCS_TICK="${VCS_NUM}"
+ fi
+
+ # Date of the current commit
+ VCS_DATE="$(hg log -r "${VCS_NUM}" -l 1 --template '{date|isodatesec}\n' 2>/dev/null | sed -e 's: :T:' -e 's: ::' -e 's|+00:00|Z|')"
+
+ # Action Stamp
+ VCS_ACTION_STAMP="$(TZ=UTC hg log -r "${VCS_NUM}" -l 1 --template '{date|localdate|rfc3339date}\n' 2>/dev/null | sed -e 's|+00:00|Z|')!$(hg log -r "${VCS_NUM}" -l 1 --template '{author|email}\n' 2>/dev/null)"
+
+ cd "${oldPath}"
+}
+
+# For bzr repos
+# shellcheck disable=SC2039,SC2164
+bzrRepo() {
+ local oldPath="${PWD}"
+
+ cd "$(bzr root)"
+
+ VCS_TYPE="bzr"
+
+ VCS_BASENAME="$(basename "${PWD}")"
+
+ # Currently unimplemented because more investigation is needed.
+ VCS_UUID=""
+
+ # Is the working copy clean?
+ bzr version-info --custom --template='{clean}\n' | grep -q '1'
+ VCS_WC_MODIFIED="${?}"
+
+ # Enumeration of changesets
+ VCS_NUM="$(bzr revno)"
+
+ # The full revision hash
+ VCS_FULL_HASH="$(bzr version-info --custom --template='{revision_id}\n')"
+
+ # The short hash
+ VCS_SHORT_HASH="${VCS_NUM}"
+
+ # Nick of the current branch
+ VCS_BRANCH="$(bzr nick)"
+
+ # Current or last tag ancestor (excluding auto tags, empty if no tags)
+ VCS_TAG="$(bzr tags --sort=time | sed '/?$/d' | tail -n1 | cut -d ' ' -f1)"
+
+ # Distance to last tag or an alias of VCS_NUM if there is no tag
+ if [ ! -z "${VCS_TAG}" ]; then
+ VCS_TICK="$(bzr log --line -r "tag:${VCS_TAG}.." | tail -n +2 | wc -l | sed -e 's:^ *::')"
+ else
+ VCS_TICK="${VCS_NUM}"
+ fi
+
+ # Date of the current commit
+ VCS_DATE="$(bzr version-info --custom --template='{date}\n' | sed -e 's: :T:' -e 's: ::')"
+
+ # Action Stamp
+ # Currently unimplemented because more investigation is needed.
+ VCS_ACTION_STAMP=""
+
+ cd "${oldPath}"
+}
+
+# For svn repos
+# shellcheck disable=SC2039,SC2164,SC2155
+svnRepo() {
+ local oldPath="${PWD}"
+
+ VCS_TYPE="svn"
+
+ case "${PWD}" in
+ /*trunk*|/*branches*|/*tags*)
+ local fn="${PWD}"
+ while [ "$(basename "${fn}")" != 'trunk' ] && [ "$(basename "${fn}")" != 'branches' ] && [ "$(basename "${fn}")" != 'tags' ] && [ "$(basename "${fn}")" != '/' ]; do
+ local fn="$(dirname "${fn}")"
+ done
+ local fn="$(dirname "${fn}")"
+ if [ "${fn}" = '/' ]; then
+ VCS_BASENAME="$(basename "${PWD}")"
+ else
+ VCS_BASENAME="$(basename "${fn}")"
+ fi
+ ;;
+ *) VCS_BASENAME="$(basename "${PWD}")" ;;
+ esac
+
+ VCS_UUID="$(svn info --xml | sed -n -e 's:<uuid>::' -e 's:</uuid>::p')"
+
+ # Cache svnversion output
+ local SVNVERSION="$(svnversion)"
+
+ # Is the working copy clean?
+ echo "${SVNVERSION}" | grep -q "M"
+ case "${?}" in
+ 0)
+ VCS_WC_MODIFIED="1"
+ ;;
+ 1)
+ if [ ! -z "${UNTRACKEDFILES}" ]; then
+ # `svnversion` does not detect untracked files and `svn status` is really slow, so only run it if we really have to.
+ if [ -z "$(svn status)" ]; then
+ VCS_WC_MODIFIED="0"
+ else
+ VCS_WC_MODIFIED="1"
+ fi
+ else
+ VCS_WC_MODIFIED="0"
+ fi
+ ;;
+ esac
+
+ # Enumeration of changesets
+ VCS_NUM="$(echo "${SVNVERSION}" | cut -d : -f 1 | sed -e 's:M::' -e 's:S::' -e 's:P::')"
+
+ # The full revision hash
+ VCS_FULL_HASH="${SVNVERSION}"
+
+ # The short hash
+ VCS_SHORT_HASH="${VCS_NUM}"
+
+ # Current branch
+ case "${PWD}" in
+ /*trunk*|/*branches*|/*tags*)
+ local lastbase=""
+ local fn="${PWD}"
+ while :
+ do
+ base="$(basename "${fn}")"
+ if [ "${base}" = 'trunk' ]; then
+ VCS_BRANCH='trunk'
+ break
+ elif [ "${base}" = 'branches' ] || [ "${base}" = 'tags' ]; then
+ VCS_BRANCH="${lastbase}"
+ break
+ elif [ "${base}" = '/' ]; then
+ VCS_BRANCH=""
+ break
+ fi
+ local lastbase="${base}"
+ local fn="$(dirname "${fn}")"
+ done
+ ;;
+ *) VCS_BRANCH="" ;;
+ esac
+
+ # Current or last tag ancestor (empty if no tags). But "current
+ # tag" can't be extracted reliably because Subversion doesn't
+ # have tags the way other VCSes do.
+ VCS_TAG=""
+ VCS_TICK=""
+
+ # Date of the current commit
+ VCS_DATE="$(svn info --xml | sed -n -e 's:<date>::' -e 's:</date>::p')"
+
+ # Action Stamp
+ VCS_ACTION_STAMP="${VCS_DATE}!$(svn log --xml -l 1 -r "${VCS_SHORT_HASH}" | sed -n -e 's:<author>::' -e 's:</author>::p')"
+
+ cd "${oldPath}"
+}
+
+
+# Functions to output data in different formats.
+# For bash output
+shOutput() {
+ cat > "${TARGETFILE}" << EOF
+# ${GENERATED_HEADER}
+
+VCS_TYPE="${VCS_TYPE}"
+VCS_BASENAME="${VCS_BASENAME}"
+VCS_UUID="${VCS_UUID}"
+VCS_NUM="${VCS_NUM}"
+VCS_DATE="${VCS_DATE}"
+VCS_BRANCH="${VCS_BRANCH}"
+VCS_TAG="${VCS_TAG}"
+VCS_TICK="${VCS_TICK}"
+VCS_EXTRA="${VCS_EXTRA}"
+
+VCS_ACTION_STAMP="${VCS_ACTION_STAMP}"
+VCS_FULL_HASH="${VCS_FULL_HASH}"
+VCS_SHORT_HASH="${VCS_SHORT_HASH}"
+
+VCS_WC_MODIFIED="${VCS_WC_MODIFIED}"
+
+# end
+EOF
+}
+
+# For source C output
+cOutput() {
+ cat > "${TARGETFILE}" << EOF
+/* ${GENERATED_HEADER} */
+
+const char *VCS_TYPE = "${VCS_TYPE}";
+const char *VCS_BASENAME = "${VCS_BASENAME}";
+const char *VCS_UUID = "${VCS_UUID}";
+const int VCS_NUM = ${VCS_NUM};
+const char *VCS_DATE = "${VCS_DATE}";
+const char *VCS_BRANCH = "${VCS_BRANCH}";
+const char *VCS_TAG = "${VCS_TAG}";
+const int VCS_TICK = ${VCS_TICK};
+const char *VCS_EXTRA = "${VCS_EXTRA}";
+
+const char *VCS_ACTION_STAMP = "${VCS_ACTION_STAMP}";
+const char *VCS_FULL_HASH = "${VCS_FULL_HASH}";
+const char *VCS_SHORT_HASH = "${VCS_SHORT_HASH}";
+
+const int VCS_WC_MODIFIED = ${VCS_WC_MODIFIED};
+
+/* end */
+EOF
+}
+
+# For header output
+hOutput() {
+ cat > "${TARGETFILE}" << EOF
+/* ${GENERATED_HEADER} */
+#ifndef AUTOREVISION_H
+#define AUTOREVISION_H
+
+#define VCS_TYPE "${VCS_TYPE}"
+#define VCS_BASENAME "${VCS_BASENAME}"
+#define VCS_UUID "${VCS_UUID}"
+#define VCS_NUM ${VCS_NUM}
+#define VCS_DATE "${VCS_DATE}"
+#define VCS_BRANCH "${VCS_BRANCH}"
+#define VCS_TAG "${VCS_TAG}"
+#define VCS_TICK ${VCS_TICK}
+#define VCS_EXTRA "${VCS_EXTRA}"
+
+#define VCS_ACTION_STAMP "${VCS_ACTION_STAMP}"
+#define VCS_FULL_HASH "${VCS_FULL_HASH}"
+#define VCS_SHORT_HASH "${VCS_SHORT_HASH}"
+
+#define VCS_WC_MODIFIED ${VCS_WC_MODIFIED}
+
+#endif
+
+/* end */
+EOF
+}
+
+# A header output for use with xcode to populate info.plist strings
+xcodeOutput() {
+ cat > "${TARGETFILE}" << EOF
+/* ${GENERATED_HEADER} */
+#ifndef AUTOREVISION_H
+#define AUTOREVISION_H
+
+#define VCS_TYPE ${VCS_TYPE}
+#define VCS_BASENAME ${VCS_BASENAME}
+#define VCS_UUID ${VCS_UUID}
+#define VCS_NUM ${VCS_NUM}
+#define VCS_DATE ${VCS_DATE}
+#define VCS_BRANCH ${VCS_BRANCH}
+#define VCS_TAG ${VCS_TAG}
+#define VCS_TICK ${VCS_TICK}
+#define VCS_EXTRA ${VCS_EXTRA}
+
+#define VCS_ACTION_STAMP ${VCS_ACTION_STAMP}
+#define VCS_FULL_HASH ${VCS_FULL_HASH}
+#define VCS_SHORT_HASH ${VCS_SHORT_HASH}
+
+#define VCS_WC_MODIFIED ${VCS_WC_MODIFIED}
+
+#endif
+
+/* end */
+EOF
+}
+
+# For Swift output
+swiftOutput() {
+ case "${VCS_WC_MODIFIED}" in
+ 0) VCS_WC_MODIFIED="false" ;;
+ 1) VCS_WC_MODIFIED="true" ;;
+ esac
+ # For values that may not exist depending on the type of repo we
+ # have read from, set them to `nil` when they are empty.
+ if [ -z "${VCS_UUID}" ]; then
+ VCS_UUID="nil"
+ else
+ VCS_UUID="\"${VCS_UUID}\""
+ fi
+ if [ -z "${VCS_TAG}" ]; then
+ VCS_TAG="nil"
+ else
+ VCS_TAG="\"${VCS_TAG}\""
+ fi
+ : "${VCS_TICK:="nil"}"
+ if [ -z "${VCS_EXTRA}" ]; then
+ VCS_EXTRA="nil"
+ else
+ VCS_EXTRA="\"${VCS_EXTRA}\""
+ fi
+ if [ -z "${VCS_ACTION_STAMP}" ]; then
+ VCS_ACTION_STAMP="nil"
+ else
+ VCS_ACTION_STAMP="\"${VCS_ACTION_STAMP}\""
+ fi
+ cat > "${TARGETFILE}" << EOF
+/* ${GENERATED_HEADER} */
+
+let VCS_TYPE = "${VCS_TYPE}"
+let VCS_BASENAME = "${VCS_BASENAME}"
+let VCS_UUID: String? = ${VCS_UUID}
+let VCS_NUM: Int = ${VCS_NUM}
+let VCS_DATE = "${VCS_DATE}"
+let VCS_BRANCH: String = "${VCS_BRANCH}"
+let VCS_TAG: String? = ${VCS_TAG}
+let VCS_TICK: Int? = ${VCS_TICK}
+let VCS_EXTRA: String? = ${VCS_EXTRA}
+
+let VCS_ACTION_STAMP: String? = ${VCS_ACTION_STAMP}
+let VCS_FULL_HASH: String = "${VCS_FULL_HASH}"
+let VCS_SHORT_HASH: String = "${VCS_SHORT_HASH}"
+
+let VCS_WC_MODIFIED: Bool = ${VCS_WC_MODIFIED}
+
+/* end */
+EOF
+}
+
+# For Python output
+pyOutput() {
+ case "${VCS_WC_MODIFIED}" in
+ 0) VCS_WC_MODIFIED="False" ;;
+ 1) VCS_WC_MODIFIED="True" ;;
+ esac
+ cat > "${TARGETFILE}" << EOF
+# ${GENERATED_HEADER}
+
+VCS_TYPE = "${VCS_TYPE}"
+VCS_BASENAME = "${VCS_BASENAME}"
+VCS_UUID = "${VCS_UUID}"
+VCS_NUM = ${VCS_NUM}
+VCS_DATE = "${VCS_DATE}"
+VCS_BRANCH = "${VCS_BRANCH}"
+VCS_TAG = "${VCS_TAG}"
+VCS_TICK = ${VCS_TICK}
+VCS_EXTRA = "${VCS_EXTRA}"
+
+VCS_ACTION_STAMP = "${VCS_ACTION_STAMP}"
+VCS_FULL_HASH = "${VCS_FULL_HASH}"
+VCS_SHORT_HASH = "${VCS_SHORT_HASH}"
+
+VCS_WC_MODIFIED = ${VCS_WC_MODIFIED}
+
+# end
+EOF
+}
+
+# For Perl output
+plOutput() {
+ cat << EOF
+# ${GENERATED_HEADER}
+
+\$VCS_TYPE = '${VCS_TYPE}';
+\$VCS_BASENAME = '${VCS_BASENAME}';
+\$VCS_UUID = '${VCS_UUID}';
+\$VCS_NUM = ${VCS_NUM};
+\$VCS_DATE = '${VCS_DATE}';
+\$VCS_BRANCH = '${VCS_BRANCH}';
+\$VCS_TAG = '${VCS_TAG}';
+\$VCS_TICK = ${VCS_TICK};
+\$VCS_EXTRA = '${VCS_EXTRA}';
+
+\$VCS_ACTION_STAMP = '${VCS_ACTION_STAMP}';
+\$VCS_FULL_HASH = '${VCS_FULL_HASH}';
+\$VCS_SHORT_HASH = '${VCS_SHORT_HASH}';
+
+\$VCS_WC_MODIFIED = ${VCS_WC_MODIFIED};
+
+# end
+1;
+EOF
+}
+
+# For lua output
+luaOutput() {
+ case "${VCS_WC_MODIFIED}" in
+ 0) VCS_WC_MODIFIED="false" ;;
+ 1) VCS_WC_MODIFIED="true" ;;
+ esac
+ cat > "${TARGETFILE}" << EOF
+-- ${GENERATED_HEADER}
+
+VCS_TYPE = "${VCS_TYPE}"
+VCS_BASENAME = "${VCS_BASENAME}"
+VCS_UUID = "${VCS_UUID}"
+VCS_NUM = ${VCS_NUM}
+VCS_DATE = "${VCS_DATE}"
+VCS_BRANCH = "${VCS_BRANCH}"
+VCS_TAG = "${VCS_TAG}"
+VCS_TICK = ${VCS_TICK}
+VCS_EXTRA = "${VCS_EXTRA}"
+
+VCS_ACTION_STAMP = "${VCS_ACTION_STAMP}"
+VCS_FULL_HASH = "${VCS_FULL_HASH}"
+VCS_SHORT_HASH = "${VCS_SHORT_HASH}"
+
+VCS_WC_MODIFIED = ${VCS_WC_MODIFIED}
+
+-- end
+EOF
+}
+
+# For php output
+phpOutput() {
+ case "${VCS_WC_MODIFIED}" in
+ 0) VCS_WC_MODIFIED="false" ;;
+ 1) VCS_WC_MODIFIED="true" ;;
+ esac
+ cat > "${TARGETFILE}" << EOF
+<?php
+# ${GENERATED_HEADER}
+
+return array(
+ "VCS_TYPE" => "${VCS_TYPE}",
+ "VCS_BASENAME" => "${VCS_BASENAME}",
+ "VCS_UUID" => "${VCS_UUID}",
+ "VCS_NUM" => ${VCS_NUM},
+ "VCS_DATE" => "${VCS_DATE}",
+ "VCS_BRANCH" => "${VCS_BRANCH}",
+ "VCS_TAG" => "${VCS_TAG}",
+ "VCS_TICK" => ${VCS_TICK},
+ "VCS_EXTRA" => "${VCS_EXTRA}",
+ "VCS_ACTION_STAMP" => "${VCS_ACTION_STAMP}",
+ "VCS_FULL_HASH" => "${VCS_FULL_HASH}",
+ "VCS_SHORT_HASH" => "${VCS_SHORT_HASH}",
+ "VCS_WC_MODIFIED" => ${VCS_WC_MODIFIED}
+);
+
+# end
+?>
+EOF
+}
+
+# For ini output
+iniOutput() {
+ case "${VCS_WC_MODIFIED}" in
+ 0) VCS_WC_MODIFIED="false" ;;
+ 1) VCS_WC_MODIFIED="true" ;;
+ esac
+ cat > "${TARGETFILE}" << EOF
+; ${GENERATED_HEADER}
+[VCS]
+VCS_TYPE = "${VCS_TYPE}"
+VCS_BASENAME = "${VCS_BASENAME}"
+VCS_UUID = "${VCS_UUID}"
+VCS_NUM = ${VCS_NUM}
+VCS_DATE = "${VCS_DATE}"
+VCS_BRANCH = "${VCS_BRANCH}"
+VCS_TAG = "${VCS_TAG}"
+VCS_TICK = ${VCS_TICK}
+VCS_EXTRA = "${VCS_EXTRA}"
+VCS_ACTION_STAMP = "${VCS_ACTION_STAMP}"
+VCS_FULL_HASH = "${VCS_FULL_HASH}"
+VCS_SHORT_HASH = "${VCS_SHORT_HASH}"
+VCS_WC_MODIFIED = ${VCS_WC_MODIFIED}
+; end
+EOF
+}
+
+# For javascript output
+jsOutput() {
+ case "${VCS_WC_MODIFIED}" in
+ 1) VCS_WC_MODIFIED="true" ;;
+ 0) VCS_WC_MODIFIED="false" ;;
+ esac
+ cat > "${TARGETFILE}" << EOF
+/** ${GENERATED_HEADER} */
+
+var autorevision = {
+ VCS_TYPE: "${VCS_TYPE}",
+ VCS_BASENAME: "${VCS_BASENAME}",
+ VCS_UUID: "${VCS_UUID}",
+ VCS_NUM: ${VCS_NUM},
+ VCS_DATE: "${VCS_DATE}",
+ VCS_BRANCH: "${VCS_BRANCH}",
+ VCS_TAG: "${VCS_TAG}",
+ VCS_TICK: ${VCS_TICK},
+ VCS_EXTRA: "${VCS_EXTRA}",
+
+ VCS_ACTION_STAMP: "${VCS_ACTION_STAMP}",
+ VCS_FULL_HASH: "${VCS_FULL_HASH}",
+ VCS_SHORT_HASH: "${VCS_SHORT_HASH}",
+
+ VCS_WC_MODIFIED: ${VCS_WC_MODIFIED}
+};
+
+/** Node.js compatibility */
+if (typeof module !== 'undefined') {
+ module.exports = autorevision;
+}
+
+/** end */
+EOF
+}
+
+# For JSON output
+jsonOutput() {
+ case "${VCS_WC_MODIFIED}" in
+ 1) VCS_WC_MODIFIED="true" ;;
+ 0) VCS_WC_MODIFIED="false" ;;
+ esac
+ cat > "${TARGETFILE}" << EOF
+{
+ "_comment": "${GENERATED_HEADER}",
+ "VCS_TYPE": "${VCS_TYPE}",
+ "VCS_BASENAME": "${VCS_BASENAME}",
+ "VCS_UUID": "${VCS_UUID}",
+ "VCS_NUM": ${VCS_NUM},
+ "VCS_DATE": "${VCS_DATE}",
+ "VCS_BRANCH":"${VCS_BRANCH}",
+ "VCS_TAG": "${VCS_TAG}",
+ "VCS_TICK": ${VCS_TICK},
+ "VCS_EXTRA": "${VCS_EXTRA}",
+
+ "VCS_ACTION_STAMP": "${VCS_ACTION_STAMP}",
+ "VCS_FULL_HASH": "${VCS_FULL_HASH}",
+ "VCS_SHORT_HASH": "${VCS_SHORT_HASH}",
+
+ "VCS_WC_MODIFIED": ${VCS_WC_MODIFIED}
+}
+EOF
+}
+
+# For Java output
+javaOutput() {
+ case "${VCS_WC_MODIFIED}" in
+ 1) VCS_WC_MODIFIED="true" ;;
+ 0) VCS_WC_MODIFIED="false" ;;
+ esac
+ cat > "${TARGETFILE}" << EOF
+/* ${GENERATED_HEADER} */
+
+public class autorevision {
+ public static final String VCS_TYPE = "${VCS_TYPE}";
+ public static final String VCS_BASENAME = "${VCS_BASENAME}";
+ public static final String VCS_UUID = "${VCS_UUID}";
+ public static final long VCS_NUM = ${VCS_NUM};
+ public static final String VCS_DATE = "${VCS_DATE}";
+ public static final String VCS_BRANCH = "${VCS_BRANCH}";
+ public static final String VCS_TAG = "${VCS_TAG}";
+ public static final long VCS_TICK = ${VCS_TICK};
+ public static final String VCS_EXTRA = "${VCS_EXTRA}";
+
+ public static final String VCS_ACTION_STAMP = "${VCS_ACTION_STAMP}";
+ public static final String VCS_FULL_HASH = "${VCS_FULL_HASH}";
+ public static final String VCS_SHORT_HASH = "${VCS_SHORT_HASH}";
+
+ public static final boolean VCS_WC_MODIFIED = ${VCS_WC_MODIFIED};
+}
+EOF
+}
+
+# For Java properties output
+javapropOutput() {
+ case "${VCS_WC_MODIFIED}" in
+ 1) VCS_WC_MODIFIED="true" ;;
+ 0) VCS_WC_MODIFIED="false" ;;
+ esac
+ cat > "${TARGETFILE}" << EOF
+# ${GENERATED_HEADER}
+
+VCS_TYPE=${VCS_TYPE}
+VCS_BASENAME=${VCS_BASENAME}
+VCS_UUID=${VCS_UUID}
+VCS_NUM=${VCS_NUM}
+VCS_DATE=${VCS_DATE}
+VCS_BRANCH=${VCS_BRANCH}
+VCS_TAG=${VCS_TAG}
+VCS_TICK=${VCS_TICK}
+VCS_EXTRA=${VCS_EXTRA}
+
+VCS_ACTION_STAMP=${VCS_ACTION_STAMP}
+VCS_FULL_HASH=${VCS_FULL_HASH}
+VCS_SHORT_HASH=${VCS_SHORT_HASH}
+
+VCS_WC_MODIFIED=${VCS_WC_MODIFIED}
+EOF
+}
+
+# For m4 output
+m4Output() {
+ cat > "${TARGETFILE}" << EOF
+dnl ${GENERATED_HEADER}
+define(\`VCS_TYPE', \`${VCS_TYPE}')dnl
+define(\`VCS_BASENAME', \`${VCS_BASENAME}')dnl
+define(\`VCS_UUID', \`${VCS_UUID}')dnl
+define(\`VCS_NUM', \`${VCS_NUM}')dnl
+define(\`VCS_DATE', \`${VCS_DATE}')dnl
+define(\`VCS_BRANCH', \`${VCS_BRANCH}')dnl
+define(\`VCS_TAG', \`${VCS_TAG}')dnl
+define(\`VCS_TICK', \`${VCS_TICK}')dnl
+define(\`VCS_EXTRA', \`${VCS_EXTRA}')dnl
+define(\`VCS_ACTIONSTAMP', \`${VCS_ACTION_STAMP}')dnl
+define(\`VCS_FULLHASH', \`${VCS_FULL_HASH}')dnl
+define(\`VCS_SHORTHASH', \`${VCS_SHORT_HASH}')dnl
+define(\`VCS_WC_MODIFIED', \`${VCS_WC_MODIFIED}')dnl
+EOF
+}
+
+# For (La)TeX output
+texOutput() {
+ case "${VCS_WC_MODIFIED}" in
+ 0) VCS_WC_MODIFIED="false" ;;
+ 1) VCS_WC_MODIFIED="true" ;;
+ esac
+ cat > "${TARGETFILE}" << EOF
+% ${GENERATED_HEADER}
+\def \vcsType {${VCS_TYPE}}
+\def \vcsBasename {${VCS_BASENAME}}
+\def \vcsUUID {${VCS_UUID}}
+\def \vcsNum {${VCS_NUM}}
+\def \vcsDate {${VCS_DATE}}
+\def \vcsBranch {${VCS_BRANCH}}
+\def \vcsTag {${VCS_TAG}}
+\def \vcsTick {${VCS_TICK}}
+\def \vcsExtra {${VCS_EXTRA}}
+\def \vcsACTIONSTAMP {${VCS_ACTION_STAMP}}
+\def \vcsFullHash {${VCS_FULL_HASH}}
+\def \vcsShortHash {${VCS_SHORT_HASH}}
+\def \vcsWCModified {${VCS_WC_MODIFIED}}
+\endinput
+EOF
+}
+
+# For scheme output
+schemeOutput() {
+ case "${VCS_WC_MODIFIED}" in
+ 0) VCS_WC_MODIFIED="#f" ;;
+ 1) VCS_WC_MODIFIED="#t" ;;
+ esac
+ cat > "${TARGETFILE}" << EOF
+;; ${GENERATED_HEADER}
+(define VCS_TYPE "${VCS_TYPE}")
+(define VCS_BASENAME "${VCS_BASENAME}")
+(define VCS_UUID "${VCS_UUID}")
+(define VCS_NUM ${VCS_NUM})
+(define VCS_DATE "${VCS_DATE}")
+(define VCS_BRANCH "${VCS_BRANCH}")
+(define VCS_TAG "${VCS_TAG}")
+(define VCS_TICK ${VCS_TICK})
+(define VCS_EXTRA "${VCS_EXTRA}")
+
+(define VCS_ACTION_STAMP "${VCS_ACTION_STAMP}")
+(define VCS_FULL_HASH "${VCS_FULL_HASH}")
+(define VCS_SHORT_HASH "${VCS_SHORT_HASH}")
+
+(define VCS_WC_MODIFIED ${VCS_WC_MODIFIED})
+;; end
+EOF
+}
+
+# For clojure output
+clojureOutput() {
+ case "${VCS_WC_MODIFIED}" in
+ 0) VCS_WC_MODIFIED="false" ;;
+ 1) VCS_WC_MODIFIED="true" ;;
+ esac
+ cat > "${TARGETFILE}" << EOF
+;; ${GENERATED_HEADER}
+(def VCS_TYPE "${VCS_TYPE}")
+(def VCS_BASENAME "${VCS_BASENAME}")
+(def VCS_UUID "${VCS_UUID}")
+(def VCS_NUM ${VCS_NUM})
+(def VCS_DATE "${VCS_DATE}")
+(def VCS_BRANCH "${VCS_BRANCH}")
+(def VCS_TAG "${VCS_TAG}")
+(def VCS_TICK ${VCS_TICK})
+(def VCS_EXTRA "${VCS_EXTRA}")
+
+(def VCS_ACTION_STAMP "${VCS_ACTION_STAMP}")
+(def VCS_FULL_HASH "${VCS_FULL_HASH}")
+(def VCS_SHORT_HASH "${VCS_SHORT_HASH}")
+
+(def VCS_WC_MODIFIED ${VCS_WC_MODIFIED})
+;; end
+EOF
+}
+
+# For rpm spec file output
+rpmOutput() {
+ cat > "${TARGETFILE}" << EOF
+# ${GENERATED_HEADER}
+$([ "${VCS_TYPE}" ] && echo "%define vcs_type ${VCS_TYPE}")
+$([ "${VCS_BASENAME}" ] && echo "%define vcs_basename ${VCS_BASENAME}")
+$([ "${VCS_UUID}" ] && echo "%define vcs_uuid ${VCS_UUID}")
+$([ "${VCS_NUM}" ] && echo "%define vcs_num ${VCS_NUM}")
+$([ "${VCS_DATE}" ] && echo "%define vcs_date ${VCS_DATE}")
+$([ "${VCS_BRANCH}" ] && echo "%define vcs_branch ${VCS_BRANCH}")
+$([ "${VCS_TAG}" ] && echo "%define vcs_tag ${VCS_TAG}")
+$([ "${VCS_TICK}" ] && echo "%define vcs_tick ${VCS_TICK}")
+$([ "${VCS_EXTRA}" ] && echo "%define vcs_extra ${VCS_EXTRA}")
+
+$([ "${VCS_ACTION_STAMP}" ] && echo "%define vcs_action_stamp ${VCS_ACTION_STAMP}")
+$([ "${VCS_FULL_HASH}" ] && echo "%define vcs_full_hash ${VCS_FULL_HASH}")
+$([ "${VCS_SHORT_HASH}" ] && echo "%define vcs_short_hash ${VCS_SHORT_HASH}")
+
+$([ "${VCS_WC_MODIFIED}" ] && echo "%define vcs_wc_modified ${VCS_WC_MODIFIED}")
+# end
+EOF
+}
+
+# shellcheck disable=SC2155,SC2039
+hppOutput() {
+ local NAMESPACE="$(echo "${VCS_BASENAME}" | sed -e 's:_::g' | tr '[:lower:]' '[:upper:]')"
+ cat > "${TARGETFILE}" << EOF
+/* ${GENERATED_HEADER} */
+
+#ifndef ${NAMESPACE}_AUTOREVISION_H
+#define ${NAMESPACE}_AUTOREVISION_H
+
+#include <string>
+
+namespace $(echo "${NAMESPACE}" | tr '[:upper:]' '[:lower:]')
+{
+ const std::string VCS_TYPE = "${VCS_TYPE}";
+ const std::string VCS_BASENAME = "${VCS_BASENAME}";
+ const std::string VCS_UUID = "${VCS_UUID}";
+ const int VCS_NUM = ${VCS_NUM};
+ const std::string VCS_DATE = "${VCS_DATE}";
+ const std::string VCS_BRANCH = "${VCS_BRANCH}";
+ const std::string VCS_TAG = "${VCS_TAG}";
+ const int VCS_TICK = ${VCS_TICK};
+ const std::string VCS_EXTRA = "${VCS_EXTRA}";
+
+ const std::string VCS_ACTION_STAMP = "${VCS_ACTION_STAMP}";
+ const std::string VCS_FULL_HASH = "${VCS_FULL_HASH}";
+ const std::string VCS_SHORT_HASH = "${VCS_SHORT_HASH}";
+
+ const int VCS_WC_MODIFIED = ${VCS_WC_MODIFIED};
+}
+
+#endif
+
+/* end */
+EOF
+}
+
+matlabOutput() {
+ case "${VCS_WC_MODIFIED}" in
+ 0) VCS_WC_MODIFIED="FALSE" ;;
+ 1) VCS_WC_MODIFIED="TRUE" ;;
+ esac
+ cat > "${TARGETFILE}" << EOF
+% ${GENERATED_HEADER}
+
+VCS_TYPE = '${VCS_TYPE}';
+VCS_BASENAME = '${VCS_BASENAME}';
+VCS_UUID = '${VCS_UUID}';
+VCS_NUM = ${VCS_NUM};
+VCS_DATE = '${VCS_DATE}';
+VCS_BRANCH = '${VCS_BRANCH}';
+VCS_TAG = '${VCS_TAG}';
+VCS_TICK = ${VCS_TICK};
+VCS_EXTRA = '${VCS_EXTRA}';
+
+VCS_ACTION_STAMP = '${VCS_ACTION_STAMP}';
+VCS_FULL_HASH = '${VCS_FULL_HASH}';
+VCS_SHORT_HASH = '${VCS_SHORT_HASH}';
+
+VCS_WC_MODIFIED = ${VCS_WC_MODIFIED};
+
+% end
+EOF
+}
+
+octaveOutput() {
+ cat > "${TARGETFILE}" << EOF
+% ${GENERATED_HEADER}
+
+VCS_TYPE = '${VCS_TYPE}';
+VCS_BASENAME = '${VCS_BASENAME}';
+VCS_UUID = '${VCS_UUID}';
+VCS_NUM = ${VCS_NUM};
+VCS_DATE = '${VCS_DATE}';
+VCS_BRANCH = '${VCS_BRANCH}';
+VCS_TAG = '${VCS_TAG}';
+VCS_TICK = ${VCS_TICK};
+VCS_EXTRA = '${VCS_EXTRA}';
+
+VCS_ACTION_STAMP = '${VCS_ACTION_STAMP}';
+VCS_FULL_HASH = '${VCS_FULL_HASH}';
+VCS_SHORT_HASH = '${VCS_SHORT_HASH}';
+
+VCS_WC_MODIFIED = ${VCS_WC_MODIFIED};
+
+% end
+EOF
+}
+
+cmakeOutput() {
+ cat > "${TARGETFILE}" << EOF
+# ${GENERATED_HEADER}
+
+set(VCS_TYPE ${VCS_TYPE})
+set(VCS_BASENAME ${VCS_BASENAME})
+set(VCS_UUID ${VCS_UUID})
+set(VCS_NUM ${VCS_NUM})
+set(VCS_DATE ${VCS_DATE})
+set(VCS_BRANCH ${VCS_BRANCH})
+set(VCS_TAG ${VCS_TAG})
+set(VCS_TICK ${VCS_TICK})
+set(VCS_EXTRA ${VCS_EXTRA})
+
+set(VCS_ACTION_STAMP ${VCS_ACTION_STAMP})
+set(VCS_FULL_HASH ${VCS_FULL_HASH})
+set(VCS_SHORT_HASH ${VCS_SHORT_HASH})
+
+set(VCS_WC_MODIFIED ${VCS_WC_MODIFIED})
+
+# end
+EOF
+}
+
+
+# Helper functions
+# Count path segments
+# shellcheck disable=SC2039
+pathSegment() {
+ local pathz="${1}"
+ local depth="0"
+
+ if [ ! -z "${pathz}" ]; then
+ # Continue until we are at / or there are no path separators left.
+ while [ ! "${pathz}" = "/" ] && [ ! "${pathz}" = "$(echo "${pathz}" | sed -e 's:/::')" ]; do
+ pathz="$(dirname "${pathz}")"
+ depth="$((depth+1))"
+ done
+ fi
+ echo "${depth}"
+}
+
+# Largest of four numbers
+# shellcheck disable=SC2039
+multiCompare() {
+ local larger="${1}"
+ local numA="${2}"
+ local numB="${3}"
+ local numC="${4}"
+
+ [ "${numA}" -gt "${larger}" ] && larger="${numA}"
+ [ "${numB}" -gt "${larger}" ] && larger="${numB}"
+ [ "${numC}" -gt "${larger}" ] && larger="${numC}"
+ echo "${larger}"
+}
+
+# Test for repositories
+# shellcheck disable=SC2155,SC2039
+repoTest() {
+ REPONUM="0"
+ if [ ! -z "$(git rev-parse HEAD 2>/dev/null)" ]; then
+ local gitPath="$(git rev-parse --show-toplevel)"
+ local gitDepth="$(pathSegment "${gitPath}")"
+ REPONUM="$((REPONUM+1))"
+ else
+ local gitDepth="0"
+ fi
+ if [ ! -z "$(hg root 2>/dev/null)" ]; then
+ local hgPath="$(hg root 2>/dev/null)"
+ local hgDepth="$(pathSegment "${hgPath}")"
+ REPONUM="$((REPONUM+1))"
+ else
+ local hgDepth="0"
+ fi
+ if [ ! -z "$(bzr root 2>/dev/null)" ]; then
+ local bzrPath="$(bzr root 2>/dev/null)"
+ local bzrDepth="$(pathSegment "${bzrPath}")"
+ REPONUM="$((REPONUM+1))"
+ else
+ local bzrDepth="0"
+ fi
+ if [ ! -z "$(svn info 2>/dev/null)" ]; then
+ local stringz="<wcroot-abspath>"
+ local stringx="</wcroot-abspath>"
+ local svnPath="$(svn info --xml | sed -n -e "s:${stringz}::" -e "s:${stringx}::p")"
+ # An old enough svn will not be able give us a path; default
+ # to 1 for that case.
+ if [ -z "${svnPath}" ]; then
+ local svnDepth="1"
+ else
+ local svnDepth="$(pathSegment "${svnPath}")"
+ fi
+ REPONUM="$((REPONUM+1))"
+ else
+ local svnDepth="0"
+ fi
+
+ # Do not do more work then we have to.
+ if [ "${REPONUM}" = "0" ]; then
+ return
+ fi
+
+ # Figure out which repo is the deepest and use it.
+ local wonRepo="$(multiCompare "${gitDepth}" "${hgDepth}" "${bzrDepth}" "${svnDepth}")"
+ if [ "${wonRepo}" = "${gitDepth}" ]; then
+ gitRepo
+ elif [ "${wonRepo}" = "${hgDepth}" ]; then
+ hgRepo
+ elif [ "${wonRepo}" = "${bzrDepth}" ]; then
+ bzrRepo
+ elif [ "${wonRepo}" = "${svnDepth}" ]; then
+ svnRepo
+ fi
+}
+
+
+
+# Detect which repos we are in and gather data.
+# shellcheck source=/dev/null
+if [ -f "${CACHEFILE}" ] && [ "${CACHEFORCE}" = "1" ]; then
+ # When requested only read from the cache to populate our symbols.
+ . "${CACHEFILE}"
+else
+ # If a value is not set through the environment set VCS_EXTRA to nothing.
+ : "${VCS_EXTRA:=""}"
+ repoTest
+
+ if [ -f "${CACHEFILE}" ] && [ "${REPONUM}" = "0" ]; then
+ # We are not in a repo; try to use a previously generated cache to populate our symbols.
+ . "${CACHEFILE}"
+ # Do not overwrite the cache if we know we are not going to write anything new.
+ CACHEFORCE="1"
+ elif [ "${REPONUM}" = "0" ]; then
+ echo "error: No repo or cache detected." 1>&2
+ exit 1
+ fi
+fi
+
+
+# -s output is handled here.
+if [ ! -z "${VAROUT}" ]; then
+ if [ "${VAROUT}" = "VCS_TYPE" ]; then
+ echo "${VCS_TYPE}"
+ elif [ "${VAROUT}" = "VCS_BASENAME" ]; then
+ echo "${VCS_BASENAME}"
+ elif [ "${VAROUT}" = "VCS_NUM" ]; then
+ echo "${VCS_NUM}"
+ elif [ "${VAROUT}" = "VCS_DATE" ]; then
+ echo "${VCS_DATE}"
+ elif [ "${VAROUT}" = "VCS_BRANCH" ]; then
+ echo "${VCS_BRANCH}"
+ elif [ "${VAROUT}" = "VCS_TAG" ]; then
+ echo "${VCS_TAG}"
+ elif [ "${VAROUT}" = "VCS_TICK" ]; then
+ echo "${VCS_TICK}"
+ elif [ "${VAROUT}" = "VCS_FULL_HASH" ]; then
+ echo "${VCS_FULL_HASH}"
+ elif [ "${VAROUT}" = "VCS_SHORT_HASH" ]; then
+ echo "${VCS_SHORT_HASH}"
+ elif [ "${VAROUT}" = "VCS_WC_MODIFIED" ]; then
+ echo "${VCS_WC_MODIFIED}"
+ elif [ "${VAROUT}" = "VCS_ACTION_STAMP" ]; then
+ echo "${VCS_ACTION_STAMP}"
+ else
+ echo "error: Not a valid output symbol." 1>&2
+ exit 1
+ fi
+fi
+
+
+# Detect requested output type and use it.
+if [ ! -z "${AFILETYPE}" ]; then
+ if [ "${AFILETYPE}" = "c" ]; then
+ cOutput
+ elif [ "${AFILETYPE}" = "h" ]; then
+ hOutput
+ elif [ "${AFILETYPE}" = "xcode" ]; then
+ xcodeOutput
+ elif [ "${AFILETYPE}" = "swift" ]; then
+ swiftOutput
+ elif [ "${AFILETYPE}" = "sh" ]; then
+ shOutput
+ elif [ "${AFILETYPE}" = "py" ] || [ "${AFILETYPE}" = "python" ]; then
+ pyOutput
+ elif [ "${AFILETYPE}" = "pl" ] || [ "${AFILETYPE}" = "perl" ]; then
+ plOutput
+ elif [ "${AFILETYPE}" = "lua" ]; then
+ luaOutput
+ elif [ "${AFILETYPE}" = "php" ]; then
+ phpOutput
+ elif [ "${AFILETYPE}" = "ini" ]; then
+ iniOutput
+ elif [ "${AFILETYPE}" = "js" ]; then
+ jsOutput
+ elif [ "${AFILETYPE}" = "json" ]; then
+ jsonOutput
+ elif [ "${AFILETYPE}" = "java" ]; then
+ javaOutput
+ elif [ "${AFILETYPE}" = "javaprop" ]; then
+ javapropOutput
+ elif [ "${AFILETYPE}" = "tex" ]; then
+ texOutput
+ elif [ "${AFILETYPE}" = "m4" ]; then
+ m4Output
+ elif [ "${AFILETYPE}" = "scheme" ]; then
+ schemeOutput
+ elif [ "${AFILETYPE}" = "clojure" ]; then
+ clojureOutput
+ elif [ "${AFILETYPE}" = "rpm" ]; then
+ rpmOutput
+ elif [ "${AFILETYPE}" = "hpp" ]; then
+ hppOutput
+ elif [ "${AFILETYPE}" = "matlab" ]; then
+ matlabOutput
+ elif [ "${AFILETYPE}" = "octave" ]; then
+ octaveOutput
+ elif [ "${AFILETYPE}" = "cmake" ]; then
+ cmakeOutput
+ else
+ echo "error: Not a valid output type." 1>&2
+ exit 1
+ fi
+fi
+
+
+# If requested, make a cache file.
+if [ ! -z "${CACHEFILE}" ] && [ ! "${CACHEFORCE}" = "1" ]; then
+ TARGETFILE="${CACHEFILE}.tmp"
+ shOutput
+
+ # Check to see if there have been any actual changes.
+ if [ ! -f "${CACHEFILE}" ]; then
+ mv -f "${CACHEFILE}.tmp" "${CACHEFILE}"
+ elif cmp -s "${CACHEFILE}.tmp" "${CACHEFILE}"; then
+ rm -f "${CACHEFILE}.tmp"
+ else
+ mv -f "${CACHEFILE}.tmp" "${CACHEFILE}"
+ fi
+fi
diff --git a/ci/get-nprocessors.sh b/ci/get-nprocessors.sh
new file mode 100644
index 0000000..43635e7
--- /dev/null
+++ b/ci/get-nprocessors.sh
@@ -0,0 +1,48 @@
+#!/usr/bin/env bash
+# Copyright 2017 Google Inc.
+# All Rights Reserved.
+#
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# This file is typically sourced by another script.
+# if possible, ask for the precise number of processors,
+# otherwise take 2 processors as reasonable default; see
+# https://docs.travis-ci.com/user/speeding-up-the-build/#Makefile-optimization
+if [ -x /usr/bin/getconf ]; then
+ NPROCESSORS=$(/usr/bin/getconf _NPROCESSORS_ONLN)
+else
+ NPROCESSORS=2
+fi
+
+# as of 2017-09-04 Travis CI reports 32 processors, but GCC build
+# crashes if parallelized too much (maybe memory consumption problem),
+# so limit to 4 processors for the time being.
+if [ $NPROCESSORS -gt 4 ] ; then
+ echo "$0:Note: Limiting processors to use by make from $NPROCESSORS to 4."
+ NPROCESSORS=4
+fi
diff --git a/ci/perpare_pulp3_netrc.sh b/ci/perpare_pulp3_netrc.sh
new file mode 100644
index 0000000..8414bbb
--- /dev/null
+++ b/ci/perpare_pulp3_netrc.sh
@@ -0,0 +1,3 @@
+#!/usr/bin/env sh
+set -evx
+echo "machine ${PULP3_SERVER_URL}\nlogin ${PULP3_SERVER_LOGIN}\npassword ${PULP3_SERVER_PASSWORD}\n" > ~/.netrc
diff --git a/ci/travis.sh b/ci/travis.sh
new file mode 100644
index 0000000..3f5379c
--- /dev/null
+++ b/ci/travis.sh
@@ -0,0 +1,70 @@
+#!/usr/bin/env sh
+set -evx
+
+chmod +x ci/get-nprocessors.sh
+. ci/get-nprocessors.sh
+
+# if possible, ask for the precise number of processors,
+# otherwise take 2 processors as reasonable default; see
+# https://docs.travis-ci.com/user/speeding-up-the-build/#Makefile-optimization
+if [ -x /usr/bin/getconf ]; then
+ NPROCESSORS=$(/usr/bin/getconf _NPROCESSORS_ONLN)
+else
+ NPROCESSORS=2
+fi
+
+# as of 2017-09-04 Travis CI reports 32 processors, but GCC build
+# crashes if parallelized too much (maybe memory consumption problem),
+# so limit to 4 processors for the time being.
+if [ $NPROCESSORS -gt 4 ] ; then
+ echo "$0:Note: Limiting processors to use by make from $NPROCESSORS to 4."
+ NPROCESSORS=4
+fi
+
+# Tell make to use the processors. No preceding '-' required.
+MAKEFLAGS="j${NPROCESSORS}"
+export MAKEFLAGS
+
+env | sort
+
+# Set default values to OFF for these variables if not specified.
+: "${NO_EXCEPTION:=OFF}"
+: "${NO_RTTI:=OFF}"
+: "${COMPILER_IS_GNUCXX:=OFF}"
+
+# Install dependency from YUM
+if [ -n "${INSTALL_DEPENDENCY_LIBRARY}" ]; then
+ yum install -y $INSTALL_DEPENDENCY_LIBRARY
+fi
+
+if [ $ASAN_OPTION ];then
+ source /opt/rh/devtoolset-7/enable
+fi
+
+mkdir build || true
+cd build
+
+cmake3 -DCMAKE_CXX_FLAGS=$CXX_FLAGS \
+ -DCMAKE_BUILD_TYPE=$BUILD_TYPE \
+ -DCMAKE_INSTALL_PREFIX=$INSTALL_PREFIX \
+ -DASAN_OPTION=$ASAN_OPTION \
+ -DVERSION_DAILY_BUILD=$TESTING_VERSION_BUILD \
+ ..
+
+make
+
+if [ -n "${PACKAGE}" ]; then
+ make package
+fi
+
+if [ -n "${UPLOAD_RPM}" ]; then
+ cp ~/rpm_upload_tools.py ./
+ python3 rpm_upload_tools.py ${PULP3_REPO_NAME} ${PULP3_DIST_NAME} *.rpm
+fi
+
+if [ -n "${UPLOAD_SYMBOL_FILES}" ]; then
+ rpm -i $SYMBOL_TARGET*debuginfo*.rpm
+ _symbol_file=`find /usr/lib/debug/ -name "$SYMBOL_TARGET*.so*.debug"`
+ cp $_symbol_file ${_symbol_file}info.${CI_COMMIT_SHORT_SHA}
+ sentry-cli upload-dif -t elf ${_symbol_file}info.${CI_COMMIT_SHORT_SHA}
+fi
diff --git a/cmake/.gitignore b/cmake/.gitignore
new file mode 100644
index 0000000..b9ffdf6
--- /dev/null
+++ b/cmake/.gitignore
@@ -0,0 +1,5 @@
+build
+__view
+*.o
+*.so
+*.a
diff --git a/cmake/Package.cmake b/cmake/Package.cmake
new file mode 100644
index 0000000..2703138
--- /dev/null
+++ b/cmake/Package.cmake
@@ -0,0 +1,54 @@
+if(CMAKE_BUILD_TYPE STREQUAL "Debug")
+ set(MY_RPM_NAME_PREFIX "lib${lib_name}-debug")
+else()
+ set(MY_RPM_NAME_PREFIX "lib${lib_name}")
+endif()
+
+message(STATUS "Package: ${MY_RPM_NAME_PREFIX}")
+
+set(CPACK_PACKAGE_VECDOR "MESA")
+set(CPACK_PACKAGE_VERSION_MAJOR "${VERSION_MAJOR}")
+set(CPACK_PACKAGE_VERSION_MINOR "${VERSION_MINOR}")
+set(CPACK_PACKAGE_VERSION_PATCH "${VERSION_PATCH}.${VERSION_BUILD}")
+set(CPACK_PACKAGING_INSTALL_PREFIX ${CMAKE_INSTALL_PREFIX})
+set(CPACK_PACKAGE_VERSION "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}.${VERSION_BUILD}")
+execute_process(COMMAND bash -c "echo -ne \"`uname -r | awk -F'.' '{print $5\".\"$6\".\"$7}'`\"" OUTPUT_VARIABLE SYSTEM_VERSION)
+
+# RPM Build
+set(CPACK_GENERATOR "RPM")
+set(CPACK_RPM_PACKAGE_VENDOR "MESA")
+set(CPACK_RPM_PACKAGE_AUTOREQPROV "yes")
+set(CPACK_RPM_PACKAGE_RELEASE_LIBRARY "on")
+set(CPACK_RPM_DEBUGINFO_PACKAGE "on")
+set(CPACK_RPM_PACKAGE_DEBUG 1)
+
+set(CPACK_RPM_COMPONENT_INSTALL ON)
+set(CPACK_COMPONENTS_IGNORE_GROUPS 1)
+set(CPACK_COMPONENTS_GROUPING ONE_PER_GROUP)
+set(CPACK_COMPONENT_HEADER_DISPLAY_NAME "develop")
+set(CPACK_COMPONENT_LIBRARY_REQUIRED TRUE)
+set(CPACK_COMPONENT_HEADER_REQUIRED TRUE)
+set(CPACK_RPM_HEADER_PACKAGE_NAME "${MY_RPM_NAME_PREFIX}-devel")
+set(CPACK_RPM_LIBRARY_PACKAGE_NAME ${MY_RPM_NAME_PREFIX})
+
+set(CPACK_RPM_FILE_NAME "${CPACK_RPM_LIBRARY_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}-${SYSTEM_VERSION}.rpm")
+set(CPACK_RPM_LIBRARY_DEBUGINFO_FILE_NAME "${CPACK_RPM_LIBRARY_PACKAGE_NAME}-debuginfo-${CPACK_PACKAGE_VERSION}-${SYSTEM_VERSION}.rpm")
+set(CPACK_COMPONENT_LIBRARY_GROUP "library")
+
+set(CPACK_RPM_HEADER_FILE_NAME "${CPACK_RPM_HEADER_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}-${SYSTEM_VERSION}.rpm")
+set(CPACK_RPM_HEADER_DEBUGINFO_FILE_NAME "${CPACK_RPM_HEADER_PACKAGE_NAME}-debuginfo-${CPACK_PACKAGE_VERSION}-${SYSTEM_VERSION}.rpm")
+set(CPACK_COMPONENT_HEADER_GROUP "header")
+
+set(CPACK_RPM_HEADER_PACKAGE_REQUIRES_PRE ${CPACK_RPM_LIBRARY_PACKAGE_NAME})
+set(CPACK_RPM_HEADER_PACKAGE_CONFLICTS ${CPACK_RPM_HEADER_PACKAGE_NAME})
+
+set(CPACK_COMPONENTS_ALL LIBRARY HEADER)
+
+
+set(CPACK_BUILD_SOURCE_DIRS "${CMAKE_SOURCE_DIR}")
+
+# Must uninstall the debug package before install release package
+set(CPACK_RPM_PACKAGE_CONFLICTS ${MY_RPM_NAME_PREFIX})
+
+# set(CPACK_STRIP_FILES TRUE)
+include(CPack)
diff --git a/cmake/Version.cmake b/cmake/Version.cmake
new file mode 100644
index 0000000..9b05d0b
--- /dev/null
+++ b/cmake/Version.cmake
@@ -0,0 +1,54 @@
+
+# Using autorevision.sh to generate version information
+
+set(__SOURCE_AUTORESIVISION ${CMAKE_SOURCE_DIR}/autorevision.sh)
+set(__AUTORESIVISION ${CMAKE_BINARY_DIR}/autorevision.sh)
+set(__VERSION_CACHE ${CMAKE_SOURCE_DIR}/version.txt)
+set(__VERSION_CONFIG ${CMAKE_BINARY_DIR}/version.cmake)
+
+file(COPY ${__SOURCE_AUTORESIVISION} DESTINATION ${CMAKE_BINARY_DIR}
+ FILE_PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE
+ WORLD_READ WORLD_EXECUTE)
+
+# execute autorevision.sh to generate version information
+execute_process(COMMAND ${__AUTORESIVISION} -t cmake -o ${__VERSION_CACHE}
+ OUTPUT_FILE ${__VERSION_CONFIG} ERROR_QUIET)
+include(${__VERSION_CONFIG})
+
+# extract major, minor, patch version from git tag
+string(REGEX REPLACE "^v([0-9]+)\\..*" "\\1" VERSION_MAJOR "${VCS_TAG}")
+string(REGEX REPLACE "^v[0-9]+\\.([0-9]+).*" "\\1" VERSION_MINOR "${VCS_TAG}")
+string(REGEX REPLACE "^v[0-9]+\\.[0-9]+\\.([0-9]+).*" "\\1" VERSION_PATCH "${VCS_TAG}")
+string(REGEX REPLACE "[T\\:\\+\\-]" "" VERSION_DATE "${VCS_DATE}")
+
+if(VERSION_DAILY_BUILD)
+ set(VERSION_PATCH ${VERSION_PATCH}.${VERSION_DATE})
+endif()
+
+if(NOT VERSION_MAJOR)
+ set(VERSION_MAJOR 1)
+endif()
+
+if(NOT VERSION_MINOR)
+ set(VERSION_MINOR 0)
+endif()
+
+if(NOT VERSION_PATCH)
+ set(VERSION_PATCH 0)
+endif()
+
+set(VERSION "${VERSION_MAJOR}_${VERSION_MINOR}_${VERSION_PATCH}")
+set(VERSION_BUILD "${VCS_SHORT_HASH}")
+
+# print information
+message(STATUS "Version: ${VERSION}-${VERSION_BUILD}")
+
+option(DEFINE_GIT_VERSION "Set DEFINE_GIT_VERSION to TRUE or FALSE" TRUE)
+
+if(DEFINE_GIT_VERSION)
+ set(GIT_VERSION
+ "${VERSION}-${CMAKE_BUILD_TYPE}-${VERSION_BUILD}-${VCS_BRANCH}-${VCS_TAG}-${VCS_DATE}")
+ string(REGEX REPLACE "[-:+/\\.]" "_" GIT_VERSION ${GIT_VERSION})
+
+ add_definitions(-DGIT_VERSION=${GIT_VERSION})
+endif()
diff --git a/inc/MESA_jump_layer.h b/inc/MESA_jump_layer.h
new file mode 100644
index 0000000..5356f6a
--- /dev/null
+++ b/inc/MESA_jump_layer.h
@@ -0,0 +1,30 @@
+#ifndef __MESA_JUMP_LAYER_H_
+#define __MESA_JUMP_LAYER_H_ 1
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "stream.h"
+#include <netinet/ip.h>
+#include <netinet/ip6.h>
+
+
+const char *MESA_jump_layer_get_last_error(void);
+
+/*
+ The raw_layer_type and expect_layer_type refer to sapp_base.h->enum addr_type_t
+*/
+const void *MESA_net_jump_to_layer(const void *raw_data, int raw_layer_type, int expect_layer_type);
+
+const void *MESA_net_jump_to_layer_greedy(const void *raw_data, int raw_layer_type, int expect_layer_type);
+
+
+const char *MESA_jump_layer_ipv4_ntop(const struct ip *ip4_hdr, char *out_buf, int buf_len );
+
+const char *MESA_jump_layer_ipv6_ntop(const struct ip6_hdr *ip6_hdr, char *out_buf, int buf_len);
+
+#ifdef __cplusplus
+}
+#endif \ No newline at end of file
diff --git a/src/MESA_jump_layer.cpp b/src/MESA_jump_layer.cpp
new file mode 100644
index 0000000..0641498
--- /dev/null
+++ b/src/MESA_jump_layer.cpp
@@ -0,0 +1,1501 @@
+#include "stream.h"
+#include "mesa_net.h"
+#include "deal_ipv6.h"
+/* Linux OS std */
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <assert.h>
+#include <errno.h>
+#include <dlfcn.h>
+#include <linux/if_ether.h>
+#include <linux/limits.h>
+#include <netinet/ip.h>
+#include <netinet/ip6.h>
+#include <net/if_arp.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <pthread.h>
+#include <sys/select.h>
+#include <sys/types.h>
+#include <linux/version.h>
+#include <net/if.h>
+#include <sys/ioctl.h>
+#include <signal.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/prctl.h>
+#include <sys/un.h>
+#include <link.h>
+#include <execinfo.h>
+#include <pcap/pcap.h>
+#include <getopt.h>
+#include <sys/sysinfo.h>
+#include <dirent.h>
+#include <sys/syscall.h>
+
+
+static int eth_jump_to_layer(const char *raw_data, int raw_layer_type, int expect_layer_type);
+static int vlan8021q_jump_to_layer(const char *raw_data, int raw_layer_type, int expect_layer_type);
+static int ipv4_jump_to_layer(const char *raw_data, int raw_layer_type, int expect_layer_type);
+static int ipv6_jump_to_layer(const char *raw_data, int raw_layer_type, int expect_layer_type);
+static int ppp_jump_to_layer(const char *raw_data, int raw_layer_type, int expect_layer_type);
+
+static char _g_mesa_jump_layer_last_error[PIPE_BUF];
+
+
+/* ascii�ַ�ת16���� */
+char MESA_ascii_to_hex(char ascii)
+{
+ char c = 0;
+
+ switch(ascii)
+ {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ c = ascii - 0x30;
+ break;
+
+ case 'a':
+ case 'b':
+ case 'c':
+ case 'd':
+ case 'e':
+ case 'f':
+ c = 10 + ascii - 0x61;
+ break;
+
+ case 'A':
+ case 'B':
+ case 'C':
+ case 'D':
+ case 'E':
+ case 'F':
+ c = 10 + ascii - 0x41;
+ break;
+
+ default:
+ c = 0; //todo , what error number return?
+ break;
+ }
+
+ return c;
+}
+
+static int __mjl_guess_mpls_with_control_word(const unsigned char *maybe_eth_hdr)
+{
+ const struct mesa_ethernet_hdr *ehdr = (struct mesa_ethernet_hdr *)(maybe_eth_hdr);
+
+ /*
+ MPLSû���ֶα�ʾ���ص�Э������, ����!!
+
+ https://tools.ietf.org/html/rfc4623
+ https://wiki.mikrotik.com/wiki/Manual:VPLS_Control_Word
+ https://www.ciscopress.com/articles/article.asp?p=386788&seqNum=2
+
+ ����׼��ipv4, ipv6֮��, ���п�����ethernet, ���п����Ǵ�PW Ethernet Control Word��, ��ʽ����:
+
+ 0 1 2 3
+ 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 2
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ |0 0 0 0| flags |frag|len(6bit) | Sequence Number(16bit) |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+ ʵ�����֤��, ��4bit�Ƿ�==0Ϊ����, ���ǿ��ܲ´�, ���ж�һ����̫�����Ƿ�Ϊ��������.
+ */
+
+ switch(ntohs(ehdr->ether_type)){
+ case ETH_P_IP:
+ case ETH_P_IPV6:
+ case ETH_P_8021Q:
+ case ETH_P_MPLS_UC:
+ case ETH_P_PPP_SES:
+ return 0; /* �Ϸ���ethernet����, ����CW */
+ break;
+
+ default:
+ break;
+ }
+
+ ehdr = (struct mesa_ethernet_hdr *)(maybe_eth_hdr + 4);
+ switch(ntohs(ehdr->ether_type)){
+ case ETH_P_IP:
+ case ETH_P_IPV6:
+ case ETH_P_8021Q:
+ case ETH_P_MPLS_UC:
+ case ETH_P_PPP_SES:
+ return 1; /* �Ϸ���ethernet����, ����CW */
+ break;
+
+ default:
+ break;
+ }
+
+ /* TODO: ���϶�����, �˴�Ӧ�÷��ظ�ʲôֵ? */
+ return 0;
+}
+
+static int __mjl_mpls_addr_net_to_mem(const struct mesa_mpls_hdr *net_mpls_hdr, struct single_layer_mpls_addr *mem_mpls_hdr)
+{
+ memset(mem_mpls_hdr, 0, sizeof(struct single_layer_mpls_addr));
+
+ mem_mpls_hdr->label = htonl( (net_mpls_hdr->mpls_label_low<<12) | (net_mpls_hdr->mpls_label_mid<<4) | net_mpls_hdr->mpls_label_high ); /* network order */
+ mem_mpls_hdr->experimental = net_mpls_hdr->mpls_exp;
+ mem_mpls_hdr->bottom = net_mpls_hdr->mpls_bls;
+ mem_mpls_hdr->ttl = net_mpls_hdr->mpls_ttl;
+
+ return 0;
+}
+
+static int __mjl_set_mpls_addr(struct layer_addr_mpls *addr, const unsigned char *raw_mpls_pkt_data)
+{
+ const struct mesa_mpls_hdr *this_mpls_hdr;
+ int i;
+
+ memset(addr, 0, sizeof(struct layer_addr_mpls));
+ for(i = 0; i < MAX_MPLS_ADDR_LAYER; i++)
+ {
+ this_mpls_hdr = (const struct mesa_mpls_hdr *)raw_mpls_pkt_data;
+ //memcpy(&addr->src_mpls_pkt[i], raw_mpls_pkt_data, sizeof(struct mesa_mpls_hdr));
+ __mjl_mpls_addr_net_to_mem(this_mpls_hdr, &addr->c2s_addr_array[i]); /* ����ջ��ĵ�ַ, ÿ���ݴ���c2s����, TCP/UDP���ٸ���������ת */
+
+ addr->c2s_layer_num += 1;
+ if(1 == this_mpls_hdr->mpls_bls){
+ raw_mpls_pkt_data += sizeof(struct mesa_mpls_hdr); /* Ϊ�˺��淽���ж��Ƿ���ctrl word */
+ break;
+ }
+ raw_mpls_pkt_data += sizeof(struct mesa_mpls_hdr);
+ }
+
+ if(1 != this_mpls_hdr->mpls_bls) /* ����MAX_MPLS_ADDR_LAYER, MPLS��û�н��� */
+ {
+ snprintf(_g_mesa_jump_layer_last_error, PIPE_BUF, "MPLS layer number over load, only support %d", MAX_MPLS_ADDR_LAYER);
+ return -1;
+ }
+
+ if(((*raw_mpls_pkt_data & 0xF0) != 0x40) && ((*raw_mpls_pkt_data & 0xF0) != 0x60)){ //VPLS, MPLS with Control Word
+ if(__mjl_guess_mpls_with_control_word(raw_mpls_pkt_data) > 0){
+ memcpy(&addr->c2s_mpls_ctrl_word, raw_mpls_pkt_data, sizeof(int));
+ addr->c2s_has_ctrl_word = 1;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ gprsͷ�����ݱ�־λ�IJ�ͬ, ����Ҳ��ͬ, ����ֱ����sizeof(struct gtp_hdr)��ȡ����.
+*/
+static int __mjl_gtp_calc_gtp_hdr_len(const struct gtp_hdr *gtph)
+{
+ const unsigned char *p_ext_hdr = (unsigned char *)gtph + sizeof(struct gtp_hdr);
+ unsigned char next_hdr_type;
+ unsigned char this_ext_field_cont_len;
+
+ /*
+ v0̫������, �ѱ�����;
+ ������GTPv2-UЭ��, ��LTE�е�GTP-U��ʹ��GTPv1-U,
+ ����, sappĿǰ��֧��gtp v1�汾.
+ */
+ if(((gtph->flags & GTP_HDR_VER_MASK) >> 5) != 1){
+ return -1;
+ }
+
+ if(gtph->flags & (GTP_HDR_FLAG_SEQ_NUM | GTP_HDR_FLAG_N_PDU | GTP_HDR_FLAG_NEXT_EXT_HDR)){
+ //todo, parse and get seq field
+ p_ext_hdr += 2; //seq field length is 2 bytes
+
+ //todo, parse and get N-PDU field
+ p_ext_hdr++; //N-PDU field length is 1 byte
+
+ /*
+ ����gtp��չͷ���ֶ�,
+ �ο�3GPP�ĵ���5.1, 5.2�½�,
+ �Լ�wiresharkԴ��, packet-gtp.c -> dissect_gtp_common()����.
+ */
+
+ next_hdr_type = *p_ext_hdr;
+ if(gtph->flags & GTP_HDR_FLAG_NEXT_EXT_HDR){
+ while(next_hdr_type != 0){
+ //todo, parse and get extension headers
+ p_ext_hdr++; //ָ�򳤶��ֶ�, ��4���ֽ�Ϊ��λ
+ this_ext_field_cont_len = *p_ext_hdr * 4 - 2;
+
+ p_ext_hdr++; //ָ�����ݲ��ֵ�һ���ֽ�
+ p_ext_hdr += this_ext_field_cont_len;
+
+ //ָ����һ��ͷ���ֶ�
+ next_hdr_type = *p_ext_hdr;
+ p_ext_hdr++;
+ }
+ }else{
+ p_ext_hdr++;
+ }
+ }
+
+ return (char *)p_ext_hdr - (char *)gtph;
+}
+
+static inline int check_layer_type(int layer_type)
+{
+ if((layer_type <= __ADDR_TYPE_INIT) || (layer_type >= __ADDR_TYPE_MAX)){
+ return -1;
+ }
+
+ return 0;
+}
+
+static int arp_jump_to_layer(const char *raw_data, int raw_layer_type, int expect_layer_type)
+{
+ /* arpЭ�鲻�����κ��ϲ�����Э�� */
+ return -1;
+}
+
+
+static int gtp_jump_to_layer(const char *raw_data, int raw_layer_type, int expect_layer_type)
+{
+ const struct gtp_hdr *gh = (struct gtp_hdr *)raw_data;
+ const unsigned char *next_ip_layer_hdr;
+ int skip_len;
+ int gtp_hdr_len;
+
+ if(ADDR_TYPE_GPRS_TUNNEL == expect_layer_type){
+ return 0;
+ }
+
+ gtp_hdr_len = __mjl_gtp_calc_gtp_hdr_len(gh);
+ if(gtp_hdr_len < 0){
+ snprintf(_g_mesa_jump_layer_last_error, PIPE_BUF, "calc gtp hdr len error");
+ return -1;
+ }
+
+ next_ip_layer_hdr = (unsigned char *)raw_data + gtp_hdr_len;
+
+ if((*next_ip_layer_hdr & 0x40) == 0x40){
+ skip_len = ipv4_jump_to_layer((char *)next_ip_layer_hdr, __ADDR_TYPE_IP_PAIR_V4, expect_layer_type);
+ }else if((*next_ip_layer_hdr & 0x60) == 0x60){
+ skip_len = ipv6_jump_to_layer((char *)next_ip_layer_hdr, __ADDR_TYPE_IP_PAIR_V6, expect_layer_type);
+ }else{
+ snprintf(_g_mesa_jump_layer_last_error, PIPE_BUF, "gtp_jump_to_layer() error, unsupport type in GTP, 0x%x!", (*next_ip_layer_hdr));
+ return -1;
+ }
+
+ return gtp_hdr_len + skip_len;
+}
+
+static int __mjl_guess_l2tp_ppp_layer_len(const unsigned char *maybe_l2tp_ppp_hdr)
+{
+ int ppp_layer_len = -1;
+ const unsigned short *ppp_proto;
+ if((0xFF == maybe_l2tp_ppp_hdr[0]) && (0x03 == maybe_l2tp_ppp_hdr[1])){
+ ppp_proto = (unsigned short *)(maybe_l2tp_ppp_hdr + 2);
+
+ switch(ntohs(*ppp_proto)){
+ case PPP_PROTOCOL_IPv4:
+ case PPP_PROTOCOL_PAP:
+ case PPP_PROTOCOL_CHAP:
+ case PPP_PROTOCOL_IPv6:
+ case PPP_PROTOCOL_LCP:
+ case PPP_PROTOCOL_CCP:
+ case PPP_PROTOCOL_IPCP:
+ ppp_layer_len = 4;
+ break;
+ }
+ }else{
+ if((0x21 == maybe_l2tp_ppp_hdr[0]) || (0x57 == maybe_l2tp_ppp_hdr[0])){
+
+ ppp_layer_len = 1; /* ʡ����control, address�ֶ�, ֻ��һ���ֽڵ�Э���, �ο�: http://www2.ic.uff.br/~michael/kr1999/5-datalink/5_08-ppp.htm#[RFC%201662] */
+ }
+ }
+
+ return ppp_layer_len;
+}
+
+static int __mjl_parse_l2tpv2_ppp_hdr(const unsigned char *l2tp_ppp_hdr, struct layer_addr_l2tp *l2tpaddr)
+{
+ int ppp_hdr_len;
+ const unsigned short *ppp_protocol;
+
+ ppp_hdr_len = __mjl_guess_l2tp_ppp_layer_len(l2tp_ppp_hdr);
+ if(ppp_hdr_len < 0){
+ return -1;
+ }
+
+ if(sizeof(struct layer_compress_ppp_hdr) == ppp_hdr_len){
+ l2tpaddr->l2tpun.l2tp_addr_v2.ppp_hdr_compress_enable = 1;
+ l2tpaddr->l2tpun.l2tp_addr_v2.compress_ppp_hdr.protocol = l2tp_ppp_hdr[0];
+ }else if(sizeof(struct layer_ppp_hdr) == ppp_hdr_len){
+ l2tpaddr->l2tpun.l2tp_addr_v2.ppp_hdr_compress_enable = 0;
+ l2tpaddr->l2tpun.l2tp_addr_v2.ppp_hdr.address = l2tp_ppp_hdr[0];
+ l2tpaddr->l2tpun.l2tp_addr_v2.ppp_hdr.control = l2tp_ppp_hdr[1];
+
+ ppp_protocol = (unsigned short *)&l2tp_ppp_hdr[2];
+ l2tpaddr->l2tpun.l2tp_addr_v2.ppp_hdr.protocol = *ppp_protocol;
+ }else{
+ return -1;
+ }
+
+ return ppp_hdr_len;
+}
+
+static int __mjl_parse_l2tpv2_hdr(const struct l2tp_hdr_v2 *pl2tphdrv2, struct layer_addr_l2tp *l2tpaddr)
+{
+ unsigned short l2top_tot_len, offset_size;
+ const char *ptr = (const char *)pl2tphdrv2 + sizeof(struct l2tp_hdr_v2);
+ int l2tp_ppp_hdr_len;
+
+ memset(l2tpaddr, 0, sizeof(struct layer_addr_l2tp));
+
+ if(pl2tphdrv2->length_present){
+ l2top_tot_len = ntohs(*((unsigned short *)ptr));
+ ptr += sizeof(short);
+ if(l2top_tot_len < sizeof(struct l2tp_hdr_v2) + 1/* compress ppp hdr len */ + sizeof(struct mesa_ip4_hdr)){
+ return -1; /* ���������� */
+ }
+ }
+
+ /* L2TP��ַC2S, S2C�������, �޷�����ǰ����ַ����dir, ÿ��ջ��ı������洢��source����, ��C2S����,
+ ������ʱ, �����Ҫreverse����, ��source, dest�ߵ�, ����ֱ��memcpy�������addr.
+ */
+
+ l2tpaddr->l2tpun.l2tp_addr_v2.tunnelid_C2S = *((unsigned short *)ptr);
+ ptr += sizeof(short);
+ l2tpaddr->l2tpun.l2tp_addr_v2.sessionid_C2S = *((unsigned short *)ptr);
+ ptr += sizeof(short);
+
+ if(pl2tphdrv2->seq_present){
+ ptr += sizeof(int);
+ l2tpaddr->l2tpun.l2tp_addr_v2.seq_present_C2S = 1;
+ }
+
+ if(pl2tphdrv2->offset_present){
+ offset_size = ntohs(*((unsigned short *)ptr));
+ ptr += sizeof(short); /* 2 byte fix len offset size */
+ ptr += offset_size; /* var bytes offset value length */
+ }
+
+ l2tp_ppp_hdr_len = __mjl_parse_l2tpv2_ppp_hdr((unsigned char *)ptr, l2tpaddr);
+ if(l2tp_ppp_hdr_len < 0){
+ return -1;
+ }
+ ptr += l2tp_ppp_hdr_len;
+
+ l2tpaddr->version = 2; /* version, RFC2661 */
+
+ return ptr - (char *)pl2tphdrv2;
+}
+static int l2tp_jump_to_layer(const char *raw_data, int raw_layer_type, int expect_layer_type)
+{
+ int l2tp_hdr_len, skip_len = 0;
+
+ const unsigned char *next_layer_hdr;
+ struct layer_addr_l2tp tmp_l2tp_addr;
+
+ if(ADDR_TYPE_L2TP == expect_layer_type){
+ return 0;
+ }
+
+ l2tp_hdr_len = __mjl_parse_l2tpv2_hdr((const struct l2tp_hdr_v2 *)raw_data, &tmp_l2tp_addr);
+ if(l2tp_hdr_len < 0){
+ return -1;
+ }
+
+ next_layer_hdr = (unsigned char *)raw_data + l2tp_hdr_len;
+
+ if(tmp_l2tp_addr.l2tpun.l2tp_addr_v2.ppp_hdr_compress_enable){
+ if(tmp_l2tp_addr.l2tpun.l2tp_addr_v2.compress_ppp_hdr.protocol == 0x21){
+ skip_len = ipv4_jump_to_layer((char *)next_layer_hdr, __ADDR_TYPE_IP_PAIR_V4, expect_layer_type);
+ }else if(tmp_l2tp_addr.l2tpun.l2tp_addr_v2.compress_ppp_hdr.protocol == 0x57){
+ skip_len = ipv6_jump_to_layer((char *)next_layer_hdr, __ADDR_TYPE_IP_PAIR_V6, expect_layer_type);
+ }
+ }else{
+ if(ntohs(tmp_l2tp_addr.l2tpun.l2tp_addr_v2.ppp_hdr.protocol) == 0x0021){
+ skip_len = ipv4_jump_to_layer((char *)next_layer_hdr, __ADDR_TYPE_IP_PAIR_V4, expect_layer_type);
+ }else if(ntohs(tmp_l2tp_addr.l2tpun.l2tp_addr_v2.ppp_hdr.protocol) == 0x57){
+ skip_len = ipv6_jump_to_layer((char *)next_layer_hdr, __ADDR_TYPE_IP_PAIR_V6, expect_layer_type);
+ }
+ }
+
+ return l2tp_hdr_len + skip_len;
+}
+
+static int teredo_jump_to_layer(const char *raw_data, int raw_layer_type, int expect_layer_type)
+{
+ const char *next_layer_hdr;
+ struct teredo_auth_hdr *p_teredo_hdr;
+ int teredo_layer_len = 0, tmp_hdr_len = 0, skip_len = 0;
+
+
+ /* teredoʵ��û�����ݰ�ͷ */
+ next_layer_hdr = raw_data;
+
+ while((*next_layer_hdr & 0xF0) != 0x60){
+ p_teredo_hdr = (struct teredo_auth_hdr *)next_layer_hdr;
+ if(p_teredo_hdr->flags == ntohs(TEREDO_AUTH_HDR_FLAG))
+ {
+ //rfc4380 5.1.1 teredo ����0x0001ʱΪTeredo authentication headers����Ҫ����
+ tmp_hdr_len += sizeof(struct teredo_auth_hdr) + ntohs(p_teredo_hdr->au_len) + ntohs
+ (p_teredo_hdr->id_len) + 8 + 1;
+ next_layer_hdr += tmp_hdr_len;
+ teredo_layer_len += tmp_hdr_len;
+ }
+ else if(p_teredo_hdr->flags == ntohs(TEREDO_INDICATION_HDR_FLAG))
+ {
+ //rfc4380 teredo ����0x0000ʱΪTeredo indication headers����Ҫ����
+ next_layer_hdr += TEREDO_INDICATION_HDR_LEN;
+ teredo_layer_len += TEREDO_INDICATION_HDR_LEN;
+ }
+ else
+ {
+ snprintf(_g_mesa_jump_layer_last_error, PIPE_BUF, "teredo_jump_to_layer(): unsupport teredo hdr:0x%d!\n", *(unsigned int *)(next_layer_hdr));
+ return -1;
+ }
+ }
+ skip_len = ipv6_jump_to_layer(next_layer_hdr, __ADDR_TYPE_IP_PAIR_V6, expect_layer_type);
+ if(skip_len < 0){
+ return -1;
+ }
+ skip_len += teredo_layer_len;
+
+ return skip_len;
+}
+
+
+
+static int udp_jump_to_layer(const char *raw_data, int raw_layer_type, int expect_layer_type)
+{
+ const struct mesa_udp_hdr *uh = (const struct mesa_udp_hdr *)raw_data;
+ unsigned short usport, udport;
+ int skip_len;
+
+ if(ADDR_TYPE_UDP == expect_layer_type){
+ return 0;
+ }
+
+ usport = ntohs(uh->uh_sport);
+ udport = ntohs(uh->uh_dport);
+
+ if((2152 == usport) || (2152 == udport)){
+ skip_len = gtp_jump_to_layer(raw_data+sizeof(struct mesa_udp_hdr), ADDR_TYPE_UDP, expect_layer_type);
+ }else if(4789 == udport){
+ /* vxlanģʽ��ʱֻ֧��ethernet. TODO: �����hdlc, ppp��װ, ��Ҫʵ��һ��������vxlan_jump_to_layer()���� */
+ skip_len = eth_jump_to_layer(raw_data+sizeof(struct mesa_udp_hdr)+8, ADDR_TYPE_MAC, expect_layer_type);
+ if(skip_len < 0){
+ return -1;
+ }
+ skip_len += 8; /* skip vxlan header */
+ }else if((3544 == usport) || (3544 == udport)){
+ skip_len = teredo_jump_to_layer(raw_data+sizeof(struct mesa_udp_hdr), 0, expect_layer_type);
+ }else if((1701 == usport) || (1701 == udport)){
+ skip_len = l2tp_jump_to_layer(raw_data+sizeof(struct mesa_udp_hdr), ADDR_TYPE_UDP, expect_layer_type);
+ }else{
+ /* ����UDP���Ͳ�֧������ת */
+ snprintf(_g_mesa_jump_layer_last_error, PIPE_BUF, "MESA_net_jump_to_layer_greedy() not support layer type:%d", expect_layer_type);
+ return -1;
+ }
+ if(skip_len < 0){
+ return -1;
+ }
+
+ return skip_len + sizeof(struct mesa_udp_hdr);
+}
+
+static int udp_jump_to_layer_greedy(const char *raw_data, int raw_layer_type, int expect_layer_type)
+{
+ const struct mesa_udp_hdr *uh = (const struct mesa_udp_hdr *)raw_data;
+ unsigned short usport, udport;
+ int skip_len;
+
+ usport = ntohs(uh->uh_sport);
+ udport = ntohs(uh->uh_dport);
+
+ if((2152 == usport) || (2152 == udport)){
+ skip_len = gtp_jump_to_layer(raw_data+sizeof(struct mesa_udp_hdr), ADDR_TYPE_UDP, expect_layer_type);
+ }else if(4789 == udport){
+ /* vxlanģʽ��ʱֻ֧��ethernet. TODO: �����hdlc, ppp��װ, ��Ҫʵ��һ��������vxlan_jump_to_layer()���� */
+ skip_len = eth_jump_to_layer(raw_data+sizeof(struct mesa_udp_hdr)+8, ADDR_TYPE_MAC, expect_layer_type);
+ if(skip_len < 0){
+ return -1;
+ }
+ skip_len += 8; /* skip vxlan header */
+ }else if((3544 == usport) || (3544 == udport)){
+ skip_len = teredo_jump_to_layer(raw_data+sizeof(struct mesa_udp_hdr), 0, expect_layer_type);
+ }else if((1701 == usport) || (1701 == udport)){
+ skip_len = l2tp_jump_to_layer(raw_data+sizeof(struct mesa_udp_hdr), ADDR_TYPE_UDP, expect_layer_type);
+ }else{
+ /* ����UDP���Ͳ�֧������ת */
+ snprintf(_g_mesa_jump_layer_last_error, PIPE_BUF, "udp_jump_to_layer(): unsupport udp sport:%u, dport:%u!\n", usport, udport);
+ return -1;
+ }
+ if(skip_len < 0){
+ return -1;
+ }
+
+ return skip_len + sizeof(struct mesa_udp_hdr);
+}
+
+static int set_gre_hdr_ver0(struct mesa_gre_hdr *stack_gre_addr, const struct mesa_gre_hdr *net_gre_addr)
+{
+ struct mesa_gre_extend_hdr *stack_gre_ext = &stack_gre_addr->gre_extend;
+ const struct mesa_gre_base_hdr_v0 *net_gre_base = &net_gre_addr->gre_base;
+ const char *net_ext_hdr_value = (const char *)(&net_gre_addr->gre_extend);
+ //const struct gre_source_route_entry_hdr *rse_hdr;
+
+ if(net_gre_base->checksum_flag || net_gre_base->route_flag){
+ stack_gre_ext->checksum = *((unsigned short *)net_ext_hdr_value);
+ net_ext_hdr_value += sizeof(short);
+
+ /* ���checksum����, ��offsetҲ�ش��� */
+ stack_gre_ext->offset = *((unsigned short *)net_ext_hdr_value);
+ net_ext_hdr_value += sizeof(short);
+ }
+
+ if(net_gre_base->key_flag){
+ stack_gre_ext->key = *((unsigned int *)net_ext_hdr_value);
+ net_ext_hdr_value += sizeof(int);
+ }
+
+ if(net_gre_base->seq_flag){
+ stack_gre_ext->seq_num = *((unsigned int *)net_ext_hdr_value);
+ net_ext_hdr_value += sizeof(int);
+ }
+
+ /* SRE��Ϣ��GREͷ�������, ��Ϊ������, �������� */
+ if(net_gre_base->route_flag){
+ //rse_hdr = (const struct gre_source_route_entry_hdr *)net_ext_hdr_value;
+ //TODO 1, copy SRE
+ snprintf(_g_mesa_jump_layer_last_error, PIPE_BUF, "found GRE SRE data, but not parse yet!");
+ return -1;
+ }
+
+ return sizeof(struct mesa_gre_base_hdr_v1) + (net_ext_hdr_value - (char *)&net_gre_addr->gre_extend);
+}
+
+static int set_gre_hdr_ver1(struct mesa_gre_hdr *stack_gre_addr, const struct mesa_gre_hdr *net_gre_addr)
+{
+ //struct mesa_gre_base_hdr_v1 *stack_gre_base = (struct mesa_gre_base_hdr_v1 *)&stack_gre_addr->gre_base;
+ struct mesa_gre_extend_hdr *stack_gre_ext = &stack_gre_addr->gre_extend;
+ const struct mesa_gre_base_hdr_v1 *net_gre_base = (struct mesa_gre_base_hdr_v1 *)&net_gre_addr->gre_base;
+ //const struct mesa_gre_extend_hdr *net_gre_ext = &net_gre_addr->gre_extend;
+ const char *net_ext_hdr_value = (const char *)(&net_gre_addr->gre_extend);
+
+ if(net_gre_base->checksum_flag != 0){
+ snprintf(_g_mesa_jump_layer_last_error, PIPE_BUF,"error! in gre version1, checksum flag not zero!");
+ return -1;
+ }
+
+ if(net_gre_base->route_flag != 0){
+ snprintf(_g_mesa_jump_layer_last_error, PIPE_BUF,"error! in gre version1, route flag not zero!");
+ return -1;
+ }
+
+ if(net_gre_base->recur != 0){
+ snprintf(_g_mesa_jump_layer_last_error, PIPE_BUF,"error! in gre version1, recur flag not zero!");
+ return -1;
+ }
+
+ if(net_gre_base->strict_src_route_flag != 0){
+ snprintf(_g_mesa_jump_layer_last_error, PIPE_BUF,"error! in gre version1, strict_src_route flag not zero!");
+ return -1;
+ }
+
+ if(ntohs(net_gre_base->protocol) != GRE_PRO_PPP){
+ snprintf(_g_mesa_jump_layer_last_error, PIPE_BUF,"error! in gre version1, protocol not 0x%x!", GRE_PRO_PPP);
+ return -1;
+ }
+
+ stack_gre_ext->payload_len = *((unsigned short *)net_ext_hdr_value);
+ net_ext_hdr_value += sizeof(short);
+
+ stack_gre_ext->call_id = *((unsigned short *)net_ext_hdr_value);
+ net_ext_hdr_value += sizeof(short);
+
+ if(net_gre_base->seq_flag){
+ stack_gre_ext->seq_num = *((unsigned int *)net_ext_hdr_value);
+ net_ext_hdr_value += sizeof(int);
+ }
+
+ /* version 1 has ack number */
+ if(net_gre_base->ack_flag){
+ stack_gre_ext->ack_num = *((unsigned int *)net_ext_hdr_value);
+ net_ext_hdr_value += sizeof(int);
+ }
+
+ return sizeof(struct mesa_gre_base_hdr_v1) + (net_ext_hdr_value - (char *)&net_gre_addr->gre_extend);
+}
+
+extern int __mjl_set_gre_hdr(struct mesa_gre_hdr *stack_gre_addr, const void *this_layer_data)
+{
+ int gre_hdr_len = 0;
+ const struct mesa_gre_hdr *net_gre_addr = (const struct mesa_gre_hdr *)this_layer_data;
+
+ memcpy(&stack_gre_addr->gre_base, &net_gre_addr->gre_base, sizeof(struct mesa_gre_base_hdr_v0));
+ memset(&stack_gre_addr->gre_extend, 0, sizeof(struct mesa_gre_extend_hdr));
+
+ if(0 == net_gre_addr->gre_base.version){
+ gre_hdr_len = set_gre_hdr_ver0(stack_gre_addr, net_gre_addr);
+ }else if(1 == net_gre_addr->gre_base.version){
+ gre_hdr_len = set_gre_hdr_ver1(stack_gre_addr, net_gre_addr);
+ }else{
+ //TODO 1, δ֪�汾
+ snprintf(_g_mesa_jump_layer_last_error, PIPE_BUF,"Unknown gre hdr version:%d", net_gre_addr->gre_base.version);
+ gre_hdr_len = -1;
+ }
+
+ return gre_hdr_len;
+}
+
+static int gre_jump_to_layer(const char *raw_data, int raw_layer_type, int expect_layer_type)
+{
+ int skip_len = 0;
+ int this_gre_layer_len;
+ struct mesa_gre_hdr this_layer_hdr;
+
+ if(raw_layer_type == expect_layer_type){
+ return 0;
+ }
+
+ this_gre_layer_len = __mjl_set_gre_hdr(&this_layer_hdr, (void *)raw_data);
+ if(this_gre_layer_len < 0){
+ return -1;
+ }
+
+ switch(ntohs(this_layer_hdr.gre_base.protocol))
+ {
+ case GRE_PRO_IPV4:
+ if(expect_layer_type == ADDR_TYPE_IPV4){
+ skip_len = 0;
+ break;
+ }else{
+ skip_len=ipv4_jump_to_layer(raw_data+this_gre_layer_len, __ADDR_TYPE_IP_PAIR_V4, expect_layer_type);
+ }
+ break;
+
+ case GRE_PRO_IPV6:
+ if(expect_layer_type == ADDR_TYPE_IPV4){
+ skip_len = 0;
+ break;
+ }else{
+ skip_len=ipv6_jump_to_layer(raw_data+this_gre_layer_len, __ADDR_TYPE_IP_PAIR_V6, expect_layer_type);
+ }
+ break;
+
+ case GRE_PRO_PPP:
+ if((expect_layer_type == ADDR_TYPE_PPP) || (expect_layer_type == ADDR_TYPE_PPTP)){
+ skip_len = this_gre_layer_len;
+ break;
+ }else{
+ skip_len = ppp_jump_to_layer(raw_data+this_gre_layer_len, ADDR_TYPE_PPP, expect_layer_type);
+ }
+ break;
+
+ default:
+ snprintf(_g_mesa_jump_layer_last_error, PIPE_BUF, "gre_jump_to_layer(): unknown gre protocol:0x%x!", ntohs(this_layer_hdr.gre_base.protocol));
+ return -1;
+ break;
+ }
+
+ if(skip_len < 0){
+ snprintf(_g_mesa_jump_layer_last_error, PIPE_BUF, "gre_jump_to_layer() error!");
+ return -1;
+ }
+
+ return skip_len + this_gre_layer_len;
+}
+
+static int ipv4_jump_to_layer(const char *raw_data, int raw_layer_type, int expect_layer_type)
+{
+ struct mesa_ip4_hdr *p_ip_hdr = (struct mesa_ip4_hdr *)raw_data;
+ int skip_len = 0;
+ int ip_hdr_len = p_ip_hdr->ip_hl * 4;
+ //const char *next_layer_data = raw_data + ip_hdr_len;
+
+ if(raw_layer_type == expect_layer_type){
+ return 0;
+ }
+
+ if((ntohs(p_ip_hdr->ip_off) & IP_MF ) || (ntohs(p_ip_hdr->ip_off) & IP_OFFMASK)){
+ /* IP��Ƭ���ټ������ڲ���ת */
+ return -1;
+ }
+
+ switch(p_ip_hdr->ip_p){
+ case IPPROTO_TCP:
+ if(ADDR_TYPE_TCP == expect_layer_type){
+ skip_len = 0;
+ break;
+ }else{
+ skip_len = -1; /* tcp ��֮�ϲ���������Э�� */
+ }
+ break;
+
+ case IPPROTO_UDP:
+ if(ADDR_TYPE_UDP == expect_layer_type){
+ skip_len = 0;
+ break;
+ }else{
+ skip_len = udp_jump_to_layer(raw_data+ip_hdr_len, ADDR_TYPE_UDP, expect_layer_type);
+ }
+ break;
+
+ case IPPROTO_IPV6:
+ if(__ADDR_TYPE_IP_PAIR_V6 == expect_layer_type){
+ skip_len = 0;
+ break;
+ }else{
+ skip_len = ipv6_jump_to_layer(raw_data+ip_hdr_len, __ADDR_TYPE_IP_PAIR_V6, expect_layer_type);
+ }
+ break;
+
+ case IPPROTO_GRE:
+ if((ADDR_TYPE_GRE == expect_layer_type) || (ADDR_TYPE_PPTP == expect_layer_type)){
+ skip_len = 0;
+ break;
+ }else{
+ skip_len = gre_jump_to_layer(raw_data+ip_hdr_len, ADDR_TYPE_GRE, expect_layer_type);
+ }
+ break;
+
+ default:
+ skip_len = -1;
+ break;
+ }
+
+ if(skip_len < 0){
+ return -1;
+ }
+
+ return skip_len + sizeof(struct ip);
+}
+
+static int ipv6_jump_to_layer(const char *raw_data, int raw_layer_type, int expect_layer_type)
+{
+ const struct mesa_ip6_hdr *a_packet = (const struct mesa_ip6_hdr *)raw_data;
+ UINT8 next_hdr_type = a_packet->ip6_nxt_hdr;
+ UINT8 *next_hdr_ptr = (UINT8 *)a_packet + sizeof(struct mesa_ip6_hdr);
+ int skip_len = 0;
+ int offset_to_ip6 = 0;
+
+ if(raw_layer_type == expect_layer_type){
+ return 0;
+ }
+
+ while(1){
+ offset_to_ip6 = 0;
+ switch(next_hdr_type)
+ {
+ case NEXTHDR_HOP:
+ case NEXTHDR_ROUTING:
+ case NEXTHDR_AUTH:
+ case NEXTHDR_DEST:
+ offset_to_ip6 = (*(next_hdr_ptr + 1))*8 + 8; /* ѡ�����8�ֽ�Ϊ��λ */
+ break;
+
+ case NEXTHDR_IPIP:
+ if(__ADDR_TYPE_IP_PAIR_V4 == expect_layer_type){
+ skip_len = next_hdr_ptr - (UINT8 *)raw_data;
+ }else{
+ skip_len = ipv4_jump_to_layer((const char *)next_hdr_ptr, __ADDR_TYPE_IP_PAIR_V4, expect_layer_type);
+ if(skip_len < 0){
+ return -1;
+ }else{
+ return skip_len + next_hdr_ptr - (UINT8 *)raw_data;
+ }
+ }
+ goto done;
+ break;
+
+ case NEXTHDR_NONE:
+ skip_len = -1;
+ goto done;
+ break;
+
+ case NEXTHDR_ICMP: /* IMCP���ٳ�������Э�� */
+ skip_len = -1;
+ goto done;
+ break;
+
+ case NEXTHDR_TCP:
+ if(ADDR_TYPE_TCP == expect_layer_type){
+ skip_len = next_hdr_ptr - (UINT8 *)raw_data;
+ }else{
+ skip_len = -1;
+ }
+ goto done;
+ break;
+
+ case NEXTHDR_UDP:
+ if(ADDR_TYPE_UDP == expect_layer_type){
+ skip_len = next_hdr_ptr - (UINT8 *)raw_data;
+ }else{
+ skip_len = udp_jump_to_layer((char *)next_hdr_ptr, ADDR_TYPE_UDP, expect_layer_type);
+ if(skip_len < 0){
+ return -1;
+ }else{
+ return skip_len + next_hdr_ptr - (UINT8 *)raw_data;
+ }
+ }
+ goto done;
+ break;
+
+ case NEXTHDR_FRAGMENT:
+ /* IP��Ƭ���ټ������ڲ���ת */
+ skip_len = -1;
+ goto done;
+ break;
+
+ case NEXTHDR_ESP:
+ skip_len = -1;
+ goto done;
+
+ default:
+ snprintf(_g_mesa_jump_layer_last_error, PIPE_BUF, "ipv6_jump_to_layer(): unknown IPv6 header type:0x%x!", next_hdr_type);
+ skip_len = -1;
+ goto done;
+ break;
+ }
+
+ next_hdr_type = *next_hdr_ptr;
+ next_hdr_ptr += offset_to_ip6;
+ }
+
+done:
+ if(skip_len < 0){
+ return -1;
+ }
+
+ return skip_len;
+}
+
+static int ppp_jump_to_layer(const char *raw_data, int raw_layer_type, int expect_layer_type)
+{
+ int skip_len = 0;
+ struct mesa_ppp_hdr *ppp_data_hdr;
+ char *next_hdr;
+
+ if(raw_layer_type == expect_layer_type){
+ return 0;
+ }
+ ppp_data_hdr = (struct mesa_ppp_hdr *)raw_data;
+ next_hdr = (char *)raw_data + sizeof(struct mesa_ppp_hdr);
+
+ switch(ntohs(ppp_data_hdr->protocol)){
+ case PPP_PROTOCOL_IPv4:
+ if(__ADDR_TYPE_IP_PAIR_V4 == expect_layer_type){
+ break;
+ }else{
+ skip_len = ipv4_jump_to_layer(next_hdr, __ADDR_TYPE_IP_PAIR_V4, expect_layer_type);
+ }
+ break;
+
+ case PPP_IPV6:
+ if(__ADDR_TYPE_IP_PAIR_V6 == expect_layer_type){
+ break;
+ }else{
+ skip_len = ipv6_jump_to_layer(next_hdr, __ADDR_TYPE_IP_PAIR_V6, expect_layer_type);
+ }
+ break;
+
+ case PPP_COMP:
+ case PPP_CCP:
+ case PPP_IPCP:
+ case PPP_PAP:
+ case PPP_CHAP:
+ case PPP_LQR:
+ case PPP_PROTOCOL_LCP:
+
+ /* ������Ӧ�ò�Э�� */
+ skip_len = -1;
+ break;
+
+ default:
+ snprintf(_g_mesa_jump_layer_last_error, PIPE_BUF, "ppp_jump_to_layer(): unsupport ppp pro:0x%x!", ntohs(ppp_data_hdr->protocol));
+ break;
+ }
+
+ if(skip_len < 0){
+ return -1;
+ }
+
+ return skip_len + sizeof(struct mesa_ppp_hdr);
+}
+
+static int pppoe_jump_to_layer(const char *raw_data, int raw_layer_type, int expect_layer_type)
+{
+ int skip_len = 0;
+ struct mesa_pppoe_session_hdr *pppoe_ses_hdr;
+ char *next_hdr;
+
+ if(raw_layer_type == expect_layer_type){
+ return 0;
+ }
+ pppoe_ses_hdr = (struct mesa_pppoe_session_hdr *)raw_data;
+ next_hdr = (char *)raw_data + sizeof(struct mesa_pppoe_session_hdr);
+
+ switch(ntohs(pppoe_ses_hdr->ppp_protocol)){
+ case PPP_PROTOCOL_IPv4:
+ if(__ADDR_TYPE_IP_PAIR_V4 == expect_layer_type){
+ break;
+ }else{
+ skip_len = ipv4_jump_to_layer(next_hdr, __ADDR_TYPE_IP_PAIR_V4, expect_layer_type);
+ }
+ break;
+
+ case PPP_IPV6:
+ if(__ADDR_TYPE_IP_PAIR_V6 == expect_layer_type){
+ break;
+ }else{
+ skip_len = ipv6_jump_to_layer(next_hdr, __ADDR_TYPE_IP_PAIR_V6, expect_layer_type);
+ }
+ break;
+
+ case PPP_COMP:
+ case PPP_CCP:
+ case PPP_IPCP:
+ case PPP_PAP:
+ case PPP_CHAP:
+ case PPP_LQR:
+ case PPP_PROTOCOL_LCP:
+
+ /* ������Ӧ�ò�Э�� */
+ skip_len = -1;
+ break;
+
+ default:
+ snprintf(_g_mesa_jump_layer_last_error, PIPE_BUF, "pppoe_jump_to_layer(): unsupport ppp pro:0x%x!", ntohs(pppoe_ses_hdr->ppp_protocol));
+ break;
+
+ }
+
+ if(skip_len < 0){
+ return -1;
+ }
+
+ return skip_len + sizeof(struct mesa_pppoe_session_hdr);
+}
+
+
+extern int __mjl_set_mpls_addr(struct layer_addr_mpls *addr, const unsigned char *raw_mpls_pkt_data);
+static int mpls_jump_to_layer(const char *raw_data, int raw_layer_type, int expect_layer_type)
+{
+ int skip_len = 0;
+ struct layer_addr_mpls mpls_addr = {};
+ const char *next_layer_data;
+ int mpls_layer_len;
+
+ if(raw_layer_type == expect_layer_type){
+ return 0;
+ }
+
+ __mjl_set_mpls_addr(&mpls_addr, (unsigned char *)raw_data);
+ mpls_layer_len = mpls_addr.c2s_layer_num * sizeof(struct mesa_mpls_hdr);
+ if(mpls_addr.c2s_has_ctrl_word){
+ mpls_layer_len += sizeof(int);
+ }
+
+ next_layer_data = raw_data + mpls_layer_len;
+
+ /* MPLSû���ֶα�ʶ��һ����ʲô, ���²���һ���IP���� */
+ if((*next_layer_data & 0xF0) == 0x40){
+ skip_len = ipv4_jump_to_layer(next_layer_data, __ADDR_TYPE_IP_PAIR_V4, expect_layer_type);
+ }else if((*next_layer_data & 0xF0) == 0x60){
+ skip_len = ipv6_jump_to_layer(next_layer_data, __ADDR_TYPE_IP_PAIR_V6, expect_layer_type);
+ }else{
+ /* VPLS�Ͳ���control wordһ������, ��__mjl_set_mpls_addr()������, �������Control word, next_layer_data�Ѿ����������ֽڵ�control word */
+ skip_len = eth_jump_to_layer(next_layer_data, ADDR_TYPE_MAC, expect_layer_type);
+ if(skip_len < 0){
+ snprintf(_g_mesa_jump_layer_last_error, PIPE_BUF,"WARNING: jmp unsupport type in MPLS to Ethernet, 0x%x!",
+ (unsigned char)(*next_layer_data));
+ return -1;
+ }
+ }
+
+ return skip_len + mpls_layer_len;
+}
+
+static int __common_eth_type_dispatch(UINT16 eth_type, const char *next_layer_data, int raw_layer_type, int expect_layer_type)
+{
+ int skip_len = 0;
+
+ switch(eth_type){
+ case ETH_P_ARP:
+ if(ADDR_TYPE_ARP == expect_layer_type){
+ break;
+ }else{
+ skip_len = arp_jump_to_layer(next_layer_data, ADDR_TYPE_ARP, expect_layer_type);
+ }
+ break;
+
+ case ETH_P_8021Q:
+ case ETH_P_8021AD:
+ if(ADDR_TYPE_VLAN == expect_layer_type){
+ break;
+ }else{
+ skip_len = vlan8021q_jump_to_layer(next_layer_data, ADDR_TYPE_VLAN, expect_layer_type);
+ }
+ break;
+
+ case ETH_P_IP:
+ if(__ADDR_TYPE_IP_PAIR_V4 == expect_layer_type){
+ break;
+ }else{
+ skip_len = ipv4_jump_to_layer(next_layer_data, __ADDR_TYPE_IP_PAIR_V4, expect_layer_type);
+ }
+ break;
+
+ case ETH_P_IPV6:
+ if(__ADDR_TYPE_IP_PAIR_V6 == expect_layer_type){
+ break;
+ }else{
+ skip_len = ipv6_jump_to_layer(next_layer_data, __ADDR_TYPE_IP_PAIR_V6, expect_layer_type);
+ }
+ break;
+
+ case ETH_P_PPP_SES:
+ if(ADDR_TYPE_PPPOE_SES == expect_layer_type){
+ break;
+ }else{
+ skip_len = pppoe_jump_to_layer(next_layer_data, ADDR_TYPE_PPPOE_SES, expect_layer_type);
+ }
+ break;
+
+ case ETH_P_MPLS_UC: /* MPLS, ETH_P_MPLS_UC */
+ skip_len = mpls_jump_to_layer(next_layer_data, ADDR_TYPE_MPLS, expect_layer_type);
+ break;
+
+ default:
+ skip_len = -1;
+ break;
+ }
+
+ return skip_len;
+}
+
+/* �����紫��ĵ�ַת��Ϊ�ڴ�ṹ, ����ҵ�������� */
+static int __mjl_vlan_addr_net_to_mem(const struct mesa_vlan_detail_hdr *net_vlan_hdr, struct single_layer_vlan_addr *mem_vlan_hdr)
+{
+ mem_vlan_hdr->VID = htons(net_vlan_hdr->vlan_id_high << 8 | net_vlan_hdr->vlan_id_low);
+ mem_vlan_hdr->TPID = net_vlan_hdr->type;
+ mem_vlan_hdr->PCP = net_vlan_hdr->priority;
+ mem_vlan_hdr->DEI = net_vlan_hdr->del_flag;
+
+ return 0;
+}
+
+static int __mjl_set_vlan_addr(struct layer_addr_vlan *addr, const unsigned char *vlan_tag)
+{
+ int i;
+ const struct mesa_vlan_detail_hdr *net_vhdr;
+ int vlan_layer_len = 0;
+
+ memset(addr, 0, sizeof(struct layer_addr_vlan));
+
+ for(i = 0; i < MAX_VLAN_ADDR_LAYER; i++){
+ net_vhdr = (struct mesa_vlan_detail_hdr *)vlan_tag;
+ //memcpy(&addr->c2s_addr_array[i], vlan_tag, sizeof(struct mesa_vlan_hdr));
+
+ __mjl_vlan_addr_net_to_mem(net_vhdr, &addr->c2s_addr_array[i]);
+ vlan_tag += sizeof(struct mesa_vlan_detail_hdr);
+ vlan_layer_len += sizeof(struct mesa_vlan_detail_hdr);
+ addr->c2s_layer_num++;
+ if(ETH_P_8021Q != ntohs(net_vhdr->type)){
+ break;
+ }
+ }
+
+ return vlan_layer_len;
+}
+
+static int vlan8021q_jump_to_layer(const char *raw_data, int raw_layer_type, int expect_layer_type)
+{
+ int skip_len = 0;
+ struct layer_addr_vlan vlan_addr;
+ const char *next_layer_data;
+ //const struct mesa_vlan_hdr *vhdr;
+ unsigned short next_layer_type;
+ int vlan_layer_len;
+
+ if(raw_layer_type == expect_layer_type){
+ return 0;
+ }
+
+ __mjl_set_vlan_addr(&vlan_addr, (const unsigned char *)raw_data);
+ vlan_layer_len = sizeof(struct mesa_vlan_hdr) * vlan_addr.c2s_layer_num;
+ next_layer_data = raw_data + vlan_layer_len;
+ //vhdr = (struct mesa_vlan_hdr *)&vlan_addr.c2s_addr_array[vlan_addr.c2s_layer_num-1];
+ next_layer_type = ntohs(vlan_addr.c2s_addr_array[vlan_addr.c2s_layer_num-1].TPID);
+
+ switch(next_layer_type){
+ case ETH_P_ARP:
+ if(ADDR_TYPE_ARP == expect_layer_type){
+ break;
+ }else{
+ skip_len = arp_jump_to_layer(next_layer_data, ADDR_TYPE_ARP, expect_layer_type);
+ }
+ break;
+
+ case ETH_P_IP:
+ if(__ADDR_TYPE_IP_PAIR_V4 == expect_layer_type){
+ break;
+ }else{
+ skip_len = ipv4_jump_to_layer(next_layer_data, __ADDR_TYPE_IP_PAIR_V4, expect_layer_type);
+ }
+ break;
+
+ case ETH_P_IPV6:
+ if(__ADDR_TYPE_IP_PAIR_V6 == expect_layer_type){
+ break;
+ }else{
+ skip_len = ipv6_jump_to_layer(next_layer_data, __ADDR_TYPE_IP_PAIR_V6, expect_layer_type);
+ }
+ break;
+
+ case ETH_P_PPP_SES:
+ if(ADDR_TYPE_PPPOE_SES == expect_layer_type){
+ break;
+ }else{
+ skip_len = pppoe_jump_to_layer(next_layer_data, ADDR_TYPE_PPPOE_SES, expect_layer_type);
+ }
+ break;
+
+ case ETH_P_PPP_DISC: /* pppoe���ֽ׶� */
+ skip_len = -1;
+ break;
+
+ /* QinQ */
+ case ETH_P_8021Q:
+ snprintf(_g_mesa_jump_layer_last_error, PIPE_BUF, "vlan8021q_jump_to_layer(): multiple VLAN combine to one layer!");
+ assert(0);
+ break;
+
+ case ETH_P_MPLS_UC:
+ skip_len = mpls_jump_to_layer(next_layer_data, ADDR_TYPE_MPLS, expect_layer_type);
+ break;
+
+ default:
+ snprintf(_g_mesa_jump_layer_last_error, PIPE_BUF, "vlan8021q_jump_to_layer(): unsupport type: 0x%x!", next_layer_type);
+ skip_len = -1;
+ }
+
+ if(skip_len < 0){
+ return -1;
+ }
+
+ return skip_len + vlan_layer_len;
+}
+
+static int eth_jump_to_layer(const char *raw_data, int raw_layer_type, int expect_layer_type)
+{
+ struct ethhdr *p_eth_hdr = (struct ethhdr *)raw_data;
+ unsigned short eth_type = ntohs(p_eth_hdr->h_proto);
+ //int skip_len = -1;
+ const char *next_layer_data = raw_data + sizeof(struct ethhdr);
+ int layer_skip_len;
+
+ if(raw_layer_type == expect_layer_type){
+ return 0;
+ }
+
+ layer_skip_len = __common_eth_type_dispatch(eth_type, next_layer_data, raw_layer_type, expect_layer_type);
+ if(layer_skip_len < 0){
+ return -1;
+ }
+
+ return layer_skip_len + sizeof(struct ethhdr);
+}
+
+
+static int mac_in_mac_jump_to_layer(const char *raw_data, int raw_layer_type, int expect_layer_type)
+{
+ struct ethhdr *inner_eth_hdr = (struct ethhdr *)(raw_data + sizeof(struct ethhdr ));
+ unsigned short inner_eth_type = ntohs(inner_eth_hdr->h_proto);
+ //int skip_len = -1;
+ const char *next_layer_data = raw_data + sizeof(struct ethhdr);
+ int layer_skip_len;
+
+ if(raw_layer_type == expect_layer_type){
+ return 0;
+ }
+
+ layer_skip_len = __common_eth_type_dispatch(inner_eth_type, next_layer_data, raw_layer_type, expect_layer_type);
+ if(layer_skip_len < 0){
+ return -1;
+ }
+
+ return layer_skip_len + sizeof(struct ethhdr) * 2;
+}
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ return value:
+ Non-NULL: the pointer to expect layer;
+ NULL: not found expect layer.
+*/
+const void *MESA_net_jump_to_layer(const void *raw_data, int raw_layer_type, int expect_layer_type)
+{
+ int ret;
+
+ if(check_layer_type(raw_layer_type) < 0){
+ return NULL;
+ }
+
+ if(check_layer_type(expect_layer_type) < 0){
+ return NULL;
+ }
+
+ if(ADDR_TYPE_IPV4 == raw_layer_type){
+ /* ת�ɴ�IPv4��ַ���� */
+ raw_layer_type = __ADDR_TYPE_IP_PAIR_V4;
+ }
+
+ if(ADDR_TYPE_IPV6 == raw_layer_type){
+ /* ת�ɴ�IPv6��ַ���� */
+ raw_layer_type = __ADDR_TYPE_IP_PAIR_V6;
+ }
+
+ if(ADDR_TYPE_IPV4 == expect_layer_type){
+ /* ת�ɴ�IPv4��ַ���� */
+ expect_layer_type = __ADDR_TYPE_IP_PAIR_V4;
+ }
+
+ if(ADDR_TYPE_IPV6 == expect_layer_type){
+ /* ת�ɴ�IPv6��ַ���� */
+ expect_layer_type = __ADDR_TYPE_IP_PAIR_V6;
+ }
+
+ if(raw_layer_type == expect_layer_type){
+ return raw_data;
+ }
+
+ switch(raw_layer_type){
+ case ADDR_TYPE_MAC:
+ ret = eth_jump_to_layer((const char *)raw_data, raw_layer_type, expect_layer_type);
+ break;
+
+ case ADDR_TYPE_ARP:
+ ret = arp_jump_to_layer((const char *)raw_data, raw_layer_type, expect_layer_type);
+ break;
+ case ADDR_TYPE_VLAN:
+ ret = vlan8021q_jump_to_layer((const char *)raw_data, raw_layer_type, expect_layer_type);
+ break;
+
+ case __ADDR_TYPE_IP_PAIR_V4:
+ ret = ipv4_jump_to_layer((const char *)raw_data, raw_layer_type, expect_layer_type);
+ break;
+
+ case __ADDR_TYPE_IP_PAIR_V6:
+ ret = ipv6_jump_to_layer((const char *)raw_data, raw_layer_type, expect_layer_type);
+ break;
+
+ case ADDR_TYPE_MAC_IN_MAC:
+ ret = mac_in_mac_jump_to_layer((const char *)raw_data, raw_layer_type, expect_layer_type);
+ break;
+
+ case ADDR_TYPE_UDP:
+ ret = udp_jump_to_layer((const char *)raw_data, raw_layer_type, expect_layer_type);
+ break;
+
+ case ADDR_TYPE_MPLS:
+ ret = mpls_jump_to_layer((const char *)raw_data, raw_layer_type, expect_layer_type);
+ break;
+
+ case ADDR_TYPE_GRE:
+ ret = gre_jump_to_layer((const char *)raw_data, raw_layer_type, expect_layer_type);
+ break;
+
+ case ADDR_TYPE_PPPOE_SES:
+ return NULL;
+ break;
+
+ default:
+ snprintf(_g_mesa_jump_layer_last_error, PIPE_BUF, "MESA_net_jump_to_layer(): unsupport raw_layer_type:%d in MESA_net_jump_to_layer()!", raw_layer_type);
+ return NULL;
+ }
+
+ if(ret < 0){
+ return NULL;
+ }
+
+ return ((const char *)raw_data + ret);
+}
+
+/*
+ ��MESA_net_jump_to_layer()������:
+ MESA_net_jump_to_layer()������㿪ʼ, �ҵ���һ�����������IJ���˳�;
+ MESA_net_jump_to_layer_greedy()��һֱ���������ڲ�Э��ͷ, �ʺ�����ģʽ.
+
+ return value:
+ Non-NULL: the pointer to expect layer;
+ NULL: not found expect layer.
+*/
+const void *MESA_net_jump_to_layer_greedy(const void *raw_data, int raw_layer_type, int expect_layer_type)
+{
+ int skip_len;
+ const void *expect_layer;
+ const void *success_layer = NULL; /* ���һ�γɹ��ҵ��IJ� */
+ int new_raw_layer_type = raw_layer_type; /* ����ת������, ���ܻ�����м����Ϣ */
+ const char *new_next_layer_data = (char *)raw_data;
+
+ if(ADDR_TYPE_IPV4 == raw_layer_type){
+ /* ת�ɴ�IPv4��ַ���� */
+ raw_layer_type = __ADDR_TYPE_IP_PAIR_V4;
+ }
+
+ if(ADDR_TYPE_IPV6 == raw_layer_type){
+ /* ת�ɴ�IPv6��ַ���� */
+ raw_layer_type = __ADDR_TYPE_IP_PAIR_V6;
+ }
+
+ if(ADDR_TYPE_IPV4 == expect_layer_type){
+ /* ת�ɴ�IPv4��ַ���� */
+ expect_layer_type = __ADDR_TYPE_IP_PAIR_V4;
+ }
+
+ if(ADDR_TYPE_IPV6 == expect_layer_type){
+ /* ת�ɴ�IPv6��ַ���� */
+ expect_layer_type = __ADDR_TYPE_IP_PAIR_V6;
+ }
+
+ expect_layer = MESA_net_jump_to_layer(new_next_layer_data, new_raw_layer_type, expect_layer_type);
+ while(expect_layer){
+ success_layer = expect_layer;
+
+ switch(expect_layer_type){
+ case __ADDR_TYPE_IP_PAIR_V4:
+ {
+ const struct mesa_ip4_hdr *ip4hdr = (const struct mesa_ip4_hdr *)expect_layer;
+ if((ntohs(ip4hdr->ip_off) & IP_MF ) || (ntohs(ip4hdr->ip_off) & IP_OFFMASK)){
+ /* IP��Ƭ���ټ������ڲ���ת */
+ goto done;
+ }
+ if(IPPROTO_UDP == ip4hdr->ip_p){
+ new_next_layer_data = (char *)expect_layer + ip4hdr->ip_hl * 4;
+ new_raw_layer_type = ADDR_TYPE_UDP; /* IP���������һ��ƫ�� */
+ }else if(IPPROTO_GRE == ip4hdr->ip_p){
+ new_next_layer_data = (char *)expect_layer + ip4hdr->ip_hl * 4;
+ new_raw_layer_type = ADDR_TYPE_GRE; /* GRE */
+ }else{
+ //TODO 2, IPIP, L2TPv3
+ goto done;
+ }
+ }
+ break;
+
+ case __ADDR_TYPE_IP_PAIR_V6:
+ {
+ //TODO2,
+ goto done;
+ }
+ break;
+
+ case ADDR_TYPE_UDP:
+ {
+ skip_len = udp_jump_to_layer_greedy((char *)expect_layer, ADDR_TYPE_UDP, expect_layer_type);
+ if(skip_len < 0){
+ goto done;
+ }
+
+ success_layer = (char *)expect_layer + skip_len;
+ goto done;
+ }
+ break;
+
+ default:
+ snprintf(_g_mesa_jump_layer_last_error, PIPE_BUF, "MESA_net_jump_to_layer_greedy() not support layer type:%d\n", expect_layer_type);
+ goto done;
+ }
+
+ expect_layer = MESA_net_jump_to_layer(new_next_layer_data, new_raw_layer_type, expect_layer_type);
+ }
+
+done:
+ return success_layer;
+}
+
+/* ģ��tcpdump��ʽ: 192.168.40.137.22 > 192.168.36.40.49429 */
+const char *MESA_jump_layer_ipv4_ntop(const struct ip *ip4_hdr, char *out_buf, int buf_len )
+{
+ unsigned char inner_ip_proto;
+ const struct mesa_tcp_hdr *inner_thdr = NULL;
+ const struct mesa_udp_hdr *inner_uhdr = NULL;
+ unsigned short sport, dport;
+ char ipsrc_str[INET6_ADDRSTRLEN];
+ char ipdst_str[INET6_ADDRSTRLEN];
+
+ inner_ip_proto = ip4_hdr->ip_p;
+ if(IPPROTO_TCP == inner_ip_proto){
+ inner_thdr = (struct mesa_tcp_hdr *)((char *)ip4_hdr + ip4_hdr->ip_hl*4);
+ sport = ntohs(inner_thdr->th_sport);
+ dport = ntohs(inner_thdr->th_dport);
+ }else if(IPPROTO_UDP){
+ inner_uhdr = (struct mesa_udp_hdr *)((char *)ip4_hdr + ip4_hdr->ip_hl*4);
+ sport = ntohs(inner_uhdr->uh_sport);
+ dport = ntohs(inner_uhdr->uh_dport);
+ }else{
+ snprintf(_g_mesa_jump_layer_last_error, PIPE_BUF, "MESA_jump_layer_ipv4_ntop() error, unsupport ip protocol:%d", inner_ip_proto);
+ return NULL;
+ }
+
+ inet_ntop(AF_INET, &ip4_hdr->ip_src.s_addr, ipsrc_str, sizeof(ipsrc_str));
+ inet_ntop(AF_INET, &ip4_hdr->ip_dst.s_addr, ipdst_str, sizeof(ipdst_str));
+
+ snprintf(out_buf, buf_len, "%s.%u > %s.%u", ipsrc_str, sport, ipdst_str, dport);
+
+ return out_buf;
+}
+
+
+const char *MESA_jump_layer_ipv6_ntop(const struct ip6_hdr *ip6_hdr, char *out_buf, int buf_len)
+{
+ unsigned char inner_ip_proto;
+ const struct tcphdr *inner_thdr = NULL;
+ const struct udphdr *inner_uhdr = NULL;
+ unsigned short sport, dport;
+ char ipsrc_str[INET6_ADDRSTRLEN];
+ char ipdst_str[INET6_ADDRSTRLEN];
+
+ /* TODO: �˴��п��ܰ���ѡ�����Ƭ, ����ֱ�ӻ�ȡ��һ���Э������, ��˴��������Ͻ�! */
+ inner_ip_proto = ip6_hdr->ip6_nxt;
+ if(IPPROTO_TCP == inner_ip_proto){
+ inner_thdr = (struct tcphdr *)((char *)ip6_hdr + sizeof(struct ip6_hdr));
+ sport = inner_thdr->source;
+ dport = inner_thdr->dest;
+ }else if(IPPROTO_UDP){
+ inner_uhdr = (struct udphdr *)((char *)ip6_hdr + sizeof(struct ip6_hdr));
+ sport = inner_uhdr->source;
+ dport = inner_uhdr->dest;
+ }else{
+ snprintf(_g_mesa_jump_layer_last_error, PIPE_BUF, "MESA_jump_layer_ipv6_ntop() error, unsupport ip6_nxt_hdr:%d", inner_ip_proto);
+ return NULL;
+ }
+
+ inet_ntop(AF_INET6, &ip6_hdr->ip6_src, ipsrc_str, sizeof(ipsrc_str));
+ inet_ntop(AF_INET6, &ip6_hdr->ip6_dst, ipdst_str, sizeof(ipdst_str));
+
+ snprintf(out_buf, buf_len, "%s.%u > %s.%u", ipsrc_str, sport, ipdst_str, dport);
+
+ return out_buf;
+}
+
+const char *MESA_jump_layer_get_last_error(void)
+{
+ return _g_mesa_jump_layer_last_error;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
diff --git a/src/Makefile b/src/Makefile
new file mode 100644
index 0000000..38a95cc
--- /dev/null
+++ b/src/Makefile
@@ -0,0 +1,10 @@
+INC=-I../inc -I/opt/MESA/include -I/opt/MESA/include/MESA -I/opt/MESA/include/MESA/stream_inc
+CFLAGS=-g -Wall
+
+all:libMESA_jump_layer.so
+
+libMESA_jump_layer.so:MESA_jump_layer.o
+ g++ -o $@ $^ -fPIC -shared
+
+MESA_jump_layer.o:MESA_jump_layer.cpp
+ g++ -c -fPIC -o $@ $^ $(INC) $(CFLAGS)
diff --git a/src/deal_ipv6.h b/src/deal_ipv6.h
new file mode 100644
index 0000000..9fe520f
--- /dev/null
+++ b/src/deal_ipv6.h
@@ -0,0 +1,113 @@
+#ifndef __DEAL_IPV6_H_
+#define __DEAL_IPV6_H_
+
+#include <netinet/ip6.h>
+
+#define IPV6_DEBUG (0)
+
+#define IPV6_FRAG_DUMP (1 && IPV6_DEBUG)
+
+#define IPV6_MAXPLEN (65535)
+
+#define IPV6_FRAG_RESERVED_HDR_LEN (40) /* Ԥ����һ��IPv6��Ƭͷ������ */
+
+//#define IPV6_FRAG_TIMEOUT (60) /* ���鳬ʱʱ�� */
+/*
+ 2015-12-02 lijia modify,
+ ��ȻRFC�涨, 60�������з�Ƭ������ɾ��ǺϷ���,
+ ���ʵ�����, IPv6��Ƭ�����10���ڻ�δ�������, ����Ϊ�ǹ�����Ϊ�򶪰�, ֱ��free.
+*/
+#define IPV6_FRAG_TIMEOUT (10) /* ���鳬ʱʱ�� */
+
+
+#define IPV6_FRAG_MEM_FREE_ONCE (512*1024) /* ÿ���ͷ��ڴ����� */
+#define IPV6_FRAG_MEM_HIGH_THRESH (16*1024*1024) /* �ڴ����� */
+
+#define IPV6_FRAG_NUM_PER_IPQ (100) /* ͬһIPQ����Ƭ���� */
+
+#if IPV6_DEBUG
+#define IPV6_PRINT(fmt, args...) printf(fmt, ##args)
+#else
+#define IPV6_PRINT(fmt, args...)
+#endif
+
+
+struct simple_ip6_hdr
+{
+ unsigned char ip6_flags[4]; /* version, traffic-class, flow-label */
+ u_int16_t ip6_payload_len; /* payload length, not contain header */
+ unsigned char ip6_nxt_hdr; /* next header, same as protocol in IPv4 */
+ unsigned char ip6_hop; /* hop limit, same as TTL in IPv4 */
+ struct in6_addr ip6_src; /* source address */
+ struct in6_addr ip6_dst; /* dest address */
+};
+
+
+/*
+ * NextHeader field of IPv6 header
+ */
+#define NEXTHDR_HOP 0 /* Hop-by-hop option header. */
+#define NEXTHDR_IPIP 4 /* IPIP header. */
+#define NEXTHDR_TCP 6 /* TCP segment. */
+#define NEXTHDR_UDP 17 /* UDP message. */
+#define NEXTHDR_IPV6 41 /* IPv6 in IPv6 */
+#define NEXTHDR_ROUTING 43 /* Routing header. */
+#define NEXTHDR_FRAGMENT 44 /* Fragmentation/reassembly header. */
+#define NEXTHDR_ESP 50 /* Encapsulating security payload. */
+#define NEXTHDR_AUTH 51 /* Authentication header. */
+#define NEXTHDR_ICMP 58 /* ICMP for IPv6. */
+#define NEXTHDR_NONE 59 /* No next header */
+#define NEXTHDR_DEST 60 /* Destination options header. */
+#define NEXTHDR_MOBILITY 135 /* Mobility header. */
+
+struct ipv6_opt_hdr{
+ unsigned char nexthdr;
+ unsigned char hdrlen;
+ /*
+ * TLV encoded option data follows.
+ */
+} __attribute__((packed)); /* required for some archs */
+
+
+
+/*
+ * Hop-By-Hop header
+ */
+struct ipv6_hop_hdr{
+ unsigned char nexthdr;
+ unsigned char hdrlen;
+};
+
+
+/*
+ * fragmentation header
+ */
+
+#define IPv6_FRAG_ISF (1) /* ������һ����Ƭ�� */
+#define IPv6_FRAG_NEW (2) /* ���յ����з�Ƭ��������ɵ��°� */
+
+#define IP6_MF (0x0001)
+
+struct ipv6_frag_hdr{
+ unsigned char nexthdr;
+ unsigned char reserved;
+ unsigned short frag_off;
+ unsigned int identification;
+};
+
+struct ipv6_frag_key{
+ unsigned int identification; /* ���п��ܲ�ͬ��ֵ���ڽṹ��ǰ�棬�Ƚ�ʱ���һЩ */
+ int __pad__; /* ����ṹ8�ֽڶ��� */
+ struct in6_addr ip6_src; /* source address */
+ struct in6_addr ip6_dst; /* dest address */
+ struct streaminfo_private *pfstream_pr;
+};
+
+struct ipv6_frag_private{
+ unsigned char raw_next_hdr; /* ԭʼIP���ĵ�һ���ɷ�Ƭ����ͷ������ */
+ int unfragmentable_len; /* ԭʼIP���IJ��ɷ�Ƭ���ֳ��� */
+};
+
+
+#endif
+
diff --git a/src/mesa_net.h b/src/mesa_net.h
new file mode 100644
index 0000000..f0319f8
--- /dev/null
+++ b/src/mesa_net.h
@@ -0,0 +1,885 @@
+#ifndef _MESA_NET_H_
+#define _MESA_NET_H_
+
+#include <stdio.h>
+#include <endian.h>
+#include <netinet/in.h>
+#include <netinet/ip_icmp.h>
+#include <netinet/in_systm.h>
+#include <linux/ppp_defs.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#define BYTE_ALIGNED(n) __attribute__((packed, aligned(n)))
+
+
+#define SENDPACKET_ARP_H 0x1c /* ARP header: 28 bytes */
+#define SENDPACKET_ETH_H 0xe /* Etherner header: 14 bytes */
+#define SENDPACKET_IP_H 0x14 /* IP header: 20 bytes */
+/* See sendpacket-ospf.h for OSPF related header sizes */
+#define SENDPACKET_RIP_H 0x18 /* RIP header base: 24 bytes */
+#define SENDPACKET_TCP_H 0x14 /* TCP header: 20 bytes */
+#define SENDPACKET_UDP_H 0x8 /* UDP header: 8 bytes */
+
+/*
+ * Ethernet packet header prototype. Too many O/S's define this differently.
+ * Easy enough to solve that and define it here.
+ */
+#ifndef ETHER_ADDR_LEN
+#define ETHER_ADDR_LEN 6
+#endif
+#define ETHERTYPE_PUP 0x0200 /* PUP protocol */
+#define ETHERTYPE_IP 0x0800 /* IP protocol */
+#define ETHERTYPE_IPv6 0x86dd /* IPv6 protocol */
+#define ETHERTYPE_ARP 0x0806 /* Addr. resolution protocol */
+#define ETHERTYPE_REVARP 0x8035 /* reverse Addr. resolution protocol */
+#define ETHERTYPE_VLAN 0x8100 /* IEEE 802.1Q VLAN tagging */
+#define ETHERTYPE_LOOPBACK 0x9000 /* used to test interfaces */
+
+//#define ETH_P_8021AD 0x88A8
+//#define ETHERTYPE_PANGU_MAC_IN_MAC 0x88A8 /* 2018-08-16 lijia add, for pangu MAC-in-MAC */
+
+
+
+#define ETHERNET_HDR_LEN (14)
+struct mesa_ethernet_hdr
+{
+ u_int8_t ether_dhost[ETHER_ADDR_LEN]; /* destination ethernet address */
+ u_int8_t ether_shost[ETHER_ADDR_LEN]; /* source ethernet address */
+ u_int16_t ether_type; /* packet type ID */
+}BYTE_ALIGNED(1);
+
+
+/*
+ * IPv4 packet header prototype.
+ */
+#ifndef IP_RF
+#define IP_RF 0x8000 /* reserved fragment flag */
+#endif
+#ifndef IP_DF
+#define IP_DF 0x4000 /* dont fragment flag */
+#endif
+#ifndef IP_MF
+#define IP_MF 0x2000 /* more fragments flag */
+#endif
+#ifndef IP_OFFMASK
+#define IP_OFFMASK 0x1fff /* mask for fragmenting bits */
+#endif
+
+
+#define IPPROTO_L2TPV3 (115) /* L2TPv3, RFC3931-page17 */
+
+struct mesa_ip4_hdr
+{
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ u_int8_t ip_hl:4, /* header length */
+ ip_v:4; /* version */
+#elif __BYTE_ORDER == __BIG_ENDIAN
+ u_int8_t ip_v:4, /* version */
+ ip_hl:4; /* header length */
+#else
+#error "Please check <endian.h>"
+#endif
+ u_int8_t ip_tos; /* type of service */
+ u_int16_t ip_len; /* total length */
+ u_int16_t ip_id; /* identification */
+ u_int16_t ip_off;
+ u_int8_t ip_ttl; /* time to live */
+ u_int8_t ip_p; /* protocol */
+ u_int16_t ip_sum; /* checksum */
+ struct in_addr ip_src, ip_dst; /* source and dest address */
+};
+
+
+/*
+ * ARP packet header prototype. Too many O/S's define this differently.
+ * Easy enough to solve that and define it here.
+ */
+#define ARPOP_REQUEST 1 /* req to resolve address */
+#define ARPOP_REPLY 2 /* resp to previous request */
+#define ARPOP_REVREQUEST 3 /* req protocol address given hardware */
+#define ARPOP_REVREPLY 4 /* resp giving protocol address */
+#define ARPOP_INVREQUEST 8 /* req to identify peer */
+#define ARPOP_INVREPLY 9 /* resp identifying peer */
+
+
+#define ARPHRD_ETHER 1 /* ethernet hardware format */
+struct mesa_arp_hdr
+{
+ u_short ar_hrd; /* format of hardware address */
+
+ u_short ar_pro; /* format of protocol address */
+ u_char ar_hln; /* length of hardware address */
+ u_char ar_pln; /* length of protocol addres */
+ u_short ar_op; /* operation type */
+
+ /*
+ * These should implementation defined but I've hardcoded eth/IP.
+ */
+ u_char ar_sha[6]; /* sender hardware address */
+ u_char ar_spa[4]; /* sender protocol address */
+ u_char ar_tha[6]; /* target hardware address */
+ u_char ar_tpa[4]; /* target protocol address */
+};
+
+
+/*
+ * IPv6 packet header prototype, add by LiJia 2012-03-19.
+ */
+struct mesa_ip6_hdr
+{
+ u_int8_t ip6_flags[4]; /* version, traffic-class, flow-label */
+ u_int16_t ip6_payload_len; /* payload length, not contain header */
+ u_int8_t ip6_nxt_hdr; /* next header, same as protocol in IPv4 */
+ u_int8_t ip6_hop; /* hop limit, same as TTL in IPv4 */
+ struct in6_addr ip6_src; /* source address */
+ struct in6_addr ip6_dst; /* dest address */
+};
+
+
+struct mesa_icmp_echo_hdr{
+ unsigned char icmp_type;
+ unsigned char icmp_code;
+ unsigned short icmp_cksum;
+ unsigned short icd_id;
+ unsigned short icd_seq;
+ //char echo_data[];
+};
+
+
+/*
+ * ICMP packet header prototype. // from libnet-headers.h
+ */
+struct mesa_icmp_hdr
+{
+ u_char icmp_type;
+/*
+ * ICMP types.
+ */
+#ifndef ICMP_ECHOREPLY
+#define ICMP_ECHOREPLY 0
+#endif
+#ifndef ICMP_UNREACH
+#define ICMP_UNREACH 3
+#endif
+#ifndef ICMP_SOURCEQUENCH
+#define ICMP_SOURCEQUENCH 4
+#endif
+#ifndef ICMP_REDIRECT
+#define ICMP_REDIRECT 5
+#endif
+#ifndef ICMP_ECHO
+#define ICMP_ECHO 8
+#endif
+#ifndef ICMP_ROUTERADVERT
+#define ICMP_ROUTERADVERT 9
+#endif
+#ifndef ICMP_ROUTERSOLICIT
+#define ICMP_ROUTERSOLICIT 10
+#endif
+#ifndef ICMP_TIMXCEED
+#define ICMP_TIMXCEED 11
+#endif
+#ifndef ICMP_PARAMPROB
+#define ICMP_PARAMPROB 12
+#endif
+#ifndef ICMP_TSTAMP
+#define ICMP_TSTAMP 13
+#endif
+#ifndef ICMP_TSTAMPREPLY
+#define ICMP_TSTAMPREPLY 14
+#endif
+#ifndef ICMP_IREQ
+#define ICMP_IREQ 15
+#endif
+#ifndef ICMP_IREQREPLY
+#define ICMP_IREQREPLY 16
+#endif
+#ifndef ICMP_MASKREQ
+#define ICMP_MASKREQ 17
+#endif
+#ifndef ICMP_MASKREPLY
+#define ICMP_MASKREPLY 18
+#endif
+ u_char icmp_code;
+/*
+ * ICMP codes.
+ */
+#ifndef ICMP_UNREACH_NET
+#define ICMP_UNREACH_NET 0
+#endif
+#ifndef ICMP_UNREACH_HOST
+#define ICMP_UNREACH_HOST 1
+#endif
+#ifndef ICMP_UNREACH_PROTOCOL
+#define ICMP_UNREACH_PROTOCOL 2
+#endif
+#ifndef ICMP_UNREACH_PORT
+#define ICMP_UNREACH_PORT 3
+#endif
+#ifndef ICMP_UNREACH_NEEDFRAG
+#define ICMP_UNREACH_NEEDFRAG 4
+#endif
+#ifndef ICMP_UNREACH_SRCFAIL
+#define ICMP_UNREACH_SRCFAIL 5
+#endif
+#ifndef ICMP_UNREACH_NET_UNKNOWN
+#define ICMP_UNREACH_NET_UNKNOWN 6
+#endif
+#ifndef ICMP_UNREACH_HOST_UNKNOWN
+#define ICMP_UNREACH_HOST_UNKNOWN 7
+#endif
+#ifndef ICMP_UNREACH_ISOLATED
+#define ICMP_UNREACH_ISOLATED 8
+#endif
+#ifndef ICMP_UNREACH_NET_PROHIB
+#define ICMP_UNREACH_NET_PROHIB 9
+#endif
+#ifndef ICMP_UNREACH_HOST_PROHIB
+#define ICMP_UNREACH_HOST_PROHIB 10
+#endif
+#ifndef ICMP_UNREACH_TOSNET
+#define ICMP_UNREACH_TOSNET 11
+#endif
+#ifndef ICMP_UNREACH_TOSHOST
+#define ICMP_UNREACH_TOSHOST 12
+#endif
+#ifndef ICMP_UNREACH_FILTER_PROHIB
+#define ICMP_UNREACH_FILTER_PROHIB 13
+#endif
+#ifndef ICMP_UNREACH_HOST_PRECEDENCE
+#define ICMP_UNREACH_HOST_PRECEDENCE 14
+#endif
+#ifndef ICMP_UNREACH_PRECEDENCE_CUTOFF
+#define ICMP_UNREACH_PRECEDENCE_CUTOFF 15
+#endif
+#ifndef ICMP_REDIRECT_NET
+#define ICMP_REDIRECT_NET 0
+#endif
+#ifndef ICMP_REDIRECT_HOST
+#define ICMP_REDIRECT_HOST 1
+#endif
+#ifndef ICMP_REDIRECT_TOSNET
+#define ICMP_REDIRECT_TOSNET 2
+#endif
+#ifndef ICMP_REDIRECT_TOSHOST
+#define ICMP_REDIRECT_TOSHOST 3
+#endif
+#ifndef ICMP_TIMXCEED_INTRANS
+#define ICMP_TIMXCEED_INTRANS 0
+#endif
+#ifndef ICMP_TIMXCEED_REASS
+#define ICMP_TIMXCEED_REASS 1
+#endif
+#ifndef ICMP_PARAMPROB_OPTABSENT
+#define ICMP_PARAMPROB_OPTABSENT 1
+#endif
+
+ u_short icmp_sum;
+
+ union
+ {
+ struct
+ {
+ u_short id;
+ u_short seq;
+ }echo;
+
+#undef icmp_id
+#undef icmp_seq
+#define icmp_id hun.echo.id
+#define icmp_seq hun.echo.seq
+
+ u_long gateway;
+ struct
+ {
+ u_short pad;
+ u_short mtu;
+ }frag;
+ }hun;
+ union
+ {
+ struct
+ {
+ n_time its_otime;
+ n_time its_rtime;
+ n_time its_ttime;
+ }ts;
+ struct
+ {
+ struct ip idi_ip;
+ /* options and then 64 bits of data */
+ }ip;
+ u_long mask;
+ char data[1];
+
+#undef icmp_mask
+#define icmp_mask dun.mask
+#undef icmp_data
+#define icmp_data dun.data
+
+#undef icmp_otime
+#define icmp_otime dun.ts.its_otime
+#undef icmp_rtime
+#define icmp_rtime dun.ts.its_rtime
+#undef icmp_ttime
+#define icmp_ttime dun.ts.its_ttime
+ }dun;
+
+};
+
+/*
+ * TCP packet header prototype.
+ */
+#ifndef TH_FIN
+#define TH_FIN 0x01
+#endif
+#ifndef TH_SYN
+#define TH_SYN 0x02
+#endif
+#ifndef TH_RST
+#define TH_RST 0x04
+#endif
+#ifndef TH_PUSH
+#define TH_PUSH 0x08
+#endif
+#ifndef TH_ACK
+#define TH_ACK 0x10
+#endif
+#ifndef TH_URG
+#define TH_URG 0x20
+#endif
+struct mesa_tcp_hdr
+{
+ u_int16_t th_sport; /* source port */
+ u_int16_t th_dport; /* destination port */
+ u_int32_t th_seq; /* sequence number */
+ u_int32_t th_ack; /* acknowledgement number */
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ u_int8_t th_x2:4, /* (unused) */
+ th_off:4; /* data offset */
+#elif __BYTE_ORDER == __BIG_ENDIAN
+ u_int8_t th_off:4, /* data offset */
+ th_x2:4; /* (unused) */
+#else
+#error "Please check <endian.h>"
+#endif
+ u_int8_t th_flags; /* control flags */
+ u_int16_t th_win; /* window */
+ u_int16_t th_sum; /* checksum */
+ u_int16_t th_urp; /* urgent pointer */
+};
+
+
+/*
+ * UDP packet header prototype.
+ */
+struct mesa_udp_hdr
+{
+ u_int16_t uh_sport; /* soure port */
+ u_int16_t uh_dport; /* destination port */
+ u_int16_t uh_ulen; /* length */
+ u_int16_t uh_sum; /* checksum */
+};
+
+
+#define PPPOE_HDR_LEN (sizeof(struct mesa_pppoe_session_hdr))
+#define PPP_PROTOCOL_PAD (0x0001)
+#define PPP_PROTOCOL_IPv4 (0x0021)
+#define PPP_PROTOCOL_PAP (0xC023)
+#define PPP_PROTOCOL_CHAP (0xC223)
+#define PPP_PROTOCOL_IPv6 (0x0057)
+#define PPP_COMPRESS_DATA (0x00FD)
+
+#define PPP_PROTOCOL_LCP (0xC021)
+#define PPP_PROTOCOL_CCP (0x80FD)
+#define PPP_PROTOCOL_IPCP (0x8021)
+
+struct mesa_pppoe_session_hdr{
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ unsigned int ver:4;
+ unsigned int type:4;
+#elif __BYTE_ORDER == __BIG_ENDIAN
+ unsigned int type:4;
+ unsigned int ver:4;
+#else
+#error "Please check <endian.h>"
+#endif
+ unsigned char code;
+ unsigned short session_id;
+ unsigned short len;
+ /* to do:
+ pppӦ�õ�����Ϊһ�����, Ϊ�˼򻯴���, ǿ�ƽ����PPPOE_SES����һ��,
+ �����Ҫ����PPPЭ�̹���, �˽ṹ��Ҫ�Ķ�.
+ */
+ unsigned short ppp_protocol;
+}BYTE_ALIGNED(1);
+
+
+struct mesa_ppp_hdr{
+ unsigned char address;
+ unsigned char control;
+ unsigned short protocol;
+}BYTE_ALIGNED(1);
+
+#define PPP_LCP_CODE_REQUEST (1)
+#define PPP_LCP_CODE_ACK (2)
+#define PPP_LCP_CODE_NAK (3)
+#define PPP_LCP_CODE_REJECT (4)
+#define PPP_LCP_CODE_TERMINATE_REQ (5)
+#define PPP_LCP_CODE_TERMINATE_ACK (6)
+
+/* refer to RFC1661 */
+#define PPP_LCP_OPT_RESERVED (0)
+#define PPP_LCP_OPT_MAX_RCV_UNIT (1)
+#define PPP_LCP_OPT_AUTH_PRO (3)
+#define PPP_LCP_OPT_QA_PRO (4)
+#define PPP_LCP_OPT_MAGIC (5)
+#define PPP_LCP_OPT_PRO_FIELD_COMPRESS (7)
+#define PPP_LCP_OPT_ADDR_CTRL_FIELD_COMPRESS (8)
+
+#define PPP_LCP_OPT_AUTH_PRO_PAP (0xC023)
+#define PPP_LCP_OPT_AUTH_PRO_CHAP (0xC223)
+
+#define PPP_LCP_OPT_AUTH_PRO_CHAP_ALGO_MS_CHAP_V2 (0x81)
+#define PPP_LCP_OPT_AUTH_PRO_CHAP_ALGO_CHAP_MD5 (0x05)
+
+
+/* refer to RFC1962 Page6 */
+#define PPP_CCP_OPT_OUI (0)
+#define PPP_CCP_OPT_MS_PPC (18)
+
+struct mesa_ppp_lcp_ack_hdr{ /* RFC1661-Page29 */
+ unsigned char code;
+ unsigned char identifier;
+ unsigned short length;
+}BYTE_ALIGNED(1);
+
+struct mesa_ppp_ccp_ack_hdr{ /* RFC1661-Page29 */
+ unsigned char code;
+ unsigned char identifier;
+ unsigned short length;
+}BYTE_ALIGNED(1);
+
+#define PPP_CHAP_CHALLENGE (1)
+#define PPP_CHAP_RESPONSE (2)
+#define PPP_CHAP_SUCCESS (3)
+#define PPP_CHAP_FAILURE (4)
+
+struct mesa_ppp_chap_hdr{
+ unsigned char code;
+ unsigned char identifier;
+ unsigned short length;
+}BYTE_ALIGNED(1);
+
+struct mesa_ppp_ipcp_ack_hdr{
+ unsigned char code;
+ unsigned char identifier;
+ unsigned short length;
+}BYTE_ALIGNED(1);
+
+enum pptp_control_message_type{
+ PPTP_CTRL_START_CONN_REQ = 1,
+ PPTP_CTRL_START_CONN_REPLY = 2,
+ PPTP_CTRL_STOP_CONN_REQ = 3,
+ PPTP_CTRL_STOP_CONN_REPLY = 4,
+ PPTP_CTRL_ECHO_REQ = 5,
+ PPTP_CTRL_ECHO_REPLY = 6,
+ PPTP_CTRL_OUT_GO_REQ = 7,
+ PPTP_CTRL_OUT_GO_REPLY = 8,
+ PPTP_CTRL_IN_CALL_REQ = 9,
+ PPTP_CTRL_IN_CALL_REPLY = 10,
+ PPTP_CTRL_IN_CALL_CONN = 11,
+ PPTP_CTRL_CALL_CLEAR_REQ = 12,
+ PPTP_CTRL_CALL_DISCONN_NOTIFY = 13,
+ PPTP_CTRL_WAN_ERROR_NOTIFY = 14,
+ PPTP_CTRL_SET_LINK_INFO = 15,
+};
+
+struct mesa_pptp_control_hdr{
+ unsigned short length; /* ȫ�����ݳ���, ������ͷ�� */
+ unsigned short pptp_message_type;
+ unsigned int magic_cookie;
+ unsigned short control_message_type;
+ char ignore_bytes[0]; /* �����ֶ��ݲ�����, ����Ҳ��һ�� */
+};
+
+struct mesa_vlan_hdr{
+ unsigned short pri_cfi_id;
+ unsigned short type;
+};
+
+struct mesa_vlan_detail_hdr{
+ unsigned char vlan_id_high:4;
+ unsigned char del_flag:1;
+ unsigned char priority:3;
+ unsigned char vlan_id_low;
+ unsigned short type;
+};
+
+/* 2018-08-28 lijia add, for pangu ��Ŀmac_in_mac���� */
+struct mesa_mac_in_mac_net_hdr{
+ unsigned int route_dir:1;
+ unsigned int link_id:3;
+ unsigned int dev_id:6;
+ unsigned int region_id:5;
+ unsigned int __pad1:1;
+ unsigned int encap_type:4;
+ unsigned int __pad2:20;
+ unsigned int __pad3:8;
+};
+
+
+#define GRE_PRO_IPV4 (0x0800)
+#define GRE_PRO_IPV6 (0x86DD)
+#define GRE_PRO_ARP (0x0806)
+#define GRE_PRO_PPP (0x880B)
+
+struct mesa_gre_base_hdr_v0{
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ unsigned char recur:3;
+ unsigned char strict_src_route_flag:1;
+ unsigned char seq_flag:1;
+ unsigned char key_flag:1;
+ unsigned char route_flag:1;
+ unsigned char checksum_flag:1;
+
+ unsigned char version:3;
+ unsigned char flags:5; /* version 0 flags is 5 bit */
+#elif __BYTE_ORDER == __BIG_ENDIAN
+ unsigned char checksum_flag:1;
+ unsigned char route_flag:1;
+ unsigned char key_flag:1;
+ unsigned char seq_flag:1;
+ unsigned char strict_src_route_flag:1;
+ unsigned char recur:3;
+
+ unsigned char flags:5; /* version 0 flags is 5 bit */
+ unsigned char version:3;
+#else
+#error "Please check <endian.h>"
+#endif
+ unsigned short protocol;
+};
+
+struct mesa_gre_base_hdr_v1{
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ unsigned char recur:3;
+ unsigned char strict_src_route_flag:1;
+ unsigned char seq_flag:1;
+ unsigned char key_flag:1;
+ unsigned char route_flag:1;
+ unsigned char checksum_flag:1;
+
+ unsigned char version:3;
+ unsigned char flags:4; /* version 1 flags is 4 bit */
+ unsigned char ack_flag:1;
+
+#elif __BYTE_ORDER == __BIG_ENDIAN
+ unsigned char checksum_flag:1;
+ unsigned char route_flag:1;
+ unsigned char key_flag:1;
+ unsigned char seq_flag:1;
+ unsigned char strict_src_route_flag:1;
+ unsigned char recur:3;
+
+ unsigned char ack_flag:1;
+ unsigned char flags:4; /* version 1 flags is 4 bit */
+ unsigned char version:3;
+#else
+#error "Please check <endian.h>"
+#endif
+ unsigned short protocol;
+};
+
+#define GRE_SRE_MAX_LEN (256) /* �����Ϊһ���ֽ�, 256 */
+struct gre_source_route_entry_hdr{
+ unsigned short address_family;
+ unsigned char sre_offset;
+ unsigned char sre_length;
+ unsigned char sre_entry_list[GRE_SRE_MAX_LEN];
+};
+
+/* ���п��ܵ�ֵ����, ��Ҫ����mesa_gre_base_hdr����bit��ֵ, �ж��Ƿ�������ֵ */
+struct mesa_gre_extend_hdr{
+ unsigned short checksum; //version0
+ unsigned short offset; //version0, if checksum present, then offset also present
+ unsigned short payload_len; //version1
+ unsigned short call_id; //version1
+ unsigned int key; //version0
+ unsigned int seq_num; //version0 and version1
+ unsigned int ack_num; //version1
+ //struct gre_source_route_entry_hdr sre_list;
+};
+
+struct mesa_gre_hdr{
+ /* version0��version1��ͷ����, version�ֶ�ʱһ�µ�, ������С����, Ĭ��ʹ��v0��ʽ���� */
+ struct mesa_gre_base_hdr_v0 gre_base;
+ struct mesa_gre_extend_hdr gre_extend;
+};
+
+
+#define MPLS_LABEL_MASK (0xFFFFF000)
+#define MPLS_EXP_MASK (0x00000E00)
+#define MPLS_BLS_MASK (0x00000100)
+#define MPLS_TTL_MASK (0x000000FF)
+struct mesa_mpls_hdr{
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ unsigned char mpls_label_low;
+ unsigned char mpls_label_mid;
+ unsigned char mpls_bls:1; /* bottom of label stack */
+ unsigned char mpls_exp:3;
+ unsigned char mpls_label_high:4;
+ unsigned char mpls_ttl;
+#elif __BYTE_ORDER == __BIG_ENDIAN
+ unsigned char mpls_ttl;
+ unsigned char mpls_label_high:4;
+ unsigned char mpls_exp:3;
+ unsigned char mpls_bls:1; /* bottom of label stack */
+ unsigned short mpls_label_low;
+#else
+#error "Please check <endian.h>"
+#endif
+};
+
+#define L2TP_REGISTERED_IP_PRO (115)
+#define L2TP_REGISTERED_PORT (1701)
+
+#define L2TP_HDR_TYPE_DATA (0)
+#define L2TP_HDR_TYPE_CONTROL (1)
+
+struct l2tp_hdr_v2{
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ unsigned char priority:1;
+ unsigned char offset_present:1;
+ unsigned char reserved2:1;
+ unsigned char seq_present:1;
+ unsigned char reserved1:2;
+ unsigned char length_present:1;
+ unsigned char type:1;
+
+ unsigned char version:4;
+ unsigned char reserved3:4;
+#elif __BYTE_ORDER == __BIG_ENDIAN
+ unsigned char reserved3:4;
+ unsigned char version:4;
+
+ unsigned char type:1;
+ unsigned char length_present:1;
+ unsigned char reserved1:2;
+ unsigned char seq_present:1;
+ unsigned char reserved2:1;
+ unsigned char offset_present:1;
+ unsigned char priority:1;
+#else
+#error "Please check <endian.h>"
+#endif
+};
+
+/* refer to RFC2661-Page12 */
+#define L2TP_CTRL_MSG_RESERVED0 (0)
+#define L2TP_CTRL_MSG_SCCRQ (1)
+#define L2TP_CTRL_MSG_SCCRP (2)
+#define L2TP_CTRL_MSG_SCCCN (3)
+#define L2TP_CTRL_MSG_STOP_CCN (4)
+#define L2TP_CTRL_MSG_RESERVED5 (5)
+#define L2TP_CTRL_MSG_HELLO (6)
+#define L2TP_CTRL_MSG_OCRQ (7)
+#define L2TP_CTRL_MSG_OCRP (8)
+#define L2TP_CTRL_MSG_OCCN (9)
+#define L2TP_CTRL_MSG_ICRQ (10)
+#define L2TP_CTRL_MSG_ICRP (11)
+#define L2TP_CTRL_MSG_ICCN (12)
+#define L2TP_CTRL_MSG_RESERVED13 (13)
+#define L2TP_CTRL_MSG_CDN (14)
+#define L2TP_CTRL_MSG_WEN (15)
+#define L2TP_CTRL_MSG_SLI (16)
+
+#define L2TP_AVP_GET_LEN(u) (ntohs(u) & 0x3F)
+struct l2tp_avp{
+ unsigned short M_H_rsvd_len_union;
+ unsigned short vendor_id;
+ unsigned short attribute_type;
+}BYTE_ALIGNED(1);
+
+/* RFC2408-Page23 */
+#define ISAKMP_PAYLOAD_TYPE_NONE (0)
+#define ISAKMP_PAYLOAD_TYPE_SA (1)
+#define ISAKMP_PAYLOAD_TYPE_PROPOSAL (2)
+#define ISAKMP_PAYLOAD_TYPE_TRANSFORM (3)
+#define ISAKMP_PAYLOAD_TYPE_KEY_EXCHANGE (4)
+#define ISAKMP_PAYLOAD_TYPE_ID (5)
+#define ISAKMP_PAYLOAD_TYPE_CERT (6)
+#define ISAKMP_PAYLOAD_TYPE_CR (7)
+#define ISAKMP_PAYLOAD_TYPE_HASH (8)
+#define ISAKMP_PAYLOAD_TYPE_SIG (9)
+#define ISAKMP_PAYLOAD_TYPE_NONCE (10)
+#define ISAKMP_PAYLOAD_TYPE_NOTIFY (11)
+#define ISAKMP_PAYLOAD_TYPE_DELETE (12)
+#define ISAKMP_PAYLOAD_TYPE_VENDOR_ID (13)
+#define ISAKMP_PAYLOAD_TYPE_RESERVED_BEGIN (14) /* 14 - 127 */
+#define ISAKMP_PAYLOAD_TYPE_RESERVED_END (127) /* 14 - 127 */
+#define ISAKMP_PAYLOAD_TYPE_PRIVATE_USE_BEGIN (128) /* 128-255 */
+#define ISAKMP_PAYLOAD_TYPE_PRIVATE_USE_END (255) /* 128-255 */
+
+/* RFC2408-Page23 */
+#define ISAKMP_EXCHANGE_TYPE_NONE (0)
+#define ISAKMP_EXCHANGE_TYPE_BASE (1)
+#define ISAKMP_EXCHANGE_TYPE_ID_PROT (2) /* RFC-2409 page8, main mode is instantiation os ISAKMP Identity Protect Exchange */
+#define ISAKMP_EXCHANGE_TYPE_AUTH (3)
+#define ISAKMP_EXCHANGE_TYPE_AGGRESS (4)/* RFC-2409 page8, Aggressive mode is instantiation os ISAKMP Aggressive Exchange */
+#define ISAKMP_EXCHANGE_TYPE_INFO (5)
+#define ISAKMP_EXCHANGE_TYPE_FEATURE_USE_BEGIN (6) /* 6-31��ֵ�ݲ����� */
+#define ISAKMP_EXCHANGE_TYPE_FEATURE_USE_END (31) /* 6-31��ֵ�ݲ����� */
+
+struct mesa_isakmp_hdr{ /* RFC2408-Page22 */
+ unsigned long long init_cookie;
+ unsigned long long resp_cookie;
+ unsigned char next_payload;
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ unsigned char minor_version:4;
+ unsigned char major_version:4;
+#elif __BYTE_ORDER == __BIG_ENDIAN
+ unsigned char major_version:4;
+ unsigned char minor_version:4;
+#else
+#error "Please check <endian.h>"
+#endif
+
+ unsigned char exchange_type;
+ unsigned char flags;
+ unsigned int message_id;
+ unsigned int length;
+};
+
+struct mesa_isakmp_payload_hdr{ /* RFC2408-Page22 */
+ unsigned char next_payload;
+ unsigned char reserver;
+ unsigned short payload_len;
+};
+
+#define GTP_MSG_TYPE_T_PDU (0xFF)
+
+#define GTP_HDR_VER_MASK (0xE0)
+
+#define GTP_HDR_FLAG_NEXT_EXT_HDR (0x04)
+#define GTP_HDR_FLAG_SEQ_NUM (0x02)
+#define GTP_HDR_FLAG_N_PDU (0x01)
+
+
+struct gtp_hdr{
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ unsigned char flags;
+ unsigned char msg_type;
+ unsigned short len;
+ unsigned int teid;
+#elif __BYTE_ORDER == __BIG_ENDIAN
+ unsigned int teid;
+ unsigned short len;
+ unsigned char msg_type;
+ unsigned char flags;
+#else
+#error "Please check <endian.h>"
+#endif
+};
+
+#define TEREDO_AUTH_HDR_FLAG (0x0001)
+#define TEREDO_INDICATION_HDR_FLAG (0x0000)
+
+#define TEREDO_INDICATION_HDR_LEN (8)
+
+struct teredo_auth_hdr{
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ unsigned short flags;
+ unsigned char id_len;
+ unsigned char au_len;
+#elif __BYTE_ORDER == __BIG_ENDIAN
+ unsigned char au_len;
+ unsigned char id_len;
+ unsigned short flags;
+#else
+#error "Please check <endian.h>"
+#endif
+};
+
+#define MAX_ADDR_TYPE_STRING_LEN (64)
+#define MAX_ADDR_LIST_STRING_LEN (2048)
+#define MAX_ADDR_EMBED_LAYER_NUM (20) /* ����ַǶ�ײ��� */
+#define MAX_ADDR_BIN_VALUE_LEN (40) /* paddrʵ��������󳤶�, Ŀǰ��tuple4v6� */
+
+/* ����ģʽ��, ��¼MAC��ַ���ڷ��� */
+struct packet_io_mac_addr{
+ struct mesa_ethernet_hdr eth_hdr;
+ char route_dir;
+ char __pad__; /* ����ṹ8�ֽڶ��� */
+};
+
+
+
+struct hdlc_net_hdr{
+ unsigned char address;
+ unsigned char control;
+ unsigned short protocol; /* network order */
+}__attribute__((packed));
+
+
+
+/* ������������ֶ�, ��Ϊ������, network order */
+#define VXLAN_KEEPALIVE_PKT_PORT (3784)
+#define VXLAN_OVERLAY_PKT_PORT (4789)
+
+
+typedef enum{
+ VXLAN_ENCAP_ETH = 0x0,
+ VXLAN_ENCAP_PPP = 0x8,
+ VXLAN_ENCAP_HDLC = 0xC,
+}vxlan_encap_type_t;
+
+struct __inline_vxlan_hdr{
+ unsigned char flags;
+ unsigned char reserved[3];
+ /*--------int delim -------*/
+ unsigned char vlan_id_half_high;
+ unsigned char link_layer_type : 4; /* ���㱨�ķ�װ��ʽ */
+ unsigned char vlan_id_half_low : 4;
+
+ unsigned int dir : 1;
+ unsigned int link_id : 6;
+ unsigned int online_test : 1;
+
+ unsigned int r7 : 1;
+ unsigned int r6 : 1;
+ unsigned int r5 : 1;
+ unsigned int r4 : 1;
+ unsigned int vni_flag : 1;
+ unsigned int r2 : 1;
+ unsigned int r1 : 1;
+ unsigned int r0 : 1;
+}__attribute__((packed));
+typedef struct __inline_vxlan_hdr inline_vxlan_hdr_t;
+
+
+
+unsigned char net_layer_to_ipv4_protocol(int addr_type);
+unsigned char net_layer_to_ipv6_protocol(int addr_type);
+unsigned short net_layer_to_ethernet_protocol(int addr_type);
+UINT16 net_layer_to_ethernet_protocol_by_stream(const struct streaminfo *pstream);
+enum addr_type_t ethernet_protocol_to_net_layer(UINT16 ether_type_host);
+int net_common_build_send_mac(unsigned char *buf, const struct mesa_ethernet_hdr *raw_eth_hdr, int addr_type, int dir_reverse, int net_topology_mode);
+int net_common_adjust_forward_mac(struct mesa_ethernet_hdr *raw_eth_hdr,int net_topology_mode);
+const void *MESA_net_jump_to_layer(const void *raw_data, int raw_layer_type, int expect_layer_type);
+const void *MESA_net_jump_to_layer_greedy(const void *raw_data, int raw_layer_type, int expect_layer_type);
+char MESA_ascii_to_hex(char ascii);
+const char *sapp_raw_ipv4_ntop(const struct mesa_ip4_hdr *ip4_hdr, char *out_buf, int buf_len );
+const char *sapp_raw_ipv6_ntop(const struct mesa_ip6_hdr *ip6_hdr, char *out_buf, int buf_len);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/test/Makefile b/test/Makefile
new file mode 100644
index 0000000..af0990a
--- /dev/null
+++ b/test/Makefile
@@ -0,0 +1,2 @@
+test_jump_layer:test_jump_layer.c
+ gcc -g -o $@ test_jump_layer.c -D_GNU_SOURCE -L/opt/MESA/lib -lMESA_jump_layer -I ../inc -I/opt/MESA/include/MESA -l pcap
diff --git a/test/test_jump_layer.c b/test/test_jump_layer.c
new file mode 100644
index 0000000..0cd518d
--- /dev/null
+++ b/test/test_jump_layer.c
@@ -0,0 +1,153 @@
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <getopt.h>
+#include <pcap/pcap.h>
+#include "MESA_jump_layer.h"
+
+static pcap_t *g_pcap_handle;
+static char *g_input_pcap_name;
+static char *g_input_bpf_string;
+static struct bpf_program g_bpf_filter;
+
+static void usage(const char *prog)
+{
+ printf("Usage:\n");
+ printf("\t-r set input pcap file.\n");
+ printf("\t-f set pcap BPF fileter.\n");
+ exit(0);
+}
+
+static int pcap_set_bpf(pcap_t *handle, const char *filter_str)
+{
+ struct bpf_program bpf_filter;
+
+ if((NULL == handle) || (NULL == filter_str) || ('\0' == *filter_str)){
+ return 0;
+ }
+
+ if(pcap_compile(handle, &bpf_filter, (char *)filter_str, 1, 0) < 0)
+ {
+ printf("Compile pcap filter '%s' error:%s\n", filter_str, pcap_geterr(handle));
+ return -1;
+ }
+
+ if(pcap_setfilter(handle, &bpf_filter) < 0){
+ printf("Set pcap filter '%s' error:%s\n", filter_str, pcap_geterr(handle));
+ return -1;
+ }
+
+ return 0;
+}
+
+static int pcap_init(void)
+{
+ char err_string[PCAP_ERRBUF_SIZE];
+
+ g_pcap_handle = pcap_open_offline(g_input_pcap_name, err_string);
+ if(NULL == g_pcap_handle){
+ printf("open file:%s error, %s\n", g_input_pcap_name, err_string);
+ return -1;
+ }
+
+ if(pcap_compile_nopcap(65535, DLT_RAW, &g_bpf_filter, g_input_bpf_string, 1, 0) < 0){
+ printf("Compile pcap filter '%s' error\n", g_input_bpf_string);
+ return -1;
+ }
+
+ return 0;
+}
+
+static void _pcap_pkt_handle(u_char *user, const struct pcap_pkthdr *hdr, const u_char *data)
+{
+ const void *ip4_hdr, *ip6_h;
+ char print_buf[128];
+ int offset_to_eth;
+ static int pkt_index = 0;
+
+ ip4_hdr = MESA_net_jump_to_layer_greedy(data, ADDR_TYPE_MAC, ADDR_TYPE_IPV4);
+ ip6_h = MESA_net_jump_to_layer_greedy(data, ADDR_TYPE_MAC, ADDR_TYPE_IPV6);
+
+ printf("-----------------------------packet index:%d------------------------------------------\n", pkt_index++);
+ if(ip4_hdr){
+ offset_to_eth = (u_char *)ip4_hdr-data;
+ if(g_input_bpf_string
+ && (0 == bpf_filter(g_bpf_filter.bf_insns, (const unsigned char *)ip4_hdr, hdr->caplen-offset_to_eth, hdr->caplen-offset_to_eth))){
+ goto done;
+ }
+ printf("Innermost layer ipv4 offset:%d, addr: %s\n", offset_to_eth, MESA_jump_layer_ipv4_ntop((struct ip *)ip4_hdr, print_buf, sizeof(print_buf)));
+ }
+
+ if(ip6_h){
+ offset_to_eth = (u_char *)ip6_h-data;
+ if(g_input_bpf_string
+ && (0 == bpf_filter(g_bpf_filter.bf_insns, (const unsigned char *)ip6_h, hdr->caplen-offset_to_eth, hdr->caplen-offset_to_eth))){
+ goto done;
+ }
+
+ printf("Innermost layer ipv6 offset:%d, addr: %s\n", offset_to_eth, MESA_jump_layer_ipv6_ntop((struct ip6_hdr *)ip6_h, print_buf, sizeof(print_buf)));
+ }
+
+done:
+
+ printf("--------------------------------------------------------------------------------------\n\n");
+}
+
+static void pcap_run(void)
+{
+
+ pcap_loop(g_pcap_handle, -1, _pcap_pkt_handle, NULL);
+}
+
+int main(int argc, char *argv[])
+{
+ int ret, c, opt_index;
+
+ while(1){
+ c = getopt_long(argc, argv, "hr:f:", NULL, &opt_index);
+ if(c == -1){
+ ret = 0;
+ break;
+ }
+
+ switch(c){
+ case 'h':
+ usage(argv[0]);
+ break;
+
+ case 'r':
+ g_input_pcap_name = strdup(optarg);
+ break;
+
+ case 'f':
+ g_input_bpf_string = strdup(optarg);
+ break;
+
+ default:
+ return -1;
+ }
+ }
+
+ if(NULL == g_input_pcap_name){
+ printf("error! must set pcap file name use -r\n");
+ return -1;
+ }
+
+ if(NULL == g_input_bpf_string){
+ printf("you can set BPF filter use -f\n");
+ }
+
+ if(pcap_init() < 0){
+ return -1;
+ }
+
+ pcap_run();
+
+ return 0;
+}
+
+
+#ifdef __cplusplus
+}
+#endif