commit f6f399f69a950ab1c45ea0e8c0787a476ff58754 Author: lijia Date: Tue Sep 14 15:50:53 2021 +0800 create new project. 除sapp和插件之外, 其他模块也经常有从某个层跳转到某个层的需求, 从sapp中剥离此部分代码, 独立成为一个公共库. 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:::' -e 's:::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:::' -e 's:::p')" + + # Action Stamp + VCS_ACTION_STAMP="${VCS_DATE}!$(svn log --xml -l 1 -r "${VCS_SHORT_HASH}" | sed -n -e 's:::' -e 's:::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 + "${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 + +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="" + local stringx="" + 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 +#include + + +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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +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ߵ, ֱmemcpyaddr. + */ + + 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 + +#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; /* ԭʼIPIJɷƬֳ */ +}; + + +#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 +#include +#include +#include +#include +#include + +#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 " +#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 " +#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 " +#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 " +#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 " +#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_hdrbitֵ, жǷֵ */ +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{ + /* version0version1ͷ, 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 " +#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 " +#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 " +#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 " +#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 " +#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 +#include +#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