diff options
author | jjako <jjako> | 2003-10-13 20:33:30 +0000 |
---|---|---|
committer | jjako <jjako> | 2003-10-13 20:33:30 +0000 |
commit | 08d331db63cf42d16d0b2b00533a37fde79eb2c2 (patch) | |
tree | f21b884722d5e3a1f7bc5c9ea261a6a04fdaf822 | |
parent | 48c205f3f02161cc86d97cac92577f19eda2ba34 (diff) |
First attempt at a GTP1 implementation
-rw-r--r-- | aclocal.m4 | 241 | ||||
-rw-r--r-- | config.h.in | 6 | ||||
-rwxr-xr-x | configure | 2269 | ||||
-rw-r--r-- | ggsn/ggsn.c | 40 | ||||
-rw-r--r-- | gtp/gtp.c | 2071 | ||||
-rw-r--r-- | gtp/gtp.h | 254 | ||||
-rw-r--r-- | gtp/gtpie.c | 47 | ||||
-rw-r--r-- | gtp/gtpie.h | 74 | ||||
-rw-r--r-- | gtp/pdp.c | 7 | ||||
-rw-r--r-- | gtp/pdp.h | 18 | ||||
-rw-r--r-- | gtp/queue.c | 8 | ||||
-rw-r--r-- | gtp/queue.h | 7 | ||||
-rw-r--r-- | sgsnemu/sgsnemu.c | 49 |
13 files changed, 3282 insertions, 1809 deletions
@@ -118,6 +118,8 @@ AC_REQUIRE([AC_PROG_CC])dnl AC_REQUIRE([AC_PROG_LD])dnl AC_REQUIRE([AC_PROG_LD_RELOAD_FLAG])dnl AC_REQUIRE([AC_PROG_NM])dnl +AC_REQUIRE([LT_AC_PROG_SED])dnl + AC_REQUIRE([AC_PROG_LN_S])dnl AC_REQUIRE([AC_DEPLIBS_CHECK_METHOD])dnl AC_REQUIRE([AC_OBJEXT])dnl @@ -285,9 +287,12 @@ hpux*) # Its linker distinguishes data from code symbols lt_cv_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern char \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" lt_cv_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\) $/ {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (lt_ptr) \&\2},/p'" ;; -irix*) +irix* | nonstopux*) symcode='[[BCDEGRST]]' ;; +osf*) + symcode='[[BCDEGQRST]]' + ;; solaris* | sysv5*) symcode='[[BDT]]' ;; @@ -384,7 +389,7 @@ EOF save_CFLAGS="$CFLAGS" LIBS="conftstm.$ac_objext" CFLAGS="$CFLAGS$no_builtin_flag" - if AC_TRY_EVAL(ac_link) && test -s conftest; then + if AC_TRY_EVAL(ac_link) && test -s conftest$ac_exeext; then pipe_works=yes fi LIBS="$save_LIBS" @@ -928,7 +933,7 @@ AC_CACHE_VAL(lt_cv_prog_cc_pic, # like `-m68040'. lt_cv_prog_cc_pic='-m68020 -resident32 -malways-restore-a4' ;; - beos* | irix5* | irix6* | osf3* | osf4* | osf5*) + beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) # PIC is the default for these OSes. ;; darwin* | rhapsody*) @@ -971,7 +976,7 @@ AC_CACHE_VAL(lt_cv_prog_cc_pic, lt_cv_prog_cc_pic='+Z' ;; - irix5* | irix6*) + irix5* | irix6* | nonstopux*) lt_cv_prog_cc_wl='-Wl,' lt_cv_prog_cc_static='-non_shared' # PIC (with -KPIC) is the default. @@ -1015,11 +1020,7 @@ AC_CACHE_VAL(lt_cv_prog_cc_pic, sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) lt_cv_prog_cc_pic='-KPIC' lt_cv_prog_cc_static='-Bstatic' - if test "x$host_vendor" = xsni; then - lt_cv_prog_cc_wl='-LD' - else - lt_cv_prog_cc_wl='-Wl,' - fi + lt_cv_prog_cc_wl='-Wl,' ;; uts4*) @@ -1384,7 +1385,7 @@ EOF # If the export-symbols file already is a .def file (1st line # is EXPORTS), use it as is. # If DATA tags from a recent dlltool are present, honour them! - archive_expsym_cmds='if test "x`head -1 $export_symbols`" = xEXPORTS; then + archive_expsym_cmds='if test "x`sed 1q $export_symbols`" = xEXPORTS; then cp $export_symbols $output_objdir/$soname-def; else echo EXPORTS > $output_objdir/$soname-def; @@ -1393,6 +1394,7 @@ EOF set dummy \$symbol; case \[$]# in 2) echo " \[$]2 @ \$_lt_hint ; " >> $output_objdir/$soname-def;; + 4) echo " \[$]2 \[$]3 \[$]4 ; " >> $output_objdir/$soname-def; _lt_hint=`expr \$_lt_hint - 1`;; *) echo " \[$]2 @ \$_lt_hint \[$]3 ; " >> $output_objdir/$soname-def;; esac; _lt_hint=`expr 1 + \$_lt_hint`; @@ -1505,10 +1507,12 @@ else # need to do runtime linking. case $host_os in aix4.[[23]]|aix4.[[23]].*|aix5*) for ld_flag in $LDFLAGS; do - if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then + case $ld_flag in + *-brtl*) aix_use_runtimelinking=yes break - fi + ;; + esac done esac @@ -1622,8 +1626,9 @@ else esac # FIXME: Relying on posixy $() will cause problems for # cross-compilation, but unfortunately the echo tests do not - # yet detect zsh echo's removal of \ escapes. - archive_cmds='$nonopt $(test "x$module" = xyes && echo -bundle || echo -dynamiclib) $allow_undefined_flag -o $lib $libobjs $deplibs$linker_flags -install_name $rpath/$soname $verstring' + # yet detect zsh echo's removal of \ escapes. Also zsh mangles + # `"' quotes if we put them in here... so don't! + archive_cmds='$CC -r -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs && $CC $(test .$module = .yes && echo -bundle || echo -dynamiclib) $allow_undefined_flag -o $lib ${lib}-master.o $deplibs$linker_flags $(test .$module != .yes && echo -install_name $rpath/$soname $verstring)' # We need to add '_' to the symbols in $export_symbols first #archive_expsym_cmds="$archive_cmds"' && strip -s $export_symbols' hardcode_direct=yes @@ -1675,13 +1680,14 @@ else export_dynamic_flag_spec='${wl}-E' ;; - irix5* | irix6*) + irix5* | irix6* | nonstopux*) if test "$GCC" = yes; then archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' else archive_cmds='$LD -shared $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + hardcode_libdir_flag_spec='-rpath $libdir' fi - hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator=: link_all_deplibs=yes ;; @@ -1709,7 +1715,7 @@ else hardcode_direct=yes hardcode_shlibpath_var=no if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then - archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $linker_flags' + archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' hardcode_libdir_flag_spec='${wl}-rpath,$libdir' export_dynamic_flag_spec='${wl}-E' else @@ -1719,7 +1725,7 @@ else hardcode_libdir_flag_spec='-R$libdir' ;; *) - archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $linker_flags' + archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' hardcode_libdir_flag_spec='${wl}-rpath,$libdir' ;; esac @@ -1831,13 +1837,23 @@ EOF ;; sysv4) - if test "x$host_vendor" = xsno; then - archive_cmds='$LD -G -Bsymbolic -h $soname -o $lib $libobjs $deplibs $linker_flags' - hardcode_direct=yes # is this really true??? - else - archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' - hardcode_direct=no #Motorola manual says yes, but my tests say they lie - fi + case $host_vendor in + sni) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=yes # is this really true??? + ;; + siemens) + ## LD is ld it makes a PLAMLIB + ## CC just makes a GrossModule. + archive_cmds='$LD -G -o $lib $libobjs $deplibs $linker_flags' + reload_cmds='$CC -r -o $output$reload_objs' + hardcode_direct=no + ;; + motorola) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=no #Motorola manual says yes, but my tests say they lie + ;; + esac runpath_var='LD_RUN_PATH' hardcode_shlibpath_var=no ;; @@ -1978,6 +1994,9 @@ aix3*) aix4* | aix5*) version_type=linux + need_lib_prefix=no + need_version=no + hardcode_into_libs=yes if test "$host_cpu" = ia64; then # AIX 5 supports IA64 library_names_spec='${libname}${release}.so$major ${libname}${release}.so$versuffix $libname.so' @@ -2016,6 +2035,7 @@ aix4* | aix5*) fi shlibpath_var=LIBPATH fi + hardcode_into_libs=yes ;; amigaos*) @@ -2063,7 +2083,7 @@ cygwin* | mingw* | pw32*) ;; yes,mingw*) library_names_spec='${libname}`echo ${release} | sed -e 's/[[.]]/-/g'`${versuffix}.dll' - sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | sed -e "s/^libraries://" -e "s/;/ /g"` + sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | sed -e "s/^libraries://" -e "s/;/ /g" -e "s,=/,/,g"` ;; yes,pw32*) library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | sed -e 's/[.]/-/g'`${versuffix}.dll' @@ -2146,14 +2166,17 @@ hpux9* | hpux10* | hpux11*) postinstall_cmds='chmod 555 $lib' ;; -irix5* | irix6*) - version_type=irix +irix5* | irix6* | nonstopux*) + case $host_os in + nonstopux*) version_type=nonstopux ;; + *) version_type=irix ;; + esac need_lib_prefix=no need_version=no soname_spec='${libname}${release}.so$major' library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major ${libname}${release}.so $libname.so' case $host_os in - irix5*) + irix5* | nonstopux*) libsuff= shlibsuff= ;; *) @@ -2198,6 +2221,26 @@ linux-gnu*) # people can always --disable-shared, the test was removed, and we # assume the GNU/Linux dynamic linker is in use. dynamic_linker='GNU/Linux ld.so' + + # Find out which ABI we are using (multilib Linux x86_64 hack). + libsuff= + case "$host_cpu" in + x86_64*|s390x*) + echo '[#]line __oline__ "configure"' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + case `/usr/bin/file conftest.$ac_objext` in + *64-bit*) + libsuff=64 + ;; + esac + fi + rm -rf conftest* + ;; + *) + ;; + esac + sys_lib_dlsearch_path_spec="/lib${libsuff} /usr/lib${libsuff}" + sys_lib_search_path_spec="/lib${libsuff} /usr/lib${libsuff} /usr/local/lib${libsuff}" ;; netbsd*) @@ -2257,11 +2300,12 @@ os2*) osf3* | osf4* | osf5*) version_type=osf need_version=no - soname_spec='${libname}${release}.so' - library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so $libname.so' + soname_spec='${libname}${release}.so$major' + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" + hardcode_into_libs=yes ;; sco3.2v5*) @@ -2304,6 +2348,12 @@ sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) case $host_vendor in sni) shlibpath_overrides_runpath=no + need_lib_prefix=no + export_dynamic_flag_spec='${wl}-Blargedynsym' + runpath_var=LD_RUN_PATH + ;; + siemens) + need_lib_prefix=no ;; motorola) need_lib_prefix=no @@ -2458,7 +2508,7 @@ if test -f "$ltmain"; then # Now quote all the things that may contain metacharacters while being # careful not to overquote the AC_SUBSTed values. We take copies of the # variables and quote the copies for generation of the libtool script. - for var in echo old_CC old_CFLAGS \ + for var in echo old_CC old_CFLAGS SED \ AR AR_FLAGS CC LD LN_S NM SHELL \ reload_flag reload_cmds wl \ pic_flag link_static_flag no_builtin_flag export_dynamic_flag_spec \ @@ -2520,8 +2570,11 @@ if test -f "$ltmain"; then # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. +# A sed that does not truncate output. +SED=$lt_SED + # Sed that helps us avoid accidentally triggering echo(1) options like -n. -Xsed="sed -e s/^X//" +Xsed="${SED} -e s/^X//" # The HP-UX ksh and POSIX shell print the target directory to stdout # if CDPATH is set. @@ -3282,7 +3335,7 @@ test -n "$reload_flag" && reload_flag=" $reload_flag" # AC_DEPLIBS_CHECK_METHOD - how to check for library dependencies # -- PORTME fill in with the dynamic library characteristics AC_DEFUN([AC_DEPLIBS_CHECK_METHOD], -[AC_CACHE_CHECK([how to recognise dependant libraries], +[AC_CACHE_CHECK([how to recognise dependent libraries], lt_cv_deplibs_check_method, [lt_cv_file_magic_cmd='$MAGIC_CMD' lt_cv_file_magic_test_file= @@ -3357,9 +3410,9 @@ hpux10.20*|hpux11*) lt_cv_file_magic_test_file=/usr/lib/libc.sl ;; -irix5* | irix6*) +irix5* | irix6* | nonstopux*) case $host_os in - irix5*) + irix5* | nonstopux*) # this will be overridden with pass_all, but let us keep it just in case lt_cv_deplibs_check_method="file_magic ELF 32-bit MSB dynamic lib MIPS - version 1" ;; @@ -3381,7 +3434,7 @@ irix5* | irix6*) # This must be Linux ELF. linux-gnu*) case $host_cpu in - alpha* | hppa* | i*86 | powerpc* | sparc* | ia64* | s390* ) + alpha* | hppa* | i*86 | mips | mipsel | powerpc* | sparc* | ia64* | s390* | x86_64*) lt_cv_deplibs_check_method=pass_all ;; *) # glibc up to 2.1.1 does not perform some relocations on ARM @@ -3452,6 +3505,9 @@ sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) lt_cv_deplibs_check_method="file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB dynamic lib" lt_cv_file_magic_test_file=/lib/libc.so ;; + siemens) + lt_cv_deplibs_check_method=pass_all + ;; esac ;; esac @@ -3517,12 +3573,12 @@ esac ]) # AC_LIBLTDL_CONVENIENCE[(dir)] - sets LIBLTDL to the link flags for -# the libltdl convenience library and INCLTDL to the include flags for +# the libltdl convenience library and LTDLINCL to the include flags for # the libltdl header and adds --enable-ltdl-convenience to the -# configure arguments. Note that LIBLTDL and INCLTDL are not +# configure arguments. Note that LIBLTDL and LTDLINCL are not # AC_SUBSTed, nor is AC_CONFIG_SUBDIRS called. If DIR is not # provided, it is assumed to be `libltdl'. LIBLTDL will be prefixed -# with '${top_builddir}/' and INCLTDL will be prefixed with +# with '${top_builddir}/' and LTDLINCL will be prefixed with # '${top_srcdir}/' (note the single quotes!). If your package is not # flat and you're not using automake, define top_builddir and # top_srcdir appropriately in the Makefiles. @@ -3534,16 +3590,18 @@ AC_DEFUN([AC_LIBLTDL_CONVENIENCE], ac_configure_args="$ac_configure_args --enable-ltdl-convenience" ;; esac LIBLTDL='${top_builddir}/'ifelse($#,1,[$1],['libltdl'])/libltdlc.la - INCLTDL='-I${top_srcdir}/'ifelse($#,1,[$1],['libltdl']) + LTDLINCL='-I${top_srcdir}/'ifelse($#,1,[$1],['libltdl']) + # For backwards non-gettext consistent compatibility... + INCLTDL="$LTDLINCL" ]) # AC_LIBLTDL_INSTALLABLE[(dir)] - sets LIBLTDL to the link flags for -# the libltdl installable library and INCLTDL to the include flags for +# the libltdl installable library and LTDLINCL to the include flags for # the libltdl header and adds --enable-ltdl-install to the configure -# arguments. Note that LIBLTDL and INCLTDL are not AC_SUBSTed, nor is +# arguments. Note that LIBLTDL and LTDLINCL are not AC_SUBSTed, nor is # AC_CONFIG_SUBDIRS called. If DIR is not provided and an installed # libltdl is not found, it is assumed to be `libltdl'. LIBLTDL will -# be prefixed with '${top_builddir}/' and INCLTDL will be prefixed +# be prefixed with '${top_builddir}/' and LTDLINCL will be prefixed # with '${top_srcdir}/' (note the single quotes!). If your package is # not flat and you're not using automake, define top_builddir and # top_srcdir appropriately in the Makefiles. @@ -3561,12 +3619,14 @@ AC_DEFUN([AC_LIBLTDL_INSTALLABLE], if test x"$enable_ltdl_install" = x"yes"; then ac_configure_args="$ac_configure_args --enable-ltdl-install" LIBLTDL='${top_builddir}/'ifelse($#,1,[$1],['libltdl'])/libltdl.la - INCLTDL='-I${top_srcdir}/'ifelse($#,1,[$1],['libltdl']) + LTDLINCL='-I${top_srcdir}/'ifelse($#,1,[$1],['libltdl']) else ac_configure_args="$ac_configure_args --enable-ltdl-install=no" LIBLTDL="-lltdl" - INCLTDL= + LTDLINCL= fi + # For backwards non-gettext consistent compatibility... + INCLTDL="$LTDLINCL" ]) # old names @@ -3581,6 +3641,95 @@ AC_DEFUN([AM_PROG_NM], [AC_PROG_NM]) # This is just to silence aclocal about the macro not being used ifelse([AC_DISABLE_FAST_INSTALL]) +# NOTE: This macro has been submitted for inclusion into # +# GNU Autoconf as AC_PROG_SED. When it is available in # +# a released version of Autoconf we should remove this # +# macro and use it instead. # +# LT_AC_PROG_SED +# -------------- +# Check for a fully-functional sed program, that truncates +# as few characters as possible. Prefer GNU sed if found. +AC_DEFUN([LT_AC_PROG_SED], +[AC_MSG_CHECKING([for a sed that does not truncate output]) +AC_CACHE_VAL(lt_cv_path_SED, +[# Loop through the user's path and test for sed and gsed. +# Then use that list of sed's as ones to test for truncation. +as_executable_p="test -f" +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in sed gsed; do + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then + _sed_list="$_sed_list $as_dir/$ac_prog$ac_exec_ext" + fi + done + done +done + + # Create a temporary directory, and hook for its removal unless debugging. +$debug || +{ + trap 'exit_status=$?; rm -rf $tmp && exit $exit_status' 0 + trap '{ (exit 1); exit 1; }' 1 2 13 15 +} + +# Create a (secure) tmp directory for tmp files. +: ${TMPDIR=/tmp} +{ + tmp=`(umask 077 && mktemp -d -q "$TMPDIR/sedXXXXXX") 2>/dev/null` && + test -n "$tmp" && test -d "$tmp" +} || +{ + tmp=$TMPDIR/sed$$-$RANDOM + (umask 077 && mkdir $tmp) +} || +{ + echo "$me: cannot create a temporary directory in $TMPDIR" >&2 + { (exit 1); exit 1; } +} + _max=0 + _count=0 + # Add /usr/xpg4/bin/sed as it is typically found on Solaris + # along with /bin/sed that truncates output. + for _sed in $_sed_list /usr/xpg4/bin/sed; do + test ! -f ${_sed} && break + cat /dev/null > "$tmp/sed.in" + _count=0 + echo ${ECHO_N-$ac_n} "0123456789${ECHO_C-$ac_c}" >"$tmp/sed.in" + # Check for GNU sed and select it if it is found. + if "${_sed}" --version 2>&1 < /dev/null | egrep '(GNU)' > /dev/null; then + lt_cv_path_SED=${_sed} + break + fi + while true; do + cat "$tmp/sed.in" "$tmp/sed.in" >"$tmp/sed.tmp" + mv "$tmp/sed.tmp" "$tmp/sed.in" + cp "$tmp/sed.in" "$tmp/sed.nl" + echo >>"$tmp/sed.nl" + ${_sed} -e 's/a$//' < "$tmp/sed.nl" >"$tmp/sed.out" || break + cmp -s "$tmp/sed.out" "$tmp/sed.nl" || break + # 40000 chars as input seems more than enough + test $_count -gt 10 && break + _count=`expr $_count + 1` + if test $_count -gt $_max; then + _max=$_count + lt_cv_path_SED=$_sed + fi + done + done + rm -rf "$tmp" +]) +if test "X$SED" != "X"; then + lt_cv_path_SED=$SED +else + SED=$lt_cv_path_SED +fi +AC_MSG_RESULT([$SED]) +]) + # Do all the work for Automake. -*- Autoconf -*- # This macro actually does too much some checks are only needed if diff --git a/config.h.in b/config.h.in index e27fa33..39b59f8 100644 --- a/config.h.in +++ b/config.h.in @@ -18,7 +18,8 @@ /* Define to 1 if you have the <inttypes.h> header file. */ #undef HAVE_INTTYPES_H -/* Define to 1 if your system has a working `malloc' function. */ +/* Define to 1 if your system has a GNU libc compatible `malloc' function, and + to 0 otherwise. */ #undef HAVE_MALLOC /* Define to 1 if you have the <memory.h> header file. */ @@ -114,6 +115,9 @@ /* Define to empty if `const' does not conform to ANSI C. */ #undef const +/* Define to rpl_malloc if the replacement function should be used. */ +#undef malloc + /* Define to `int' if <sys/types.h> does not define. */ #undef mode_t @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.53 for openggsn 0.61b. +# Generated by GNU Autoconf 2.57 for openggsn 0.61b. # # Report bugs to <jj@openggsn.org>. # @@ -8,173 +8,6 @@ # Free Software Foundation, Inc. # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. - -# Find the correct PATH separator. Usually this is `:', but -# DJGPP uses `;' like DOS. -if test "X${PATH_SEPARATOR+set}" != Xset; then - UNAME=${UNAME-`uname 2>/dev/null`} - case X$UNAME in - *-DOS) lt_cv_sys_path_separator=';' ;; - *) lt_cv_sys_path_separator=':' ;; - esac - PATH_SEPARATOR=$lt_cv_sys_path_separator -fi - - -# Check that we are running under the correct shell. -SHELL=${CONFIG_SHELL-/bin/sh} - -case X$ECHO in -X*--fallback-echo) - # Remove one level of quotation (which was required for Make). - ECHO=`echo "$ECHO" | sed 's,\\\\\$\\$0,'$0','` - ;; -esac - -echo=${ECHO-echo} -if test "X$1" = X--no-reexec; then - # Discard the --no-reexec flag, and continue. - shift -elif test "X$1" = X--fallback-echo; then - # Avoid inline document here, it may be left over - : -elif test "X`($echo '\t') 2>/dev/null`" = 'X\t'; then - # Yippee, $echo works! - : -else - # Restart under the correct shell. - exec $SHELL "$0" --no-reexec ${1+"$@"} -fi - -if test "X$1" = X--fallback-echo; then - # used as fallback echo - shift - cat <<EOF - -EOF - exit 0 -fi - -# The HP-UX ksh and POSIX shell print the target directory to stdout -# if CDPATH is set. -if test "X${CDPATH+set}" = Xset; then CDPATH=:; export CDPATH; fi - -if test -z "$ECHO"; then -if test "X${echo_test_string+set}" != Xset; then -# find a string as large as possible, as long as the shell can cope with it - for cmd in 'sed 50q "$0"' 'sed 20q "$0"' 'sed 10q "$0"' 'sed 2q "$0"' 'echo test'; do - # expected sizes: less than 2Kb, 1Kb, 512 bytes, 16 bytes, ... - if (echo_test_string="`eval $cmd`") 2>/dev/null && - echo_test_string="`eval $cmd`" && - (test "X$echo_test_string" = "X$echo_test_string") 2>/dev/null - then - break - fi - done -fi - -if test "X`($echo '\t') 2>/dev/null`" = 'X\t' && - echo_testing_string=`($echo "$echo_test_string") 2>/dev/null` && - test "X$echo_testing_string" = "X$echo_test_string"; then - : -else - # The Solaris, AIX, and Digital Unix default echo programs unquote - # backslashes. This makes it impossible to quote backslashes using - # echo "$something" | sed 's/\\/\\\\/g' - # - # So, first we look for a working echo in the user's PATH. - - IFS="${IFS= }"; save_ifs="$IFS"; IFS=$PATH_SEPARATOR - for dir in $PATH /usr/ucb; do - if (test -f $dir/echo || test -f $dir/echo$ac_exeext) && - test "X`($dir/echo '\t') 2>/dev/null`" = 'X\t' && - echo_testing_string=`($dir/echo "$echo_test_string") 2>/dev/null` && - test "X$echo_testing_string" = "X$echo_test_string"; then - echo="$dir/echo" - break - fi - done - IFS="$save_ifs" - - if test "X$echo" = Xecho; then - # We didn't find a better echo, so look for alternatives. - if test "X`(print -r '\t') 2>/dev/null`" = 'X\t' && - echo_testing_string=`(print -r "$echo_test_string") 2>/dev/null` && - test "X$echo_testing_string" = "X$echo_test_string"; then - # This shell has a builtin print -r that does the trick. - echo='print -r' - elif (test -f /bin/ksh || test -f /bin/ksh$ac_exeext) && - test "X$CONFIG_SHELL" != X/bin/ksh; then - # If we have ksh, try running configure again with it. - ORIGINAL_CONFIG_SHELL=${CONFIG_SHELL-/bin/sh} - export ORIGINAL_CONFIG_SHELL - CONFIG_SHELL=/bin/ksh - export CONFIG_SHELL - exec $CONFIG_SHELL "$0" --no-reexec ${1+"$@"} - else - # Try using printf. - echo='printf %s\n' - if test "X`($echo '\t') 2>/dev/null`" = 'X\t' && - echo_testing_string=`($echo "$echo_test_string") 2>/dev/null` && - test "X$echo_testing_string" = "X$echo_test_string"; then - # Cool, printf works - : - elif echo_testing_string=`($ORIGINAL_CONFIG_SHELL "$0" --fallback-echo '\t') 2>/dev/null` && - test "X$echo_testing_string" = 'X\t' && - echo_testing_string=`($ORIGINAL_CONFIG_SHELL "$0" --fallback-echo "$echo_test_string") 2>/dev/null` && - test "X$echo_testing_string" = "X$echo_test_string"; then - CONFIG_SHELL=$ORIGINAL_CONFIG_SHELL - export CONFIG_SHELL - SHELL="$CONFIG_SHELL" - export SHELL - echo="$CONFIG_SHELL $0 --fallback-echo" - elif echo_testing_string=`($CONFIG_SHELL "$0" --fallback-echo '\t') 2>/dev/null` && - test "X$echo_testing_string" = 'X\t' && - echo_testing_string=`($CONFIG_SHELL "$0" --fallback-echo "$echo_test_string") 2>/dev/null` && - test "X$echo_testing_string" = "X$echo_test_string"; then - echo="$CONFIG_SHELL $0 --fallback-echo" - else - # maybe with a smaller string... - prev=: - - for cmd in 'echo test' 'sed 2q "$0"' 'sed 10q "$0"' 'sed 20q "$0"' 'sed 50q "$0"'; do - if (test "X$echo_test_string" = "X`eval $cmd`") 2>/dev/null - then - break - fi - prev="$cmd" - done - - if test "$prev" != 'sed 50q "$0"'; then - echo_test_string=`eval $prev` - export echo_test_string - exec ${ORIGINAL_CONFIG_SHELL-${CONFIG_SHELL-/bin/sh}} "$0" ${1+"$@"} - else - # Oops. We lost completely, so just stick with echo. - echo=echo - fi - fi - fi - fi -fi -fi - -# Copy echo and quote the copy suitably for passing to libtool from -# the Makefile, instead of quoting the original, which is used later. -ECHO=$echo -if test "X$ECHO" = "X$CONFIG_SHELL $0 --fallback-echo"; then - ECHO="$CONFIG_SHELL \\\$\$0 --fallback-echo" -fi - - - -if expr a : '\(a\)' >/dev/null 2>&1; then - as_expr=expr -else - as_expr=false -fi - - ## --------------------- ## ## M4sh Initialization. ## ## --------------------- ## @@ -183,11 +16,13 @@ fi if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then emulate sh NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then set -o posix fi -# NLS nuisances. # Support unset when possible. if (FOO=FOO; unset FOO) >/dev/null 2>&1; then as_unset=unset @@ -195,34 +30,42 @@ else as_unset=false fi -(set +x; test -n "`(LANG=C; export LANG) 2>&1`") && - { $as_unset LANG || test "${LANG+set}" != set; } || - { LANG=C; export LANG; } -(set +x; test -n "`(LC_ALL=C; export LC_ALL) 2>&1`") && - { $as_unset LC_ALL || test "${LC_ALL+set}" != set; } || - { LC_ALL=C; export LC_ALL; } -(set +x; test -n "`(LC_TIME=C; export LC_TIME) 2>&1`") && - { $as_unset LC_TIME || test "${LC_TIME+set}" != set; } || - { LC_TIME=C; export LC_TIME; } -(set +x; test -n "`(LC_CTYPE=C; export LC_CTYPE) 2>&1`") && - { $as_unset LC_CTYPE || test "${LC_CTYPE+set}" != set; } || - { LC_CTYPE=C; export LC_CTYPE; } -(set +x; test -n "`(LANGUAGE=C; export LANGUAGE) 2>&1`") && - { $as_unset LANGUAGE || test "${LANGUAGE+set}" != set; } || - { LANGUAGE=C; export LANGUAGE; } -(set +x; test -n "`(LC_COLLATE=C; export LC_COLLATE) 2>&1`") && - { $as_unset LC_COLLATE || test "${LC_COLLATE+set}" != set; } || - { LC_COLLATE=C; export LC_COLLATE; } -(set +x; test -n "`(LC_NUMERIC=C; export LC_NUMERIC) 2>&1`") && - { $as_unset LC_NUMERIC || test "${LC_NUMERIC+set}" != set; } || - { LC_NUMERIC=C; export LC_NUMERIC; } -(set +x; test -n "`(LC_MESSAGES=C; export LC_MESSAGES) 2>&1`") && - { $as_unset LC_MESSAGES || test "${LC_MESSAGES+set}" != set; } || - { LC_MESSAGES=C; export LC_MESSAGES; } + +# Work around bugs in pre-3.0 UWIN ksh. +$as_unset ENV MAIL MAILPATH +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +for as_var in \ + LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ + LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ + LC_TELEPHONE LC_TIME +do + if (set +x; test -n "`(eval $as_var=C; export $as_var) 2>&1`"); then + eval $as_var=C; export $as_var + else + $as_unset $as_var + fi +done + +# Required to use basename. +if expr a : '\(a\)' >/dev/null 2>&1; then + as_expr=expr +else + as_expr=false +fi + +if (basename /) >/dev/null 2>&1 && test "X`basename / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi # Name of the executable. -as_me=`(basename "$0") 2>/dev/null || +as_me=`$as_basename "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)$' \| \ @@ -233,6 +76,7 @@ echo X/"$0" | /^X\/\(\/\).*/{ s//\1/; q; } s/.*/./; q'` + # PATH needs CR, and LINENO needs CR and PATH. # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' @@ -243,15 +87,15 @@ as_cr_alnum=$as_cr_Letters$as_cr_digits # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then - echo "#! /bin/sh" >conftest.sh - echo "exit 0" >>conftest.sh - chmod +x conftest.sh - if (PATH=".;."; conftest.sh) >/dev/null 2>&1; then + echo "#! /bin/sh" >conf$$.sh + echo "exit 0" >>conf$$.sh + chmod +x conf$$.sh + if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then PATH_SEPARATOR=';' else PATH_SEPARATOR=: fi - rm -f conftest.sh + rm -f conf$$.sh fi @@ -299,6 +143,8 @@ do as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` test "x$as_lineno_1" != "x$as_lineno_2" && test "x$as_lineno_3" = "x$as_lineno_2" ') 2>/dev/null; then + $as_unset BASH_ENV || test "${BASH_ENV+set}" != set || { BASH_ENV=; export BASH_ENV; } + $as_unset ENV || test "${ENV+set}" != set || { ENV=; export ENV; } CONFIG_SHELL=$as_dir/$as_base export CONFIG_SHELL exec "$CONFIG_SHELL" "$0" ${1+"$@"} @@ -371,6 +217,12 @@ else fi rm -f conf$$ conf$$.exe conf$$.file +if mkdir -p . 2>/dev/null; then + as_mkdir_p=: +else + as_mkdir_p=false +fi + as_executable_p="test -f" # Sed expression to map a string onto a valid CPP name. @@ -387,7 +239,166 @@ as_nl=' IFS=" $as_nl" # CDPATH. -$as_unset CDPATH || test "${CDPATH+set}" != set || { CDPATH=$PATH_SEPARATOR; export CDPATH; } +$as_unset CDPATH + + +# Find the correct PATH separator. Usually this is `:', but +# DJGPP uses `;' like DOS. +if test "X${PATH_SEPARATOR+set}" != Xset; then + UNAME=${UNAME-`uname 2>/dev/null`} + case X$UNAME in + *-DOS) lt_cv_sys_path_separator=';' ;; + *) lt_cv_sys_path_separator=':' ;; + esac + PATH_SEPARATOR=$lt_cv_sys_path_separator +fi + + +# Check that we are running under the correct shell. +SHELL=${CONFIG_SHELL-/bin/sh} + +case X$ECHO in +X*--fallback-echo) + # Remove one level of quotation (which was required for Make). + ECHO=`echo "$ECHO" | sed 's,\\\\\$\\$0,'$0','` + ;; +esac + +echo=${ECHO-echo} +if test "X$1" = X--no-reexec; then + # Discard the --no-reexec flag, and continue. + shift +elif test "X$1" = X--fallback-echo; then + # Avoid inline document here, it may be left over + : +elif test "X`($echo '\t') 2>/dev/null`" = 'X\t'; then + # Yippee, $echo works! + : +else + # Restart under the correct shell. + exec $SHELL "$0" --no-reexec ${1+"$@"} +fi + +if test "X$1" = X--fallback-echo; then + # used as fallback echo + shift + cat <<EOF + +EOF + exit 0 +fi + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +if test "X${CDPATH+set}" = Xset; then CDPATH=:; export CDPATH; fi + +if test -z "$ECHO"; then +if test "X${echo_test_string+set}" != Xset; then +# find a string as large as possible, as long as the shell can cope with it + for cmd in 'sed 50q "$0"' 'sed 20q "$0"' 'sed 10q "$0"' 'sed 2q "$0"' 'echo test'; do + # expected sizes: less than 2Kb, 1Kb, 512 bytes, 16 bytes, ... + if (echo_test_string="`eval $cmd`") 2>/dev/null && + echo_test_string="`eval $cmd`" && + (test "X$echo_test_string" = "X$echo_test_string") 2>/dev/null + then + break + fi + done +fi + +if test "X`($echo '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`($echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + : +else + # The Solaris, AIX, and Digital Unix default echo programs unquote + # backslashes. This makes it impossible to quote backslashes using + # echo "$something" | sed 's/\\/\\\\/g' + # + # So, first we look for a working echo in the user's PATH. + + IFS="${IFS= }"; save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for dir in $PATH /usr/ucb; do + if (test -f $dir/echo || test -f $dir/echo$ac_exeext) && + test "X`($dir/echo '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`($dir/echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + echo="$dir/echo" + break + fi + done + IFS="$save_ifs" + + if test "X$echo" = Xecho; then + # We didn't find a better echo, so look for alternatives. + if test "X`(print -r '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`(print -r "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + # This shell has a builtin print -r that does the trick. + echo='print -r' + elif (test -f /bin/ksh || test -f /bin/ksh$ac_exeext) && + test "X$CONFIG_SHELL" != X/bin/ksh; then + # If we have ksh, try running configure again with it. + ORIGINAL_CONFIG_SHELL=${CONFIG_SHELL-/bin/sh} + export ORIGINAL_CONFIG_SHELL + CONFIG_SHELL=/bin/ksh + export CONFIG_SHELL + exec $CONFIG_SHELL "$0" --no-reexec ${1+"$@"} + else + # Try using printf. + echo='printf %s\n' + if test "X`($echo '\t') 2>/dev/null`" = 'X\t' && + echo_testing_string=`($echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + # Cool, printf works + : + elif echo_testing_string=`($ORIGINAL_CONFIG_SHELL "$0" --fallback-echo '\t') 2>/dev/null` && + test "X$echo_testing_string" = 'X\t' && + echo_testing_string=`($ORIGINAL_CONFIG_SHELL "$0" --fallback-echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + CONFIG_SHELL=$ORIGINAL_CONFIG_SHELL + export CONFIG_SHELL + SHELL="$CONFIG_SHELL" + export SHELL + echo="$CONFIG_SHELL $0 --fallback-echo" + elif echo_testing_string=`($CONFIG_SHELL "$0" --fallback-echo '\t') 2>/dev/null` && + test "X$echo_testing_string" = 'X\t' && + echo_testing_string=`($CONFIG_SHELL "$0" --fallback-echo "$echo_test_string") 2>/dev/null` && + test "X$echo_testing_string" = "X$echo_test_string"; then + echo="$CONFIG_SHELL $0 --fallback-echo" + else + # maybe with a smaller string... + prev=: + + for cmd in 'echo test' 'sed 2q "$0"' 'sed 10q "$0"' 'sed 20q "$0"' 'sed 50q "$0"'; do + if (test "X$echo_test_string" = "X`eval $cmd`") 2>/dev/null + then + break + fi + prev="$cmd" + done + + if test "$prev" != 'sed 50q "$0"'; then + echo_test_string=`eval $prev` + export echo_test_string + exec ${ORIGINAL_CONFIG_SHELL-${CONFIG_SHELL-/bin/sh}} "$0" ${1+"$@"} + else + # Oops. We lost completely, so just stick with echo. + echo=echo + fi + fi + fi + fi +fi +fi + +# Copy echo and quote the copy suitably for passing to libtool from +# the Makefile, instead of quoting the original, which is used later. +ECHO=$echo +if test "X$ECHO" = "X$CONFIG_SHELL $0 --fallback-echo"; then + ECHO="$CONFIG_SHELL \\\$\$0 --fallback-echo" +fi + # Name of the host. @@ -401,6 +412,7 @@ exec 6>&1 # Initializations. # ac_default_prefix=/usr/local +ac_config_libobj_dir=. cross_compiling=no subdirs= MFLAGS= @@ -457,6 +469,8 @@ ac_includes_default="\ # include <unistd.h> #endif" +ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA AWK CPP CXX CXXFLAGS ac_ct_CXX RANLIB ac_ct_RANLIB build build_cpu build_vendor build_os host host_cpu host_vendor host_os LN_S ECHO STRIP ac_ct_STRIP EGREP LIBTOOL EXEC_LDFLAGS LIBOBJS PACKAGE VERSION ACLOCAL AUTOCONF AUTOMAKE AUTOHEADER MAKEINFO AMTAR install_sh INSTALL_STRIP_PROGRAM SET_MAKE DEPDIR am__include am__quote AMDEP_TRUE AMDEP_FALSE AMDEPBACKSLASH CCDEPMODE CXXDEPMODE LTLIBOBJS' +ac_subst_files='' # Initialize some variables set by options. ac_init_help= @@ -880,6 +894,9 @@ if test ! -r $srcdir/$ac_unique_file; then { (exit 1); exit 1; }; } fi fi +(cd $srcdir && test -r ./$ac_unique_file) 2>/dev/null || + { echo "$as_me: error: sources are in $srcdir, but \`cd $srcdir' does not work" >&2 + { (exit 1); exit 1; }; } srcdir=`echo "$srcdir" | sed 's%\([^\\/]\)[\\/]*$%\1%'` ac_env_build_alias_set=${build_alias+set} ac_env_build_alias_value=$build_alias @@ -1067,7 +1084,7 @@ esac # Don't blindly perform a `cd "$ac_dir"/$ac_foo && pwd` since $ac_foo can be # absolute. ac_abs_builddir=`cd "$ac_dir" && cd $ac_builddir && pwd` -ac_abs_top_builddir=`cd "$ac_dir" && cd $ac_top_builddir && pwd` +ac_abs_top_builddir=`cd "$ac_dir" && cd ${ac_top_builddir}. && pwd` ac_abs_srcdir=`cd "$ac_dir" && cd $ac_srcdir && pwd` ac_abs_top_srcdir=`cd "$ac_dir" && cd $ac_top_srcdir && pwd` @@ -1094,7 +1111,7 @@ test -n "$ac_init_help" && exit 0 if $ac_init_version; then cat <<\_ACEOF openggsn configure 0.61b -generated by GNU Autoconf 2.53 +generated by GNU Autoconf 2.57 Copyright 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc. @@ -1109,7 +1126,7 @@ This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by openggsn $as_me 0.61b, which was -generated by GNU Autoconf 2.53. Invocation command line was +generated by GNU Autoconf 2.57. Invocation command line was $ $0 $@ @@ -1161,27 +1178,54 @@ _ACEOF # Keep a trace of the command line. # Strip out --no-create and --no-recursion so they do not pile up. +# Strip out --silent because we don't want to record it for future runs. # Also quote any args containing shell meta-characters. +# Make two passes to allow for proper duplicate-argument suppression. ac_configure_args= +ac_configure_args0= +ac_configure_args1= ac_sep= -for ac_arg +ac_must_keep_next=false +for ac_pass in 1 2 do - case $ac_arg in - -no-create | --no-create | --no-creat | --no-crea | --no-cre \ - | --no-cr | --no-c | -n ) continue ;; - -no-recursion | --no-recursion | --no-recursio | --no-recursi \ - | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) - continue ;; - *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*) - ac_arg=`echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; - esac - case " $ac_configure_args " in - *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. - *) ac_configure_args="$ac_configure_args$ac_sep'$ac_arg'" - ac_sep=" " ;; - esac - # Get rid of the leading space. + for ac_arg + do + case $ac_arg in + -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + continue ;; + *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*) + ac_arg=`echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + case $ac_pass in + 1) ac_configure_args0="$ac_configure_args0 '$ac_arg'" ;; + 2) + ac_configure_args1="$ac_configure_args1 '$ac_arg'" + if test $ac_must_keep_next = true; then + ac_must_keep_next=false # Got value, back to normal. + else + case $ac_arg in + *=* | --config-cache | -C | -disable-* | --disable-* \ + | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ + | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ + | -with-* | --with-* | -without-* | --without-* | --x) + case "$ac_configure_args0 " in + "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; + esac + ;; + -* ) ac_must_keep_next=true ;; + esac + fi + ac_configure_args="$ac_configure_args$ac_sep'$ac_arg'" + # Get rid of the leading space. + ac_sep=" " + ;; + esac + done done +$as_unset ac_configure_args0 || test "${ac_configure_args0+set}" != set || { ac_configure_args0=; export ac_configure_args0; } +$as_unset ac_configure_args1 || test "${ac_configure_args1+set}" != set || { ac_configure_args1=; export ac_configure_args1; } # When interrupted or exit'd, cleanup temporary files, and complete # config.log. We remove comments because anyway the quotes in there @@ -1192,6 +1236,7 @@ trap 'exit_status=$? # Save into config.log some information that might help in debugging. { echo + cat <<\_ASBOX ## ---------------- ## ## Cache variables. ## @@ -1214,6 +1259,35 @@ _ASBOX esac; } echo + + cat <<\_ASBOX +## ----------------- ## +## Output variables. ## +## ----------------- ## +_ASBOX + echo + for ac_var in $ac_subst_vars + do + eval ac_val=$`echo $ac_var` + echo "$ac_var='"'"'$ac_val'"'"'" + done | sort + echo + + if test -n "$ac_subst_files"; then + cat <<\_ASBOX +## ------------- ## +## Output files. ## +## ------------- ## +_ASBOX + echo + for ac_var in $ac_subst_files + do + eval ac_val=$`echo $ac_var` + echo "$ac_var='"'"'$ac_val'"'"'" + done | sort + echo + fi + if test -s confdefs.h; then cat <<\_ASBOX ## ----------- ## @@ -1221,7 +1295,7 @@ _ASBOX ## ----------- ## _ASBOX echo - sed "/^$/d" confdefs.h + sed "/^$/d" confdefs.h | sort echo fi test "$ac_signal" != 0 && @@ -1387,9 +1461,10 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu + # Add the stamp file to the list of files AC keeps track of, # along with our hook. -ac_config_headers="$ac_config_headers config.h" + ac_config_headers="$ac_config_headers config.h" @@ -1600,9 +1675,7 @@ if test $ac_prog_rejected = yes; then # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift - set dummy "$as_dir/$ac_word" ${1+"$@"} - shift - ac_cv_prog_CC="$@" + ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" fi fi fi @@ -1707,8 +1780,10 @@ fi fi -test -z "$CC" && { { echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH" >&5 -echo "$as_me: error: no acceptable C compiler found in \$PATH" >&2;} +test -z "$CC" && { { echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH +See \`config.log' for more details." >&5 +echo "$as_me: error: no acceptable C compiler found in \$PATH +See \`config.log' for more details." >&2;} { (exit 1); exit 1; }; } # Provide some information about the compiler. @@ -1733,14 +1808,12 @@ ac_compiler=`set X $ac_compile; echo $2` cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" -#include "confdefs.h" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ -#ifdef F77_DUMMY_MAIN -# ifdef __cplusplus - extern "C" -# endif - int F77_DUMMY_MAIN() { return 1; } -#endif int main () { @@ -1750,7 +1823,7 @@ main () } _ACEOF ac_clean_files_save=$ac_clean_files -ac_clean_files="$ac_clean_files a.out a.exe" +ac_clean_files="$ac_clean_files a.out a.exe b.out" # Try to create an executable without -o first, disregard a.out. # It will help us diagnose broken compilers, and finding out an intuition # of exeext. @@ -1769,26 +1842,39 @@ if { (eval echo "$as_me:$LINENO: \"$ac_link_default\"") >&5 # Be careful to initialize this variable, since it used to be cached. # Otherwise an old cache value of `no' led to `EXEEXT = no' in a Makefile. ac_cv_exeext= -for ac_file in `ls a_out.exe a.exe conftest.exe 2>/dev/null; - ls a.out conftest 2>/dev/null; - ls a.* conftest.* 2>/dev/null`; do +# b.out is created by i960 compilers. +for ac_file in a_out.exe a.exe conftest.exe a.out conftest a.* conftest.* b.out +do + test -f "$ac_file" || continue case $ac_file in - *.$ac_ext | *.o | *.obj | *.xcoff | *.tds | *.d | *.pdb | *.xSYM ) ;; - a.out ) # We found the default executable, but exeext='' is most - # certainly right. - break;; - *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` - # FIXME: I believe we export ac_cv_exeext for Libtool --akim. - export ac_cv_exeext - break;; - * ) break;; + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.o | *.obj ) + ;; + conftest.$ac_ext ) + # This is the source file. + ;; + [ab].out ) + # We found the default executable, but exeext='' is most + # certainly right. + break;; + *.* ) + ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + # FIXME: I believe we export ac_cv_exeext for Libtool, + # but it would be cool to find out if it's true. Does anybody + # maintain Libtool? --akim. + export ac_cv_exeext + break;; + * ) + break;; esac done else echo "$as_me: failed program was:" >&5 -cat conftest.$ac_ext >&5 -{ { echo "$as_me:$LINENO: error: C compiler cannot create executables" >&5 -echo "$as_me: error: C compiler cannot create executables" >&2;} +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { echo "$as_me:$LINENO: error: C compiler cannot create executables +See \`config.log' for more details." >&5 +echo "$as_me: error: C compiler cannot create executables +See \`config.log' for more details." >&2;} { (exit 77); exit 77; }; } fi @@ -1815,9 +1901,11 @@ if test "$cross_compiling" != yes; then cross_compiling=yes else { { echo "$as_me:$LINENO: error: cannot run C compiled programs. -If you meant to cross compile, use \`--host'." >&5 +If you meant to cross compile, use \`--host'. +See \`config.log' for more details." >&5 echo "$as_me: error: cannot run C compiled programs. -If you meant to cross compile, use \`--host'." >&2;} +If you meant to cross compile, use \`--host'. +See \`config.log' for more details." >&2;} { (exit 1); exit 1; }; } fi fi @@ -1825,7 +1913,7 @@ fi echo "$as_me:$LINENO: result: yes" >&5 echo "${ECHO_T}yes" >&6 -rm -f a.out a.exe conftest$ac_cv_exeext +rm -f a.out a.exe conftest$ac_cv_exeext b.out ac_clean_files=$ac_clean_files_save # Check the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. @@ -1845,9 +1933,10 @@ if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 # catch `conftest.exe'. For instance with Cygwin, `ls conftest' will # work properly (i.e., refer to `conftest.exe'), while it won't with # `rm'. -for ac_file in `(ls conftest.exe; ls conftest; ls conftest.*) 2>/dev/null`; do +for ac_file in conftest.exe conftest conftest.*; do + test -f "$ac_file" || continue case $ac_file in - *.$ac_ext | *.o | *.obj | *.xcoff | *.tds | *.d | *.pdb ) ;; + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.o | *.obj ) ;; *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` export ac_cv_exeext break;; @@ -1855,8 +1944,10 @@ for ac_file in `(ls conftest.exe; ls conftest; ls conftest.*) 2>/dev/null`; do esac done else - { { echo "$as_me:$LINENO: error: cannot compute suffix of executables: cannot compile and link" >&5 -echo "$as_me: error: cannot compute suffix of executables: cannot compile and link" >&2;} + { { echo "$as_me:$LINENO: error: cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details." >&2;} { (exit 1); exit 1; }; } fi @@ -1874,14 +1965,12 @@ if test "${ac_cv_objext+set}" = set; then else cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" -#include "confdefs.h" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ -#ifdef F77_DUMMY_MAIN -# ifdef __cplusplus - extern "C" -# endif - int F77_DUMMY_MAIN() { return 1; } -#endif int main () { @@ -1898,16 +1987,19 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (exit $ac_status); }; then for ac_file in `(ls conftest.o conftest.obj; ls conftest.*) 2>/dev/null`; do case $ac_file in - *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb ) ;; + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg ) ;; *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` break;; esac done else echo "$as_me: failed program was:" >&5 -cat conftest.$ac_ext >&5 -{ { echo "$as_me:$LINENO: error: cannot compute suffix of object files: cannot compile" >&5 -echo "$as_me: error: cannot compute suffix of object files: cannot compile" >&2;} +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { echo "$as_me:$LINENO: error: cannot compute suffix of object files: cannot compile +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot compute suffix of object files: cannot compile +See \`config.log' for more details." >&2;} { (exit 1); exit 1; }; } fi @@ -1924,14 +2016,12 @@ if test "${ac_cv_c_compiler_gnu+set}" = set; then else cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" -#include "confdefs.h" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ -#ifdef F77_DUMMY_MAIN -# ifdef __cplusplus - extern "C" -# endif - int F77_DUMMY_MAIN() { return 1; } -#endif int main () { @@ -1958,7 +2048,8 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 ac_compiler_gnu=yes else echo "$as_me: failed program was:" >&5 -cat conftest.$ac_ext >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + ac_compiler_gnu=no fi rm -f conftest.$ac_objext conftest.$ac_ext @@ -1978,14 +2069,12 @@ if test "${ac_cv_prog_cc_g+set}" = set; then else cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" -#include "confdefs.h" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ -#ifdef F77_DUMMY_MAIN -# ifdef __cplusplus - extern "C" -# endif - int F77_DUMMY_MAIN() { return 1; } -#endif int main () { @@ -2009,7 +2098,8 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 ac_cv_prog_cc_g=yes else echo "$as_me: failed program was:" >&5 -cat conftest.$ac_ext >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + ac_cv_prog_cc_g=no fi rm -f conftest.$ac_objext conftest.$ac_ext @@ -2031,6 +2121,102 @@ else CFLAGS= fi fi +echo "$as_me:$LINENO: checking for $CC option to accept ANSI C" >&5 +echo $ECHO_N "checking for $CC option to accept ANSI C... $ECHO_C" >&6 +if test "${ac_cv_prog_cc_stdc+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_cv_prog_cc_stdc=no +ac_save_CC=$CC +cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <stdarg.h> +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> +/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ +struct buf { int x; }; +FILE * (*rcsopen) (struct buf *, struct stat *, int); +static char *e (p, i) + char **p; + int i; +{ + return p[i]; +} +static char *f (char * (*g) (char **, int), char **p, ...) +{ + char *s; + va_list v; + va_start (v,p); + s = g (p, va_arg (v,int)); + va_end (v); + return s; +} +int test (int i, double x); +struct s1 {int (*f) (int a);}; +struct s2 {int (*f) (double a);}; +int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); +int argc; +char **argv; +int +main () +{ +return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; + ; + return 0; +} +_ACEOF +# Don't try gcc -ansi; that turns off useful extensions and +# breaks some systems' header files. +# AIX -qlanglvl=ansi +# Ultrix and OSF/1 -std1 +# HP-UX 10.20 and later -Ae +# HP-UX older versions -Aa -D_HPUX_SOURCE +# SVR4 -Xc -D__EXTENSIONS__ +for ac_arg in "" -qlanglvl=ansi -std1 -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +do + CC="$ac_save_CC $ac_arg" + rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_prog_cc_stdc=$ac_arg +break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.$ac_objext +done +rm -f conftest.$ac_ext conftest.$ac_objext +CC=$ac_save_CC + +fi + +case "x$ac_cv_prog_cc_stdc" in + x|xno) + echo "$as_me:$LINENO: result: none needed" >&5 +echo "${ECHO_T}none needed" >&6 ;; + *) + echo "$as_me:$LINENO: result: $ac_cv_prog_cc_stdc" >&5 +echo "${ECHO_T}$ac_cv_prog_cc_stdc" >&6 + CC="$CC $ac_cv_prog_cc_stdc" ;; +esac + # Some people use a C++ compiler to compile C. Since we use `exit', # in C++ we need to declare it. In case someone uses the same compiler # for both compiling C and C++ we need to have the C++ compiler decide @@ -2063,15 +2249,13 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 do cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" -#include "confdefs.h" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ #include <stdlib.h> $ac_declaration -#ifdef F77_DUMMY_MAIN -# ifdef __cplusplus - extern "C" -# endif - int F77_DUMMY_MAIN() { return 1; } -#endif int main () { @@ -2095,20 +2279,19 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 : else echo "$as_me: failed program was:" >&5 -cat conftest.$ac_ext >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + continue fi rm -f conftest.$ac_objext conftest.$ac_ext cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" -#include "confdefs.h" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ $ac_declaration -#ifdef F77_DUMMY_MAIN -# ifdef __cplusplus - extern "C" -# endif - int F77_DUMMY_MAIN() { return 1; } -#endif int main () { @@ -2132,7 +2315,8 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 break else echo "$as_me: failed program was:" >&5 -cat conftest.$ac_ext >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + fi rm -f conftest.$ac_objext conftest.$ac_ext done @@ -2145,7 +2329,8 @@ fi else echo "$as_me: failed program was:" >&5 -cat conftest.$ac_ext >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + fi rm -f conftest.$ac_objext conftest.$ac_ext ac_ext=c @@ -2319,18 +2504,28 @@ for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. + # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since + # <limits.h> exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" -#include "confdefs.h" -#include <assert.h> +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#ifdef __STDC__ +# include <limits.h> +#else +# include <assert.h> +#endif Syntax error _ACEOF if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 ac_status=$? - egrep -v '^ *\+' conftest.er1 >conftest.err + grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 @@ -2347,7 +2542,8 @@ if test -z "$ac_cpp_err"; then : else echo "$as_me: failed program was:" >&5 - cat conftest.$ac_ext >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + # Broken: fails on valid input. continue fi @@ -2357,13 +2553,17 @@ rm -f conftest.err conftest.$ac_ext # can be detected and how. cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" -#include "confdefs.h" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ #include <ac_nonexistent.h> _ACEOF if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 ac_status=$? - egrep -v '^ *\+' conftest.er1 >conftest.err + grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 @@ -2381,7 +2581,8 @@ if test -z "$ac_cpp_err"; then continue else echo "$as_me: failed program was:" >&5 - cat conftest.$ac_ext >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + # Passes both tests. ac_preproc_ok=: break @@ -2410,18 +2611,28 @@ for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. + # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since + # <limits.h> exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" -#include "confdefs.h" -#include <assert.h> +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#ifdef __STDC__ +# include <limits.h> +#else +# include <assert.h> +#endif Syntax error _ACEOF if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 ac_status=$? - egrep -v '^ *\+' conftest.er1 >conftest.err + grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 @@ -2438,7 +2649,8 @@ if test -z "$ac_cpp_err"; then : else echo "$as_me: failed program was:" >&5 - cat conftest.$ac_ext >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + # Broken: fails on valid input. continue fi @@ -2448,13 +2660,17 @@ rm -f conftest.err conftest.$ac_ext # can be detected and how. cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" -#include "confdefs.h" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ #include <ac_nonexistent.h> _ACEOF if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 ac_status=$? - egrep -v '^ *\+' conftest.er1 >conftest.err + grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 @@ -2472,7 +2688,8 @@ if test -z "$ac_cpp_err"; then continue else echo "$as_me: failed program was:" >&5 - cat conftest.$ac_ext >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + # Passes both tests. ac_preproc_ok=: break @@ -2485,8 +2702,10 @@ rm -f conftest.err conftest.$ac_ext if $ac_preproc_ok; then : else - { { echo "$as_me:$LINENO: error: C preprocessor \"$CPP\" fails sanity check" >&5 -echo "$as_me: error: C preprocessor \"$CPP\" fails sanity check" >&2;} + { { echo "$as_me:$LINENO: error: C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details." >&5 +echo "$as_me: error: C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details." >&2;} { (exit 1); exit 1; }; } fi @@ -2616,14 +2835,12 @@ if test "${ac_cv_cxx_compiler_gnu+set}" = set; then else cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" -#include "confdefs.h" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ -#ifdef F77_DUMMY_MAIN -# ifdef __cplusplus - extern "C" -# endif - int F77_DUMMY_MAIN() { return 1; } -#endif int main () { @@ -2650,7 +2867,8 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 ac_compiler_gnu=yes else echo "$as_me: failed program was:" >&5 -cat conftest.$ac_ext >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + ac_compiler_gnu=no fi rm -f conftest.$ac_objext conftest.$ac_ext @@ -2670,14 +2888,12 @@ if test "${ac_cv_prog_cxx_g+set}" = set; then else cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" -#include "confdefs.h" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ -#ifdef F77_DUMMY_MAIN -# ifdef __cplusplus - extern "C" -# endif - int F77_DUMMY_MAIN() { return 1; } -#endif int main () { @@ -2701,7 +2917,8 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 ac_cv_prog_cxx_g=yes else echo "$as_me: failed program was:" >&5 -cat conftest.$ac_ext >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + ac_cv_prog_cxx_g=no fi rm -f conftest.$ac_objext conftest.$ac_ext @@ -2734,15 +2951,13 @@ for ac_declaration in \ do cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" -#include "confdefs.h" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ #include <stdlib.h> $ac_declaration -#ifdef F77_DUMMY_MAIN -# ifdef __cplusplus - extern "C" -# endif - int F77_DUMMY_MAIN() { return 1; } -#endif int main () { @@ -2766,20 +2981,19 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 : else echo "$as_me: failed program was:" >&5 -cat conftest.$ac_ext >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + continue fi rm -f conftest.$ac_objext conftest.$ac_ext cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" -#include "confdefs.h" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ $ac_declaration -#ifdef F77_DUMMY_MAIN -# ifdef __cplusplus - extern "C" -# endif - int F77_DUMMY_MAIN() { return 1; } -#endif int main () { @@ -2803,7 +3017,8 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 break else echo "$as_me: failed program was:" >&5 -cat conftest.$ac_ext >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + fi rm -f conftest.$ac_objext conftest.$ac_ext done @@ -3185,6 +3400,91 @@ NM="$lt_cv_path_NM" echo "$as_me:$LINENO: result: $NM" >&5 echo "${ECHO_T}$NM" >&6 +echo "$as_me:$LINENO: checking for a sed that does not truncate output" >&5 +echo $ECHO_N "checking for a sed that does not truncate output... $ECHO_C" >&6 +if test "${lt_cv_path_SED+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + # Loop through the user's path and test for sed and gsed. +# Then use that list of sed's as ones to test for truncation. +as_executable_p="test -f" +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in sed gsed; do + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then + _sed_list="$_sed_list $as_dir/$ac_prog$ac_exec_ext" + fi + done + done +done + + # Create a temporary directory, and hook for its removal unless debugging. +$debug || +{ + trap 'exit_status=$?; rm -rf $tmp && exit $exit_status' 0 + trap '{ (exit 1); exit 1; }' 1 2 13 15 +} + +# Create a (secure) tmp directory for tmp files. +: ${TMPDIR=/tmp} +{ + tmp=`(umask 077 && mktemp -d -q "$TMPDIR/sedXXXXXX") 2>/dev/null` && + test -n "$tmp" && test -d "$tmp" +} || +{ + tmp=$TMPDIR/sed$$-$RANDOM + (umask 077 && mkdir $tmp) +} || +{ + echo "$me: cannot create a temporary directory in $TMPDIR" >&2 + { (exit 1); exit 1; } +} + _max=0 + _count=0 + # Add /usr/xpg4/bin/sed as it is typically found on Solaris + # along with /bin/sed that truncates output. + for _sed in $_sed_list /usr/xpg4/bin/sed; do + test ! -f ${_sed} && break + cat /dev/null > "$tmp/sed.in" + _count=0 + echo ${ECHO_N-$ac_n} "0123456789${ECHO_C-$ac_c}" >"$tmp/sed.in" + # Check for GNU sed and select it if it is found. + if "${_sed}" --version 2>&1 < /dev/null | egrep '(GNU)' > /dev/null; then + lt_cv_path_SED=${_sed} + break + fi + while true; do + cat "$tmp/sed.in" "$tmp/sed.in" >"$tmp/sed.tmp" + mv "$tmp/sed.tmp" "$tmp/sed.in" + cp "$tmp/sed.in" "$tmp/sed.nl" + echo >>"$tmp/sed.nl" + ${_sed} -e 's/a$//' < "$tmp/sed.nl" >"$tmp/sed.out" || break + cmp -s "$tmp/sed.out" "$tmp/sed.nl" || break + # 40000 chars as input seems more than enough + test $_count -gt 10 && break + _count=`expr $_count + 1` + if test $_count -gt $_max; then + _max=$_count + lt_cv_path_SED=$_sed + fi + done + done + rm -rf "$tmp" + +fi + +if test "X$SED" != "X"; then + lt_cv_path_SED=$SED +else + SED=$lt_cv_path_SED +fi +echo "$as_me:$LINENO: result: $SED" >&5 +echo "${ECHO_T}$SED" >&6 + echo "$as_me:$LINENO: checking whether ln -s works" >&5 echo $ECHO_N "checking whether ln -s works... $ECHO_C" >&6 LN_S=$as_ln_s @@ -3196,8 +3496,8 @@ else echo "${ECHO_T}no, using $LN_S" >&6 fi -echo "$as_me:$LINENO: checking how to recognise dependant libraries" >&5 -echo $ECHO_N "checking how to recognise dependant libraries... $ECHO_C" >&6 +echo "$as_me:$LINENO: checking how to recognise dependent libraries" >&5 +echo $ECHO_N "checking how to recognise dependent libraries... $ECHO_C" >&6 if test "${lt_cv_deplibs_check_method+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else @@ -3274,9 +3574,9 @@ hpux10.20*|hpux11*) lt_cv_file_magic_test_file=/usr/lib/libc.sl ;; -irix5* | irix6*) +irix5* | irix6* | nonstopux*) case $host_os in - irix5*) + irix5* | nonstopux*) # this will be overridden with pass_all, but let us keep it just in case lt_cv_deplibs_check_method="file_magic ELF 32-bit MSB dynamic lib MIPS - version 1" ;; @@ -3298,7 +3598,7 @@ irix5* | irix6*) # This must be Linux ELF. linux-gnu*) case $host_cpu in - alpha* | hppa* | i*86 | powerpc* | sparc* | ia64* | s390* ) + alpha* | hppa* | i*86 | mips | mipsel | powerpc* | sparc* | ia64* | s390* | x86_64*) lt_cv_deplibs_check_method=pass_all ;; *) # glibc up to 2.1.1 does not perform some relocations on ARM @@ -3369,6 +3669,9 @@ sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) lt_cv_deplibs_check_method="file_magic ELF [0-9][0-9]*-bit [LM]SB dynamic lib" lt_cv_file_magic_test_file=/lib/libc.so ;; + siemens) + lt_cv_deplibs_check_method=pass_all + ;; esac ;; esac @@ -3423,9 +3726,12 @@ hpux*) # Its linker distinguishes data from code symbols lt_cv_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern char \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" lt_cv_global_symbol_to_c_name_address="sed -n -e 's/^: \([^ ]*\) $/ {\\\"\1\\\", (lt_ptr) 0},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"\2\", (lt_ptr) \&\2},/p'" ;; -irix*) +irix* | nonstopux*) symcode='[BCDEGRST]' ;; +osf*) + symcode='[BCDEGQRST]' + ;; solaris* | sysv5*) symcode='[BDT]' ;; @@ -3534,7 +3840,7 @@ EOF (eval $ac_link) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && test -s conftest; then + (exit $ac_status); } && test -s conftest$ac_exeext; then pipe_works=yes fi LIBS="$save_LIBS" @@ -3582,6 +3888,21 @@ echo "${ECHO_T}ok" >&6 fi +echo "$as_me:$LINENO: checking for egrep" >&5 +echo $ECHO_N "checking for egrep... $ECHO_C" >&6 +if test "${ac_cv_prog_egrep+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if echo a | (grep -E '(a|b)') >/dev/null 2>&1 + then ac_cv_prog_egrep='grep -E' + else ac_cv_prog_egrep='egrep' + fi +fi +echo "$as_me:$LINENO: result: $ac_cv_prog_egrep" >&5 +echo "${ECHO_T}$ac_cv_prog_egrep" >&6 + EGREP=$ac_cv_prog_egrep + + echo "$as_me:$LINENO: checking for ANSI C header files" >&5 echo $ECHO_N "checking for ANSI C header files... $ECHO_C" >&6 if test "${ac_cv_header_stdc+set}" = set; then @@ -3589,48 +3910,59 @@ if test "${ac_cv_header_stdc+set}" = set; then else cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" -#include "confdefs.h" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ #include <stdlib.h> #include <stdarg.h> #include <string.h> #include <float.h> +int +main () +{ + + ; + return 0; +} _ACEOF -if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 - (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 ac_status=$? - egrep -v '^ *\+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } >/dev/null; then - if test -s conftest.err; then - ac_cpp_err=$ac_c_preproc_warn_flag - else - ac_cpp_err= - fi -else - ac_cpp_err=yes -fi -if test -z "$ac_cpp_err"; then + (exit $ac_status); } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then ac_cv_header_stdc=yes else echo "$as_me: failed program was:" >&5 - cat conftest.$ac_ext >&5 - ac_cv_header_stdc=no +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_header_stdc=no fi -rm -f conftest.err conftest.$ac_ext +rm -f conftest.$ac_objext conftest.$ac_ext if test $ac_cv_header_stdc = yes; then # SunOS 4.x string.h does not declare mem*, contrary to ANSI. cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" -#include "confdefs.h" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ #include <string.h> _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - egrep "memchr" >/dev/null 2>&1; then + $EGREP "memchr" >/dev/null 2>&1; then : else ac_cv_header_stdc=no @@ -3643,12 +3975,16 @@ if test $ac_cv_header_stdc = yes; then # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" -#include "confdefs.h" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ #include <stdlib.h> _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - egrep "free" >/dev/null 2>&1; then + $EGREP "free" >/dev/null 2>&1; then : else ac_cv_header_stdc=no @@ -3664,13 +4000,18 @@ if test $ac_cv_header_stdc = yes; then else cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" -#include "confdefs.h" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ #include <ctype.h> #if ((' ' & 0x0FF) == 0x020) # define ISLOWER(c) ('a' <= (c) && (c) <= 'z') # define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) #else -# define ISLOWER(c) (('a' <= (c) && (c) <= 'i') \ +# define ISLOWER(c) \ + (('a' <= (c) && (c) <= 'i') \ || ('j' <= (c) && (c) <= 'r') \ || ('s' <= (c) && (c) <= 'z')) # define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) @@ -3703,11 +4044,12 @@ if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 else echo "$as_me: program exited with status $ac_status" >&5 echo "$as_me: failed program was:" >&5 -cat conftest.$ac_ext >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + ( exit $ac_status ) ac_cv_header_stdc=no fi -rm -f core core.* *.core conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +rm -f core core.* *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext fi fi fi @@ -3742,7 +4084,11 @@ if eval "test \"\${$as_ac_Header+set}\" = set"; then else cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" -#include "confdefs.h" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ $ac_includes_default #include <$ac_header> @@ -3762,7 +4108,8 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 eval "$as_ac_Header=yes" else echo "$as_me: failed program was:" >&5 -cat conftest.$ac_ext >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + eval "$as_ac_Header=no" fi rm -f conftest.$ac_objext conftest.$ac_ext @@ -3797,7 +4144,11 @@ echo "$as_me:$LINENO: checking $ac_header usability" >&5 echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6 cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" -#include "confdefs.h" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ $ac_includes_default #include <$ac_header> _ACEOF @@ -3816,7 +4167,8 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 ac_header_compiler=yes else echo "$as_me: failed program was:" >&5 -cat conftest.$ac_ext >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + ac_header_compiler=no fi rm -f conftest.$ac_objext conftest.$ac_ext @@ -3828,13 +4180,17 @@ echo "$as_me:$LINENO: checking $ac_header presence" >&5 echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6 cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" -#include "confdefs.h" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ #include <$ac_header> _ACEOF if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 ac_status=$? - egrep -v '^ *\+' conftest.er1 >conftest.err + grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 @@ -3851,7 +4207,8 @@ if test -z "$ac_cpp_err"; then ac_header_preproc=yes else echo "$as_me: failed program was:" >&5 - cat conftest.$ac_ext >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + ac_header_preproc=no fi rm -f conftest.err conftest.$ac_ext @@ -3864,14 +4221,32 @@ case $ac_header_compiler:$ac_header_preproc in { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 -echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;};; +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + ( + cat <<\_ASBOX +## ------------------------------------ ## +## Report this to bug-autoconf@gnu.org. ## +## ------------------------------------ ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 + ;; no:yes ) { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 -echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;};; +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + ( + cat <<\_ASBOX +## ------------------------------------ ## +## Report this to bug-autoconf@gnu.org. ## +## ------------------------------------ ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 + ;; esac echo "$as_me:$LINENO: checking for $ac_header" >&5 echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 @@ -3897,6 +4272,7 @@ done + # Only perform the check for file, if the check method requires it case $deplibs_check_method in file_magic*) @@ -4212,7 +4588,7 @@ test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes case $host in *-*-irix6*) # Find out which ABI we are using. - echo '#line 4215 "configure"' > conftest.$ac_ext + echo '#line 4591 "configure"' > conftest.$ac_ext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>&5 ac_status=$? @@ -4252,14 +4628,12 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" -#include "confdefs.h" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ -#ifdef F77_DUMMY_MAIN -# ifdef __cplusplus - extern "C" -# endif - int F77_DUMMY_MAIN() { return 1; } -#endif int main () { @@ -4283,7 +4657,8 @@ if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 lt_cv_cc_needs_belf=yes else echo "$as_me: failed program was:" >&5 -cat conftest.$ac_ext >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + lt_cv_cc_needs_belf=no fi rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext @@ -4455,7 +4830,7 @@ else # like `-m68040'. lt_cv_prog_cc_pic='-m68020 -resident32 -malways-restore-a4' ;; - beos* | irix5* | irix6* | osf3* | osf4* | osf5*) + beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) # PIC is the default for these OSes. ;; darwin* | rhapsody*) @@ -4498,7 +4873,7 @@ else lt_cv_prog_cc_pic='+Z' ;; - irix5* | irix6*) + irix5* | irix6* | nonstopux*) lt_cv_prog_cc_wl='-Wl,' lt_cv_prog_cc_static='-non_shared' # PIC (with -KPIC) is the default. @@ -4542,11 +4917,7 @@ else sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) lt_cv_prog_cc_pic='-KPIC' lt_cv_prog_cc_static='-Bstatic' - if test "x$host_vendor" = xsni; then - lt_cv_prog_cc_wl='-LD' - else - lt_cv_prog_cc_wl='-Wl,' - fi + lt_cv_prog_cc_wl='-Wl,' ;; uts4*) @@ -4586,14 +4957,12 @@ else CFLAGS="$CFLAGS $lt_cv_prog_cc_pic -DPIC" cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" -#include "confdefs.h" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ -#ifdef F77_DUMMY_MAIN -# ifdef __cplusplus - extern "C" -# endif - int F77_DUMMY_MAIN() { return 1; } -#endif int main () { @@ -4632,7 +5001,8 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 else echo "$as_me: failed program was:" >&5 -cat conftest.$ac_ext >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + lt_cv_prog_cc_pic_works=no fi @@ -4675,14 +5045,12 @@ else LDFLAGS="$LDFLAGS $lt_cv_prog_cc_static" cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" -#include "confdefs.h" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ -#ifdef F77_DUMMY_MAIN -# ifdef __cplusplus - extern "C" -# endif - int F77_DUMMY_MAIN() { return 1; } -#endif int main () { @@ -4706,7 +5074,8 @@ if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 lt_cv_prog_cc_static_works=yes else echo "$as_me: failed program was:" >&5 -cat conftest.$ac_ext >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + fi rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext LDFLAGS="$save_LDFLAGS" @@ -4748,7 +5117,7 @@ chmod -w . save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -o out/conftest2.$ac_objext" compiler_c_o=no -if { (eval echo configure:4751: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>out/conftest.err; } && test -s out/conftest2.$ac_objext; then +if { (eval echo configure:5120: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>out/conftest.err; } && test -s out/conftest2.$ac_objext; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings if test -s out/conftest.err; then @@ -4790,14 +5159,12 @@ else ac_objext=lo cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" -#include "confdefs.h" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ -#ifdef F77_DUMMY_MAIN -# ifdef __cplusplus - extern "C" -# endif - int F77_DUMMY_MAIN() { return 1; } -#endif int main () { @@ -4828,7 +5195,8 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 else echo "$as_me: failed program was:" >&5 -cat conftest.$ac_ext >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + fi rm -f conftest.$ac_objext conftest.$ac_ext ac_objext="$save_objext" @@ -4876,14 +5244,12 @@ echo $ECHO_N "checking if $compiler supports -fno-rtti -fno-exceptions... $ECHO_ compiler_rtti_exceptions=no cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" -#include "confdefs.h" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ -#ifdef F77_DUMMY_MAIN -# ifdef __cplusplus - extern "C" -# endif - int F77_DUMMY_MAIN() { return 1; } -#endif int main () { @@ -4914,7 +5280,8 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 else echo "$as_me: failed program was:" >&5 -cat conftest.$ac_ext >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + fi rm -f conftest.$ac_objext conftest.$ac_ext CFLAGS="$save_CFLAGS" @@ -5086,7 +5453,7 @@ EOF # If the export-symbols file already is a .def file (1st line # is EXPORTS), use it as is. # If DATA tags from a recent dlltool are present, honour them! - archive_expsym_cmds='if test "x`head -1 $export_symbols`" = xEXPORTS; then + archive_expsym_cmds='if test "x`sed 1q $export_symbols`" = xEXPORTS; then cp $export_symbols $output_objdir/$soname-def; else echo EXPORTS > $output_objdir/$soname-def; @@ -5095,6 +5462,7 @@ EOF set dummy \$symbol; case \$# in 2) echo " \$2 @ \$_lt_hint ; " >> $output_objdir/$soname-def;; + 4) echo " \$2 \$3 \$4 ; " >> $output_objdir/$soname-def; _lt_hint=`expr \$_lt_hint - 1`;; *) echo " \$2 @ \$_lt_hint \$3 ; " >> $output_objdir/$soname-def;; esac; _lt_hint=`expr 1 + \$_lt_hint`; @@ -5207,10 +5575,12 @@ else # need to do runtime linking. case $host_os in aix4.[23]|aix4.[23].*|aix5*) for ld_flag in $LDFLAGS; do - if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then + case $ld_flag in + *-brtl*) aix_use_runtimelinking=yes break - fi + ;; + esac done esac @@ -5324,8 +5694,9 @@ else esac # FIXME: Relying on posixy $() will cause problems for # cross-compilation, but unfortunately the echo tests do not - # yet detect zsh echo's removal of \ escapes. - archive_cmds='$nonopt $(test "x$module" = xyes && echo -bundle || echo -dynamiclib) $allow_undefined_flag -o $lib $libobjs $deplibs$linker_flags -install_name $rpath/$soname $verstring' + # yet detect zsh echo's removal of \ escapes. Also zsh mangles + # `"' quotes if we put them in here... so don't! + archive_cmds='$CC -r -keep_private_externs -nostdlib -o ${lib}-master.o $libobjs && $CC $(test .$module = .yes && echo -bundle || echo -dynamiclib) $allow_undefined_flag -o $lib ${lib}-master.o $deplibs$linker_flags $(test .$module != .yes && echo -install_name $rpath/$soname $verstring)' # We need to add '_' to the symbols in $export_symbols first #archive_expsym_cmds="$archive_cmds"' && strip -s $export_symbols' hardcode_direct=yes @@ -5377,13 +5748,14 @@ else export_dynamic_flag_spec='${wl}-E' ;; - irix5* | irix6*) + irix5* | irix6* | nonstopux*) if test "$GCC" = yes; then archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && echo ${wl}-set_version ${wl}$verstring` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' else archive_cmds='$LD -shared $libobjs $deplibs $linker_flags -soname $soname `test -n "$verstring" && echo -set_version $verstring` -update_registry ${output_objdir}/so_locations -o $lib' + hardcode_libdir_flag_spec='-rpath $libdir' fi - hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator=: link_all_deplibs=yes ;; @@ -5411,7 +5783,7 @@ else hardcode_direct=yes hardcode_shlibpath_var=no if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then - archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $linker_flags' + archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' hardcode_libdir_flag_spec='${wl}-rpath,$libdir' export_dynamic_flag_spec='${wl}-E' else @@ -5421,7 +5793,7 @@ else hardcode_libdir_flag_spec='-R$libdir' ;; *) - archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $linker_flags' + archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' hardcode_libdir_flag_spec='${wl}-rpath,$libdir' ;; esac @@ -5533,13 +5905,23 @@ EOF ;; sysv4) - if test "x$host_vendor" = xsno; then - archive_cmds='$LD -G -Bsymbolic -h $soname -o $lib $libobjs $deplibs $linker_flags' - hardcode_direct=yes # is this really true??? - else - archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' - hardcode_direct=no #Motorola manual says yes, but my tests say they lie - fi + case $host_vendor in + sni) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=yes # is this really true??? + ;; + siemens) + ## LD is ld it makes a PLAMLIB + ## CC just makes a GrossModule. + archive_cmds='$LD -G -o $lib $libobjs $deplibs $linker_flags' + reload_cmds='$CC -r -o $output$reload_objs' + hardcode_direct=no + ;; + motorola) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=no #Motorola manual says yes, but my tests say they lie + ;; + esac runpath_var='LD_RUN_PATH' hardcode_shlibpath_var=no ;; @@ -5687,6 +6069,9 @@ aix3*) aix4* | aix5*) version_type=linux + need_lib_prefix=no + need_version=no + hardcode_into_libs=yes if test "$host_cpu" = ia64; then # AIX 5 supports IA64 library_names_spec='${libname}${release}.so$major ${libname}${release}.so$versuffix $libname.so' @@ -5725,6 +6110,7 @@ aix4* | aix5*) fi shlibpath_var=LIBPATH fi + hardcode_into_libs=yes ;; amigaos*) @@ -5772,7 +6158,7 @@ cygwin* | mingw* | pw32*) ;; yes,mingw*) library_names_spec='${libname}`echo ${release} | sed -e 's/[.]/-/g'`${versuffix}.dll' - sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | sed -e "s/^libraries://" -e "s/;/ /g"` + sys_lib_search_path_spec=`$CC -print-search-dirs | grep "^libraries:" | sed -e "s/^libraries://" -e "s/;/ /g" -e "s,=/,/,g"` ;; yes,pw32*) library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | sed -e 's/./-/g'`${versuffix}.dll' @@ -5855,14 +6241,17 @@ hpux9* | hpux10* | hpux11*) postinstall_cmds='chmod 555 $lib' ;; -irix5* | irix6*) - version_type=irix +irix5* | irix6* | nonstopux*) + case $host_os in + nonstopux*) version_type=nonstopux ;; + *) version_type=irix ;; + esac need_lib_prefix=no need_version=no soname_spec='${libname}${release}.so$major' library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major ${libname}${release}.so $libname.so' case $host_os in - irix5*) + irix5* | nonstopux*) libsuff= shlibsuff= ;; *) @@ -5907,6 +6296,30 @@ linux-gnu*) # people can always --disable-shared, the test was removed, and we # assume the GNU/Linux dynamic linker is in use. dynamic_linker='GNU/Linux ld.so' + + # Find out which ABI we are using (multilib Linux x86_64 hack). + libsuff= + case "$host_cpu" in + x86_64*|s390x*) + echo '#line 6304 "configure"' > conftest.$ac_ext + if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + case `/usr/bin/file conftest.$ac_objext` in + *64-bit*) + libsuff=64 + ;; + esac + fi + rm -rf conftest* + ;; + *) + ;; + esac + sys_lib_dlsearch_path_spec="/lib${libsuff} /usr/lib${libsuff}" + sys_lib_search_path_spec="/lib${libsuff} /usr/lib${libsuff} /usr/local/lib${libsuff}" ;; netbsd*) @@ -5966,11 +6379,12 @@ os2*) osf3* | osf4* | osf5*) version_type=osf need_version=no - soname_spec='${libname}${release}.so' - library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so $libname.so' + soname_spec='${libname}${release}.so$major' + library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" + hardcode_into_libs=yes ;; sco3.2v5*) @@ -6013,6 +6427,12 @@ sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) case $host_vendor in sni) shlibpath_overrides_runpath=no + need_lib_prefix=no + export_dynamic_flag_spec='${wl}-Blargedynsym' + runpath_var=LD_RUN_PATH + ;; + siemens) + need_lib_prefix=no ;; motorola) need_lib_prefix=no @@ -6135,37 +6555,44 @@ if test "${ac_cv_func_shl_load+set}" = set; then else cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" -#include "confdefs.h" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ /* System header to define __stub macros and hopefully few prototypes, - which can conflict with char shl_load (); below. */ -#include <assert.h> + which can conflict with char shl_load (); below. + Prefer <limits.h> to <assert.h> if __STDC__ is defined, since + <limits.h> exists even on freestanding compilers. */ +#ifdef __STDC__ +# include <limits.h> +#else +# include <assert.h> +#endif /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus extern "C" +{ #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char shl_load (); -char (*f) (); - -#ifdef F77_DUMMY_MAIN -# ifdef __cplusplus - extern "C" -# endif - int F77_DUMMY_MAIN() { return 1; } -#endif -int -main () -{ /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined (__stub_shl_load) || defined (__stub___shl_load) choke me #else -f = shl_load; +char (*f) () = shl_load; +#endif +#ifdef __cplusplus +} #endif +int +main () +{ +return f != shl_load; ; return 0; } @@ -6185,7 +6612,8 @@ if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 ac_cv_func_shl_load=yes else echo "$as_me: failed program was:" >&5 -cat conftest.$ac_ext >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + ac_cv_func_shl_load=no fi rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext @@ -6204,7 +6632,11 @@ else LIBS="-ldld $LIBS" cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" -#include "confdefs.h" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus @@ -6213,12 +6645,6 @@ extern "C" /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char shl_load (); -#ifdef F77_DUMMY_MAIN -# ifdef __cplusplus - extern "C" -# endif - int F77_DUMMY_MAIN() { return 1; } -#endif int main () { @@ -6242,7 +6668,8 @@ if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 ac_cv_lib_dld_shl_load=yes else echo "$as_me: failed program was:" >&5 -cat conftest.$ac_ext >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + ac_cv_lib_dld_shl_load=no fi rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext @@ -6260,37 +6687,44 @@ if test "${ac_cv_func_dlopen+set}" = set; then else cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" -#include "confdefs.h" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ /* System header to define __stub macros and hopefully few prototypes, - which can conflict with char dlopen (); below. */ -#include <assert.h> + which can conflict with char dlopen (); below. + Prefer <limits.h> to <assert.h> if __STDC__ is defined, since + <limits.h> exists even on freestanding compilers. */ +#ifdef __STDC__ +# include <limits.h> +#else +# include <assert.h> +#endif /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus extern "C" +{ #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char dlopen (); -char (*f) (); - -#ifdef F77_DUMMY_MAIN -# ifdef __cplusplus - extern "C" -# endif - int F77_DUMMY_MAIN() { return 1; } -#endif -int -main () -{ /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined (__stub_dlopen) || defined (__stub___dlopen) choke me #else -f = dlopen; +char (*f) () = dlopen; +#endif +#ifdef __cplusplus +} #endif +int +main () +{ +return f != dlopen; ; return 0; } @@ -6310,7 +6744,8 @@ if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 ac_cv_func_dlopen=yes else echo "$as_me: failed program was:" >&5 -cat conftest.$ac_ext >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + ac_cv_func_dlopen=no fi rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext @@ -6329,7 +6764,11 @@ else LIBS="-ldl $LIBS" cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" -#include "confdefs.h" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus @@ -6338,12 +6777,6 @@ extern "C" /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char dlopen (); -#ifdef F77_DUMMY_MAIN -# ifdef __cplusplus - extern "C" -# endif - int F77_DUMMY_MAIN() { return 1; } -#endif int main () { @@ -6367,7 +6800,8 @@ if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 ac_cv_lib_dl_dlopen=yes else echo "$as_me: failed program was:" >&5 -cat conftest.$ac_ext >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + ac_cv_lib_dl_dlopen=no fi rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext @@ -6387,7 +6821,11 @@ else LIBS="-lsvld $LIBS" cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" -#include "confdefs.h" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus @@ -6396,12 +6834,6 @@ extern "C" /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char dlopen (); -#ifdef F77_DUMMY_MAIN -# ifdef __cplusplus - extern "C" -# endif - int F77_DUMMY_MAIN() { return 1; } -#endif int main () { @@ -6425,7 +6857,8 @@ if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 ac_cv_lib_svld_dlopen=yes else echo "$as_me: failed program was:" >&5 -cat conftest.$ac_ext >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + ac_cv_lib_svld_dlopen=no fi rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext @@ -6445,7 +6878,11 @@ else LIBS="-ldld $LIBS" cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" -#include "confdefs.h" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus @@ -6454,12 +6891,6 @@ extern "C" /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char dld_link (); -#ifdef F77_DUMMY_MAIN -# ifdef __cplusplus - extern "C" -# endif - int F77_DUMMY_MAIN() { return 1; } -#endif int main () { @@ -6483,7 +6914,8 @@ if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 ac_cv_lib_dld_dld_link=yes else echo "$as_me: failed program was:" >&5 -cat conftest.$ac_ext >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + ac_cv_lib_dld_dld_link=no fi rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext @@ -6541,7 +6973,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<EOF -#line 6544 "configure" +#line 6976 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -6639,7 +7071,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<EOF -#line 6642 "configure" +#line 7074 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -6822,7 +7254,7 @@ if test -f "$ltmain"; then # Now quote all the things that may contain metacharacters while being # careful not to overquote the AC_SUBSTed values. We take copies of the # variables and quote the copies for generation of the libtool script. - for var in echo old_CC old_CFLAGS \ + for var in echo old_CC old_CFLAGS SED \ AR AR_FLAGS CC LD LN_S NM SHELL \ reload_flag reload_cmds wl \ pic_flag link_static_flag no_builtin_flag export_dynamic_flag_spec \ @@ -6884,8 +7316,11 @@ if test -f "$ltmain"; then # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. +# A sed that does not truncate output. +SED=$lt_SED + # Sed that helps us avoid accidentally triggering echo(1) options like -n. -Xsed="sed -e s/^X//" +Xsed="${SED} -e s/^X//" # The HP-UX ksh and POSIX shell print the target directory to stdout # if CDPATH is set. @@ -7389,48 +7824,59 @@ if test "${ac_cv_header_stdc+set}" = set; then else cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" -#include "confdefs.h" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ #include <stdlib.h> #include <stdarg.h> #include <string.h> #include <float.h> +int +main () +{ + + ; + return 0; +} _ACEOF -if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 - (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 ac_status=$? - egrep -v '^ *\+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } >/dev/null; then - if test -s conftest.err; then - ac_cpp_err=$ac_c_preproc_warn_flag - else - ac_cpp_err= - fi -else - ac_cpp_err=yes -fi -if test -z "$ac_cpp_err"; then + (exit $ac_status); } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then ac_cv_header_stdc=yes else echo "$as_me: failed program was:" >&5 - cat conftest.$ac_ext >&5 - ac_cv_header_stdc=no +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_header_stdc=no fi -rm -f conftest.err conftest.$ac_ext +rm -f conftest.$ac_objext conftest.$ac_ext if test $ac_cv_header_stdc = yes; then # SunOS 4.x string.h does not declare mem*, contrary to ANSI. cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" -#include "confdefs.h" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ #include <string.h> _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - egrep "memchr" >/dev/null 2>&1; then + $EGREP "memchr" >/dev/null 2>&1; then : else ac_cv_header_stdc=no @@ -7443,12 +7889,16 @@ if test $ac_cv_header_stdc = yes; then # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" -#include "confdefs.h" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ #include <stdlib.h> _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - egrep "free" >/dev/null 2>&1; then + $EGREP "free" >/dev/null 2>&1; then : else ac_cv_header_stdc=no @@ -7464,13 +7914,18 @@ if test $ac_cv_header_stdc = yes; then else cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" -#include "confdefs.h" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ #include <ctype.h> #if ((' ' & 0x0FF) == 0x020) # define ISLOWER(c) ('a' <= (c) && (c) <= 'z') # define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) #else -# define ISLOWER(c) (('a' <= (c) && (c) <= 'i') \ +# define ISLOWER(c) \ + (('a' <= (c) && (c) <= 'i') \ || ('j' <= (c) && (c) <= 'r') \ || ('s' <= (c) && (c) <= 'z')) # define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) @@ -7503,11 +7958,12 @@ if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 else echo "$as_me: program exited with status $ac_status" >&5 echo "$as_me: failed program was:" >&5 -cat conftest.$ac_ext >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + ( exit $ac_status ) ac_cv_header_stdc=no fi -rm -f core core.* *.core conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +rm -f core core.* *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext fi fi fi @@ -7528,7 +7984,11 @@ if test "${ac_cv_header_sys_wait_h+set}" = set; then else cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" -#include "confdefs.h" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ #include <sys/types.h> #include <sys/wait.h> #ifndef WEXITSTATUS @@ -7538,12 +7998,6 @@ else # define WIFEXITED(stat_val) (((stat_val) & 255) == 0) #endif -#ifdef F77_DUMMY_MAIN -# ifdef __cplusplus - extern "C" -# endif - int F77_DUMMY_MAIN() { return 1; } -#endif int main () { @@ -7569,7 +8023,8 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 ac_cv_header_sys_wait_h=yes else echo "$as_me: failed program was:" >&5 -cat conftest.$ac_ext >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + ac_cv_header_sys_wait_h=no fi rm -f conftest.$ac_objext conftest.$ac_ext @@ -7613,7 +8068,11 @@ echo "$as_me:$LINENO: checking $ac_header usability" >&5 echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6 cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" -#include "confdefs.h" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ $ac_includes_default #include <$ac_header> _ACEOF @@ -7632,7 +8091,8 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 ac_header_compiler=yes else echo "$as_me: failed program was:" >&5 -cat conftest.$ac_ext >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + ac_header_compiler=no fi rm -f conftest.$ac_objext conftest.$ac_ext @@ -7644,13 +8104,17 @@ echo "$as_me:$LINENO: checking $ac_header presence" >&5 echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6 cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" -#include "confdefs.h" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ #include <$ac_header> _ACEOF if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 ac_status=$? - egrep -v '^ *\+' conftest.er1 >conftest.err + grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 @@ -7667,7 +8131,8 @@ if test -z "$ac_cpp_err"; then ac_header_preproc=yes else echo "$as_me: failed program was:" >&5 - cat conftest.$ac_ext >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + ac_header_preproc=no fi rm -f conftest.err conftest.$ac_ext @@ -7680,14 +8145,32 @@ case $ac_header_compiler:$ac_header_preproc in { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 -echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;};; +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + ( + cat <<\_ASBOX +## ------------------------------------ ## +## Report this to bug-autoconf@gnu.org. ## +## ------------------------------------ ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 + ;; no:yes ) { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 -echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;};; +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + ( + cat <<\_ASBOX +## ------------------------------------ ## +## Report this to bug-autoconf@gnu.org. ## +## ------------------------------------ ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 + ;; esac echo "$as_me:$LINENO: checking for $ac_header" >&5 echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 @@ -7711,103 +8194,6 @@ done # Checks for typedefs, structures, and compiler characteristics. -echo "$as_me:$LINENO: checking for $CC option to accept ANSI C" >&5 -echo $ECHO_N "checking for $CC option to accept ANSI C... $ECHO_C" >&6 -if test "${ac_cv_prog_cc_stdc+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - ac_cv_prog_cc_stdc=no -ac_save_CC=$CC -cat >conftest.$ac_ext <<_ACEOF -#line $LINENO "configure" -#include "confdefs.h" -#include <stdarg.h> -#include <stdio.h> -#include <sys/types.h> -#include <sys/stat.h> -/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ -struct buf { int x; }; -FILE * (*rcsopen) (struct buf *, struct stat *, int); -static char *e (p, i) - char **p; - int i; -{ - return p[i]; -} -static char *f (char * (*g) (char **, int), char **p, ...) -{ - char *s; - va_list v; - va_start (v,p); - s = g (p, va_arg (v,int)); - va_end (v); - return s; -} -int test (int i, double x); -struct s1 {int (*f) (int a);}; -struct s2 {int (*f) (double a);}; -int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); -int argc; -char **argv; -#ifdef F77_DUMMY_MAIN -# ifdef __cplusplus - extern "C" -# endif - int F77_DUMMY_MAIN() { return 1; } -#endif -int -main () -{ -return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; - ; - return 0; -} -_ACEOF -# Don't try gcc -ansi; that turns off useful extensions and -# breaks some systems' header files. -# AIX -qlanglvl=ansi -# Ultrix and OSF/1 -std1 -# HP-UX 10.20 and later -Ae -# HP-UX older versions -Aa -D_HPUX_SOURCE -# SVR4 -Xc -D__EXTENSIONS__ -for ac_arg in "" -qlanglvl=ansi -std1 -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" -do - CC="$ac_save_CC $ac_arg" - rm -f conftest.$ac_objext -if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 - (eval $ac_compile) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -s conftest.$ac_objext' - { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 - (eval $ac_try) 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ac_cv_prog_cc_stdc=$ac_arg -break -else - echo "$as_me: failed program was:" >&5 -cat conftest.$ac_ext >&5 -fi -rm -f conftest.$ac_objext -done -rm -f conftest.$ac_ext conftest.$ac_objext -CC=$ac_save_CC - -fi - -case "x$ac_cv_prog_cc_stdc" in - x|xno) - echo "$as_me:$LINENO: result: none needed" >&5 -echo "${ECHO_T}none needed" >&6 ;; - *) - echo "$as_me:$LINENO: result: $ac_cv_prog_cc_stdc" >&5 -echo "${ECHO_T}$ac_cv_prog_cc_stdc" >&6 - CC="$CC $ac_cv_prog_cc_stdc" ;; -esac - echo "$as_me:$LINENO: checking for an ANSI C-conforming const" >&5 echo $ECHO_N "checking for an ANSI C-conforming const... $ECHO_C" >&6 if test "${ac_cv_c_const+set}" = set; then @@ -7815,14 +8201,12 @@ if test "${ac_cv_c_const+set}" = set; then else cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" -#include "confdefs.h" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ -#ifdef F77_DUMMY_MAIN -# ifdef __cplusplus - extern "C" -# endif - int F77_DUMMY_MAIN() { return 1; } -#endif int main () { @@ -7892,7 +8276,8 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 ac_cv_c_const=yes else echo "$as_me: failed program was:" >&5 -cat conftest.$ac_ext >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + ac_cv_c_const=no fi rm -f conftest.$ac_objext conftest.$ac_ext @@ -7914,14 +8299,12 @@ if test "${ac_cv_type_mode_t+set}" = set; then else cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" -#include "confdefs.h" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ $ac_includes_default -#ifdef F77_DUMMY_MAIN -# ifdef __cplusplus - extern "C" -# endif - int F77_DUMMY_MAIN() { return 1; } -#endif int main () { @@ -7948,7 +8331,8 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 ac_cv_type_mode_t=yes else echo "$as_me: failed program was:" >&5 -cat conftest.$ac_ext >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + ac_cv_type_mode_t=no fi rm -f conftest.$ac_objext conftest.$ac_ext @@ -7972,14 +8356,12 @@ if test "${ac_cv_type_size_t+set}" = set; then else cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" -#include "confdefs.h" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ $ac_includes_default -#ifdef F77_DUMMY_MAIN -# ifdef __cplusplus - extern "C" -# endif - int F77_DUMMY_MAIN() { return 1; } -#endif int main () { @@ -8006,7 +8388,8 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 ac_cv_type_size_t=yes else echo "$as_me: failed program was:" >&5 -cat conftest.$ac_ext >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + ac_cv_type_size_t=no fi rm -f conftest.$ac_objext conftest.$ac_ext @@ -8030,17 +8413,15 @@ if test "${ac_cv_header_time+set}" = set; then else cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" -#include "confdefs.h" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ #include <sys/types.h> #include <sys/time.h> #include <time.h> -#ifdef F77_DUMMY_MAIN -# ifdef __cplusplus - extern "C" -# endif - int F77_DUMMY_MAIN() { return 1; } -#endif int main () { @@ -8065,7 +8446,8 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 ac_cv_header_time=yes else echo "$as_me: failed program was:" >&5 -cat conftest.$ac_ext >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + ac_cv_header_time=no fi rm -f conftest.$ac_objext conftest.$ac_ext @@ -8091,12 +8473,16 @@ else ac_pattern="Autoconf.*'x'" cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" -#include "confdefs.h" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ #include <sgtty.h> Autoconf TIOCGETP _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - egrep "$ac_pattern" >/dev/null 2>&1; then + $EGREP "$ac_pattern" >/dev/null 2>&1; then ac_cv_prog_gcc_traditional=yes else ac_cv_prog_gcc_traditional=no @@ -8107,12 +8493,16 @@ rm -f conftest* if test $ac_cv_prog_gcc_traditional = no; then cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" -#include "confdefs.h" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ #include <termio.h> Autoconf TCGETA _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - egrep "$ac_pattern" >/dev/null 2>&1; then + $EGREP "$ac_pattern" >/dev/null 2>&1; then ac_cv_prog_gcc_traditional=yes fi rm -f conftest* @@ -8144,7 +8534,11 @@ echo "$as_me:$LINENO: checking $ac_header usability" >&5 echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6 cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" -#include "confdefs.h" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ $ac_includes_default #include <$ac_header> _ACEOF @@ -8163,7 +8557,8 @@ if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 ac_header_compiler=yes else echo "$as_me: failed program was:" >&5 -cat conftest.$ac_ext >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + ac_header_compiler=no fi rm -f conftest.$ac_objext conftest.$ac_ext @@ -8175,13 +8570,17 @@ echo "$as_me:$LINENO: checking $ac_header presence" >&5 echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6 cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" -#include "confdefs.h" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ #include <$ac_header> _ACEOF if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 ac_status=$? - egrep -v '^ *\+' conftest.er1 >conftest.err + grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 @@ -8198,7 +8597,8 @@ if test -z "$ac_cpp_err"; then ac_header_preproc=yes else echo "$as_me: failed program was:" >&5 - cat conftest.$ac_ext >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + ac_header_preproc=no fi rm -f conftest.err conftest.$ac_ext @@ -8211,14 +8611,32 @@ case $ac_header_compiler:$ac_header_preproc in { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 -echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;};; +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + ( + cat <<\_ASBOX +## ------------------------------------ ## +## Report this to bug-autoconf@gnu.org. ## +## ------------------------------------ ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 + ;; no:yes ) { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 -echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;};; +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + ( + cat <<\_ASBOX +## ------------------------------------ ## +## Report this to bug-autoconf@gnu.org. ## +## ------------------------------------ ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 + ;; esac echo "$as_me:$LINENO: checking for $ac_header" >&5 echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 @@ -8240,29 +8658,27 @@ fi done -echo "$as_me:$LINENO: checking for working malloc" >&5 -echo $ECHO_N "checking for working malloc... $ECHO_C" >&6 -if test "${ac_cv_func_malloc_works+set}" = set; then +echo "$as_me:$LINENO: checking for GNU libc compatible malloc" >&5 +echo $ECHO_N "checking for GNU libc compatible malloc... $ECHO_C" >&6 +if test "${ac_cv_func_malloc_0_nonnull+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test "$cross_compiling" = yes; then - ac_cv_func_malloc_works=no + ac_cv_func_malloc_0_nonnull=no else cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" -#include "confdefs.h" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ #if STDC_HEADERS || HAVE_STDLIB_H # include <stdlib.h> #else char *malloc (); #endif -#ifdef F77_DUMMY_MAIN -# ifdef __cplusplus - extern "C" -# endif - int F77_DUMMY_MAIN() { return 1; } -#endif int main () { @@ -8282,27 +8698,41 @@ if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then - ac_cv_func_malloc_works=yes + ac_cv_func_malloc_0_nonnull=yes else echo "$as_me: program exited with status $ac_status" >&5 echo "$as_me: failed program was:" >&5 -cat conftest.$ac_ext >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + ( exit $ac_status ) -ac_cv_func_malloc_works=no +ac_cv_func_malloc_0_nonnull=no fi -rm -f core core.* *.core conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +rm -f core core.* *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext fi fi -echo "$as_me:$LINENO: result: $ac_cv_func_malloc_works" >&5 -echo "${ECHO_T}$ac_cv_func_malloc_works" >&6 -if test $ac_cv_func_malloc_works = yes; then +echo "$as_me:$LINENO: result: $ac_cv_func_malloc_0_nonnull" >&5 +echo "${ECHO_T}$ac_cv_func_malloc_0_nonnull" >&6 +if test $ac_cv_func_malloc_0_nonnull = yes; then cat >>confdefs.h <<\_ACEOF #define HAVE_MALLOC 1 _ACEOF +else + cat >>confdefs.h <<\_ACEOF +#define HAVE_MALLOC 0 +_ACEOF + + LIBOBJS="$LIBOBJS malloc.$ac_objext" + +cat >>confdefs.h <<\_ACEOF +#define malloc rpl_malloc +_ACEOF + fi + + echo "$as_me:$LINENO: checking for working memcmp" >&5 echo $ECHO_N "checking for working memcmp... $ECHO_C" >&6 if test "${ac_cv_func_memcmp_working+set}" = set; then @@ -8313,14 +8743,12 @@ else else cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" -#include "confdefs.h" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ -#ifdef F77_DUMMY_MAIN -# ifdef __cplusplus - extern "C" -# endif - int F77_DUMMY_MAIN() { return 1; } -#endif int main () { @@ -8368,11 +8796,12 @@ if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 else echo "$as_me: program exited with status $ac_status" >&5 echo "$as_me: failed program was:" >&5 -cat conftest.$ac_ext >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + ( exit $ac_status ) ac_cv_func_memcmp_working=no fi -rm -f core core.* *.core conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +rm -f core core.* *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext fi fi echo "$as_me:$LINENO: result: $ac_cv_func_memcmp_working" >&5 @@ -8397,37 +8826,44 @@ if eval "test \"\${$as_ac_var+set}\" = set"; then else cat >conftest.$ac_ext <<_ACEOF #line $LINENO "configure" -#include "confdefs.h" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ /* System header to define __stub macros and hopefully few prototypes, - which can conflict with char $ac_func (); below. */ -#include <assert.h> + which can conflict with char $ac_func (); below. + Prefer <limits.h> to <assert.h> if __STDC__ is defined, since + <limits.h> exists even on freestanding compilers. */ +#ifdef __STDC__ +# include <limits.h> +#else +# include <assert.h> +#endif /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus extern "C" +{ #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char $ac_func (); -char (*f) (); - -#ifdef F77_DUMMY_MAIN -# ifdef __cplusplus - extern "C" -# endif - int F77_DUMMY_MAIN() { return 1; } -#endif -int -main () -{ /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined (__stub_$ac_func) || defined (__stub___$ac_func) choke me #else -f = $ac_func; +char (*f) () = $ac_func; +#endif +#ifdef __cplusplus +} #endif +int +main () +{ +return f != $ac_func; ; return 0; } @@ -8447,7 +8883,8 @@ if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 eval "$as_ac_var=yes" else echo "$as_me: failed program was:" >&5 -cat conftest.$ac_ext >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + eval "$as_ac_var=no" fi rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext @@ -8536,15 +8973,15 @@ else echo "$as_me: WARNING: \`missing' script is too old or missing" >&2;} fi -echo "$as_me:$LINENO: checking whether ${MAKE-make} sets \${MAKE}" >&5 -echo $ECHO_N "checking whether ${MAKE-make} sets \${MAKE}... $ECHO_C" >&6 +echo "$as_me:$LINENO: checking whether ${MAKE-make} sets \$(MAKE)" >&5 +echo $ECHO_N "checking whether ${MAKE-make} sets \$(MAKE)... $ECHO_C" >&6 set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y,./+-,__p_,'` if eval "test \"\${ac_cv_prog_make_${ac_make}_set+set}\" = set"; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.make <<\_ACEOF all: - @echo 'ac_maketemp="${MAKE}"' + @echo 'ac_maketemp="$(MAKE)"' _ACEOF # GNU make sometimes prints "make[1]: Entering...", which would confuse us. eval `${MAKE-make} -f conftest.make 2>/dev/null | grep temp=` @@ -8576,7 +9013,7 @@ fi rmdir .deps 2>/dev/null -ac_config_commands="$ac_config_commands depfiles" + ac_config_commands="$ac_config_commands depfiles" am_make=${MAKE-make} @@ -8913,7 +9350,7 @@ CXXDEPMODE=depmode=$am_cv_CXX_dependencies_compiler_type -ac_config_files="$ac_config_files Makefile doc/Makefile ggsn/Makefile gtp/Makefile intl/Makefile po/Makefile sgsnemu/Makefile src/Makefile tests/Makefile openggsn.spec" + ac_config_files="$ac_config_files Makefile doc/Makefile ggsn/Makefile gtp/Makefile intl/Makefile po/Makefile sgsnemu/Makefile src/Makefile tests/Makefile openggsn.spec" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure @@ -8925,7 +9362,7 @@ cat >confcache <<\_ACEOF # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # -# `ac_cv_env_foo' variables (set or unset) will be overriden when +# `ac_cv_env_foo' variables (set or unset) will be overridden when # loading this file, other *unset* `ac_cv_foo' will be assigned the # following values. @@ -8960,7 +9397,7 @@ _ACEOF t end /^ac_cv_env/!s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ : end' >>confcache -if cmp -s $cache_file confcache; then :; else +if diff $cache_file confcache >/dev/null 2>&1; then :; else if test -w $cache_file; then test "x$cache_file" != "x/dev/null" && echo "updating cache $cache_file" cat confcache >$cache_file @@ -8991,6 +9428,21 @@ fi DEFS=-DHAVE_CONFIG_H +ac_libobjs= +ac_ltlibobjs= +for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue + # 1. Remove the extension, and $U if already installed. + ac_i=`echo "$ac_i" | + sed 's/\$U\././;s/\.o$//;s/\.obj$//'` + # 2. Add them. + ac_libobjs="$ac_libobjs $ac_i\$U.$ac_objext" + ac_ltlibobjs="$ac_ltlibobjs $ac_i"'$U.lo' +done +LIBOBJS=$ac_libobjs + +LTLIBOBJS=$ac_ltlibobjs + + if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then { { echo "$as_me:$LINENO: error: conditional \"AMDEP\" was never defined. Usually this means the macro was only invoked conditionally." >&5 @@ -9012,11 +9464,12 @@ cat >$CONFIG_STATUS <<_ACEOF # configure, is in config.log if it exists. debug=false +ac_cs_recheck=false +ac_cs_silent=false SHELL=\${CONFIG_SHELL-$SHELL} _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF - ## --------------------- ## ## M4sh Initialization. ## ## --------------------- ## @@ -9025,11 +9478,13 @@ cat >>$CONFIG_STATUS <<\_ACEOF if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then emulate sh NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then set -o posix fi -# NLS nuisances. # Support unset when possible. if (FOO=FOO; unset FOO) >/dev/null 2>&1; then as_unset=unset @@ -9037,34 +9492,42 @@ else as_unset=false fi -(set +x; test -n "`(LANG=C; export LANG) 2>&1`") && - { $as_unset LANG || test "${LANG+set}" != set; } || - { LANG=C; export LANG; } -(set +x; test -n "`(LC_ALL=C; export LC_ALL) 2>&1`") && - { $as_unset LC_ALL || test "${LC_ALL+set}" != set; } || - { LC_ALL=C; export LC_ALL; } -(set +x; test -n "`(LC_TIME=C; export LC_TIME) 2>&1`") && - { $as_unset LC_TIME || test "${LC_TIME+set}" != set; } || - { LC_TIME=C; export LC_TIME; } -(set +x; test -n "`(LC_CTYPE=C; export LC_CTYPE) 2>&1`") && - { $as_unset LC_CTYPE || test "${LC_CTYPE+set}" != set; } || - { LC_CTYPE=C; export LC_CTYPE; } -(set +x; test -n "`(LANGUAGE=C; export LANGUAGE) 2>&1`") && - { $as_unset LANGUAGE || test "${LANGUAGE+set}" != set; } || - { LANGUAGE=C; export LANGUAGE; } -(set +x; test -n "`(LC_COLLATE=C; export LC_COLLATE) 2>&1`") && - { $as_unset LC_COLLATE || test "${LC_COLLATE+set}" != set; } || - { LC_COLLATE=C; export LC_COLLATE; } -(set +x; test -n "`(LC_NUMERIC=C; export LC_NUMERIC) 2>&1`") && - { $as_unset LC_NUMERIC || test "${LC_NUMERIC+set}" != set; } || - { LC_NUMERIC=C; export LC_NUMERIC; } -(set +x; test -n "`(LC_MESSAGES=C; export LC_MESSAGES) 2>&1`") && - { $as_unset LC_MESSAGES || test "${LC_MESSAGES+set}" != set; } || - { LC_MESSAGES=C; export LC_MESSAGES; } + +# Work around bugs in pre-3.0 UWIN ksh. +$as_unset ENV MAIL MAILPATH +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +for as_var in \ + LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ + LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ + LC_TELEPHONE LC_TIME +do + if (set +x; test -n "`(eval $as_var=C; export $as_var) 2>&1`"); then + eval $as_var=C; export $as_var + else + $as_unset $as_var + fi +done + +# Required to use basename. +if expr a : '\(a\)' >/dev/null 2>&1; then + as_expr=expr +else + as_expr=false +fi + +if (basename /) >/dev/null 2>&1 && test "X`basename / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi # Name of the executable. -as_me=`(basename "$0") 2>/dev/null || +as_me=`$as_basename "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)$' \| \ @@ -9075,6 +9538,7 @@ echo X/"$0" | /^X\/\(\/\).*/{ s//\1/; q; } s/.*/./; q'` + # PATH needs CR, and LINENO needs CR and PATH. # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' @@ -9085,15 +9549,15 @@ as_cr_alnum=$as_cr_Letters$as_cr_digits # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then - echo "#! /bin/sh" >conftest.sh - echo "exit 0" >>conftest.sh - chmod +x conftest.sh - if (PATH=".;."; conftest.sh) >/dev/null 2>&1; then + echo "#! /bin/sh" >conf$$.sh + echo "exit 0" >>conf$$.sh + chmod +x conf$$.sh + if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then PATH_SEPARATOR=';' else PATH_SEPARATOR=: fi - rm -f conftest.sh + rm -f conf$$.sh fi @@ -9142,6 +9606,8 @@ do as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` test "x$as_lineno_1" != "x$as_lineno_2" && test "x$as_lineno_3" = "x$as_lineno_2" ') 2>/dev/null; then + $as_unset BASH_ENV || test "${BASH_ENV+set}" != set || { BASH_ENV=; export BASH_ENV; } + $as_unset ENV || test "${ENV+set}" != set || { ENV=; export ENV; } CONFIG_SHELL=$as_dir/$as_base export CONFIG_SHELL exec "$CONFIG_SHELL" "$0" ${1+"$@"} @@ -9215,6 +9681,12 @@ else fi rm -f conf$$ conf$$.exe conf$$.file +if mkdir -p . 2>/dev/null; then + as_mkdir_p=: +else + as_mkdir_p=false +fi + as_executable_p="test -f" # Sed expression to map a string onto a valid CPP name. @@ -9231,7 +9703,7 @@ as_nl=' IFS=" $as_nl" # CDPATH. -$as_unset CDPATH || test "${CDPATH+set}" != set || { CDPATH=$PATH_SEPARATOR; export CDPATH; } +$as_unset CDPATH exec 6>&1 @@ -9248,7 +9720,7 @@ _ASBOX cat >&5 <<_CSEOF This file was extended by openggsn $as_me 0.61b, which was -generated by GNU Autoconf 2.53. Invocation command line was +generated by GNU Autoconf 2.57. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS @@ -9288,6 +9760,7 @@ Usage: $0 [OPTIONS] [FILE]... -h, --help print this help, then exit -V, --version print version number, then exit + -q, --quiet do not print progress messages -d, --debug don't remove temporary files --recheck update $as_me by reconfiguring in the same conditions --file=FILE[:TEMPLATE] @@ -9310,7 +9783,7 @@ _ACEOF cat >>$CONFIG_STATUS <<_ACEOF ac_cs_version="\\ openggsn config.status 0.61b -configured by $0, generated by GNU Autoconf 2.53, +configured by $0, generated by GNU Autoconf 2.57, with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\" Copyright 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001 @@ -9331,25 +9804,25 @@ do --*=*) ac_option=`expr "x$1" : 'x\([^=]*\)='` ac_optarg=`expr "x$1" : 'x[^=]*=\(.*\)'` - shift - set dummy "$ac_option" "$ac_optarg" ${1+"$@"} - shift + ac_shift=: + ;; + -*) + ac_option=$1 + ac_optarg=$2 + ac_shift=shift ;; - -*);; *) # This is not an option, so the user has probably given explicit # arguments. + ac_option=$1 ac_need_defaults=false;; esac - case $1 in + case $ac_option in # Handling of the options. _ACEOF -cat >>$CONFIG_STATUS <<_ACEOF - -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) - echo "running $SHELL $0 " $ac_configure_args " --no-create --no-recursion" - exec $SHELL $0 $ac_configure_args --no-create --no-recursion ;; -_ACEOF cat >>$CONFIG_STATUS <<\_ACEOF + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + ac_cs_recheck=: ;; --version | --vers* | -V ) echo "$ac_cs_version"; exit 0 ;; --he | --h) @@ -9364,13 +9837,16 @@ Try \`$0 --help' for more information." >&2;} --debug | --d* | -d ) debug=: ;; --file | --fil | --fi | --f ) - shift - CONFIG_FILES="$CONFIG_FILES $1" + $ac_shift + CONFIG_FILES="$CONFIG_FILES $ac_optarg" ac_need_defaults=false;; --header | --heade | --head | --hea ) - shift - CONFIG_HEADERS="$CONFIG_HEADERS $1" + $ac_shift + CONFIG_HEADERS="$CONFIG_HEADERS $ac_optarg" ac_need_defaults=false;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil | --si | --s) + ac_cs_silent=: ;; # This is an error. -*) { { echo "$as_me:$LINENO: error: unrecognized option: $1 @@ -9385,6 +9861,20 @@ Try \`$0 --help' for more information." >&2;} shift done +ac_configure_extra_args= + +if $ac_cs_silent; then + exec 6>/dev/null + ac_configure_extra_args="$ac_configure_extra_args --silent" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF +if \$ac_cs_recheck; then + echo "running $SHELL $0 " $ac_configure_args \$ac_configure_extra_args " --no-create --no-recursion" >&6 + exec $SHELL $0 $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion +fi + _ACEOF cat >>$CONFIG_STATUS <<_ACEOF @@ -9431,6 +9921,9 @@ if $ac_need_defaults; then test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands fi +# Have a temporary directory for convenience. Make it in the build tree +# simply because there is no reason to put it here, and in addition, +# creating and moving files from /tmp can sometimes cause problems. # Create a temporary directory, and hook for its removal unless debugging. $debug || { @@ -9439,17 +9932,17 @@ $debug || } # Create a (secure) tmp directory for tmp files. -: ${TMPDIR=/tmp} + { - tmp=`(umask 077 && mktemp -d -q "$TMPDIR/csXXXXXX") 2>/dev/null` && + tmp=`(umask 077 && mktemp -d -q "./confstatXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" } || { - tmp=$TMPDIR/cs$$-$RANDOM + tmp=./confstat$$-$RANDOM (umask 077 && mkdir $tmp) } || { - echo "$me: cannot create a temporary directory in $TMPDIR" >&2 + echo "$me: cannot create a temporary directory in ." >&2 { (exit 1); exit 1; } } @@ -9526,6 +10019,7 @@ s,@LN_S@,$LN_S,;t t s,@ECHO@,$ECHO,;t t s,@STRIP@,$STRIP,;t t s,@ac_ct_STRIP@,$ac_ct_STRIP,;t t +s,@EGREP@,$EGREP,;t t s,@LIBTOOL@,$LIBTOOL,;t t s,@EXEC_LDFLAGS@,$EXEC_LDFLAGS,;t t s,@LIBOBJS@,$LIBOBJS,;t t @@ -9548,6 +10042,7 @@ s,@AMDEP_FALSE@,$AMDEP_FALSE,;t t s,@AMDEPBACKSLASH@,$AMDEPBACKSLASH,;t t s,@CCDEPMODE@,$CCDEPMODE,;t t s,@CXXDEPMODE@,$CXXDEPMODE,;t t +s,@LTLIBOBJS@,$LTLIBOBJS,;t t CEOF _ACEOF @@ -9618,25 +10113,30 @@ echo X"$ac_file" | /^X\(\/\/\)$/{ s//\1/; q; } /^X\(\/\).*/{ s//\1/; q; } s/.*/./; q'` - { case "$ac_dir" in - [\\/]* | ?:[\\/]* ) as_incr_dir=;; - *) as_incr_dir=.;; -esac -as_dummy="$ac_dir" -for as_mkdir_dir in `IFS='/\\'; set X $as_dummy; shift; echo "$@"`; do - case $as_mkdir_dir in - # Skip DOS drivespec - ?:) as_incr_dir=$as_mkdir_dir ;; - *) - as_incr_dir=$as_incr_dir/$as_mkdir_dir - test -d "$as_incr_dir" || - mkdir "$as_incr_dir" || - { { echo "$as_me:$LINENO: error: cannot create \"$ac_dir\"" >&5 -echo "$as_me: error: cannot create \"$ac_dir\"" >&2;} - { (exit 1); exit 1; }; } - ;; - esac -done; } + { if $as_mkdir_p; then + mkdir -p "$ac_dir" + else + as_dir="$ac_dir" + as_dirs= + while test ! -d "$as_dir"; do + as_dirs="$as_dir $as_dirs" + as_dir=`(dirname "$as_dir") 2>/dev/null || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + done + test ! -n "$as_dirs" || mkdir $as_dirs + fi || { { echo "$as_me:$LINENO: error: cannot create directory \"$ac_dir\"" >&5 +echo "$as_me: error: cannot create directory \"$ac_dir\"" >&2;} + { (exit 1); exit 1; }; }; } ac_builddir=. @@ -9666,7 +10166,7 @@ esac # Don't blindly perform a `cd "$ac_dir"/$ac_foo && pwd` since $ac_foo can be # absolute. ac_abs_builddir=`cd "$ac_dir" && cd $ac_builddir && pwd` -ac_abs_top_builddir=`cd "$ac_dir" && cd $ac_top_builddir && pwd` +ac_abs_top_builddir=`cd "$ac_dir" && cd ${ac_top_builddir}. && pwd` ac_abs_srcdir=`cd "$ac_dir" && cd $ac_srcdir && pwd` ac_abs_top_srcdir=`cd "$ac_dir" && cd $ac_top_srcdir && pwd` @@ -9856,7 +10356,7 @@ _ACEOF # Break up conftest.defines because some shells have a limit on the size # of here documents, and old seds have small limits too (100 cmds). echo ' # Handle all the #define templates only if necessary.' >>$CONFIG_STATUS -echo ' if egrep "^[ ]*#[ ]*define" $tmp/in >/dev/null; then' >>$CONFIG_STATUS +echo ' if grep "^[ ]*#[ ]*define" $tmp/in >/dev/null; then' >>$CONFIG_STATUS echo ' # If there are no defines, we may have an empty if/fi' >>$CONFIG_STATUS echo ' :' >>$CONFIG_STATUS rm -f conftest.tail @@ -9880,7 +10380,7 @@ do mv conftest.tail conftest.defines done rm -f conftest.defines -echo ' fi # egrep' >>$CONFIG_STATUS +echo ' fi # grep' >>$CONFIG_STATUS echo >>$CONFIG_STATUS # Break up conftest.undefs because some shells have a limit on the size @@ -9920,7 +10420,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF cat $tmp/in >>$tmp/config.h rm -f $tmp/in if test x"$ac_file" != x-; then - if cmp -s $ac_file $tmp/config.h 2>/dev/null; then + if diff $ac_file $tmp/config.h >/dev/null 2>&1; then { echo "$as_me:$LINENO: $ac_file is unchanged" >&5 echo "$as_me: $ac_file is unchanged" >&6;} else @@ -9936,25 +10436,30 @@ echo X"$ac_file" | /^X\(\/\/\)$/{ s//\1/; q; } /^X\(\/\).*/{ s//\1/; q; } s/.*/./; q'` - { case "$ac_dir" in - [\\/]* | ?:[\\/]* ) as_incr_dir=;; - *) as_incr_dir=.;; -esac -as_dummy="$ac_dir" -for as_mkdir_dir in `IFS='/\\'; set X $as_dummy; shift; echo "$@"`; do - case $as_mkdir_dir in - # Skip DOS drivespec - ?:) as_incr_dir=$as_mkdir_dir ;; - *) - as_incr_dir=$as_incr_dir/$as_mkdir_dir - test -d "$as_incr_dir" || - mkdir "$as_incr_dir" || - { { echo "$as_me:$LINENO: error: cannot create \"$ac_dir\"" >&5 -echo "$as_me: error: cannot create \"$ac_dir\"" >&2;} - { (exit 1); exit 1; }; } - ;; - esac -done; } + { if $as_mkdir_p; then + mkdir -p "$ac_dir" + else + as_dir="$ac_dir" + as_dirs= + while test ! -d "$as_dir"; do + as_dirs="$as_dir $as_dirs" + as_dir=`(dirname "$as_dir") 2>/dev/null || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + done + test ! -n "$as_dirs" || mkdir $as_dirs + fi || { { echo "$as_me:$LINENO: error: cannot create directory \"$ac_dir\"" >&5 +echo "$as_me: error: cannot create directory \"$ac_dir\"" >&2;} + { (exit 1); exit 1; }; }; } rm -f $ac_file mv $tmp/config.h $ac_file @@ -10019,7 +10524,7 @@ esac # Don't blindly perform a `cd "$ac_dir"/$ac_foo && pwd` since $ac_foo can be # absolute. ac_abs_builddir=`cd "$ac_dir" && cd $ac_builddir && pwd` -ac_abs_top_builddir=`cd "$ac_dir" && cd $ac_top_builddir && pwd` +ac_abs_top_builddir=`cd "$ac_dir" && cd ${ac_top_builddir}. && pwd` ac_abs_srcdir=`cd "$ac_dir" && cd $ac_srcdir && pwd` ac_abs_top_srcdir=`cd "$ac_dir" && cd $ac_top_srcdir && pwd` @@ -10088,25 +10593,30 @@ echo X"$file" | /^X\(\/\/\)$/{ s//\1/; q; } /^X\(\/\).*/{ s//\1/; q; } s/.*/./; q'` - { case $dirpart/$fdir in - [\\/]* | ?:[\\/]* ) as_incr_dir=;; - *) as_incr_dir=.;; -esac -as_dummy=$dirpart/$fdir -for as_mkdir_dir in `IFS='/\\'; set X $as_dummy; shift; echo "$@"`; do - case $as_mkdir_dir in - # Skip DOS drivespec - ?:) as_incr_dir=$as_mkdir_dir ;; - *) - as_incr_dir=$as_incr_dir/$as_mkdir_dir - test -d "$as_incr_dir" || - mkdir "$as_incr_dir" || - { { echo "$as_me:$LINENO: error: cannot create $dirpart/$fdir" >&5 -echo "$as_me: error: cannot create $dirpart/$fdir" >&2;} - { (exit 1); exit 1; }; } - ;; - esac -done; } + { if $as_mkdir_p; then + mkdir -p $dirpart/$fdir + else + as_dir=$dirpart/$fdir + as_dirs= + while test ! -d "$as_dir"; do + as_dirs="$as_dir $as_dirs" + as_dir=`(dirname "$as_dir") 2>/dev/null || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + done + test ! -n "$as_dirs" || mkdir $as_dirs + fi || { { echo "$as_me:$LINENO: error: cannot create directory $dirpart/$fdir" >&5 +echo "$as_me: error: cannot create directory $dirpart/$fdir" >&2;} + { (exit 1); exit 1; }; }; } # echo "creating $dirpart/$file" echo '# dummy' > "$dirpart/$file" @@ -10135,8 +10645,11 @@ ac_clean_files=$ac_clean_files_save # need to make the FD available again. if test "$no_create" != yes; then ac_cs_success=: + ac_config_status_args= + test "$silent" = yes && + ac_config_status_args="$ac_config_status_args --quiet" exec 5>/dev/null - $SHELL $CONFIG_STATUS || ac_cs_success=false + $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false exec 5>>config.log # Use ||, not &&, to avoid exiting from the if with $? = 1, which # would make configure fail if this is the last instruction. diff --git a/ggsn/ggsn.c b/ggsn/ggsn.c index 163e602..25da64c 100644 --- a/ggsn/ggsn.c +++ b/ggsn/ggsn.c @@ -109,12 +109,15 @@ int encaps_printf(void *p, void *packet, unsigned len) int delete_context(struct pdp_t *pdp) { if (debug) printf("Deleting PDP context\n"); - ippool_freeip(ippool, (struct ippoolm_t *) pdp->peer); + if (pdp->peer) + ippool_freeip(ippool, (struct ippoolm_t *) pdp->peer); + else + sys_err(LOG_ERR, __FILE__, __LINE__, 0, "Peer not defined!"); return 0; } -int create_context(struct pdp_t *pdp) { +int create_context_ind(struct pdp_t *pdp) { struct in_addr addr; struct ippoolm_t *member; @@ -126,12 +129,16 @@ int create_context(struct pdp_t *pdp) { memcpy(pdp->qos_neg0, pdp->qos_req0, sizeof(pdp->qos_neg)); memcpy(&pdp->pco_neg, &pco, sizeof(pdp->pco_neg)); + memcpy(pdp->qos_neg.v, pdp->qos_req.v, pdp->qos_req.l); /* TODO */ + pdp->qos_neg.l = pdp->qos_req.l; + if (pdp_euaton(&pdp->eua, &addr)) { addr.s_addr = 0; /* Request dynamic */ } if (ippool_newip(ippool, &member, &addr)) { - return EOF; /* Allready in use, or no more available */ + gtp_create_context_resp(gsn, pdp, GTPCAUSE_NO_RESOURCES); + return 0; /* Allready in use, or no more available */ } pdp_ntoeua(&member->addr, &pdp->eua); @@ -139,6 +146,7 @@ int create_context(struct pdp_t *pdp) { pdp->ipif = tun; /* TODO */ member->peer = pdp; + gtp_create_context_resp(gsn, pdp, GTPCAUSE_ACC_REQ); return 0; /* Success */ } @@ -157,7 +165,7 @@ int cb_tun_ind(struct tun_t *tun, void *pack, unsigned len) { } if (ipm->peer) /* Check if a peer protocol is defined */ - gtp_gpdu(gsn, (struct pdp_t*) ipm->peer, pack, len); + gtp_data_req(gsn, (struct pdp_t*) ipm->peer, pack, len); return 0; } @@ -368,11 +376,13 @@ int main(int argc, char **argv) "Failed to create gtp"); exit(1); } - if (gsn->fd > maxfd) maxfd = gsn->fd; + if (gsn->fd0 > maxfd) maxfd = gsn->fd0; + if (gsn->fd1c > maxfd) maxfd = gsn->fd1c; + if (gsn->fd1u > maxfd) maxfd = gsn->fd1u; - gtp_set_cb_gpdu(gsn, encaps_tun); + gtp_set_cb_data_ind(gsn, encaps_tun); gtp_set_cb_delete_context(gsn, delete_context); - gtp_set_cb_create_context(gsn, create_context); + gtp_set_cb_create_context_ind(gsn, create_context_ind); /* Create a tunnel interface */ @@ -396,7 +406,9 @@ int main(int argc, char **argv) FD_ZERO(&fds); if (tun) FD_SET(tun->fd, &fds); - FD_SET(gsn->fd, &fds); + FD_SET(gsn->fd0, &fds); + FD_SET(gsn->fd1c, &fds); + FD_SET(gsn->fd1u, &fds); gtp_retranstimeout(gsn, &idleTime); switch (select(maxfd + 1, &fds, NULL, NULL, &idleTime)) { @@ -417,9 +429,15 @@ int main(int argc, char **argv) sys_err(LOG_ERR, __FILE__, __LINE__, 0, "TUN read failed (fd)=(%d)", tun->fd); } - - if (FD_ISSET(gsn->fd, &fds)) - gtp_decaps(gsn); + + if (FD_ISSET(gsn->fd0, &fds)) + gtp_decaps0(gsn); + + if (FD_ISSET(gsn->fd1c, &fds)) + gtp_decaps1c(gsn); + + if (FD_ISSET(gsn->fd1u, &fds)) + gtp_decaps1u(gsn); } @@ -122,171 +122,162 @@ int gtp_freepdp(struct gsn_t* gsn, struct pdp_t *pdp) { return pdp_freepdp(pdp); } -int gtp_create_context(struct gsn_t *gsn, struct pdp_t *pdp, void *aid, - struct in_addr* inetaddr) { - int version = 0; - - return gtp_create_pdp_req(gsn, version, aid, inetaddr, pdp); -} - -int gtp_create_context2(struct gsn_t *gsn, void *aid, - struct in_addr* inetaddr, - int selmode, uint64_t imsi, int nsapi, - uint8_t *qos, int qoslen, - char *apn, int apnlen, - char *msisdn, int msisdnlen, - uint8_t *pco, int pcolen) { - int version = 0; - - struct pdp_t *pdp; - - if (qoslen > sizeof(pdp->qos_req0)) { - gtp_err(LOG_ERR, __FILE__, __LINE__, 0, "QoS length too big"); - return -1; - } - - if (apnlen > sizeof(pdp->apn_use.v)) { - gtp_err(LOG_ERR, __FILE__, __LINE__, 0, "APN length too big"); - return -1; - } - - if (msisdnlen > sizeof(pdp->msisdn.v)) { - gtp_err(LOG_ERR, __FILE__, __LINE__, 0, "MSISDN length too big"); - return -1; - } - - if (pcolen > sizeof(pdp->pco_req.v)) { - gtp_err(LOG_ERR, __FILE__, __LINE__, 0, "PCO length too big"); - return -1; - } - - /* New pdp allocated here:*/ - pdp_newpdp(&pdp, imsi, nsapi, NULL); - - pdp->peer = aid; - pdp->ipif = NULL; - - pdp->selmode = selmode; - - memcpy(pdp->qos_req0, qos, qoslen); /* Length checked above */ - pdp->apn_use.l = apnlen; - memcpy(pdp->apn_use.v, apn, apnlen); /* Length checked above */ - - pdp->gsnlc.l = sizeof(gsn->gsnc); - memcpy(pdp->gsnlc.v, &gsn->gsnc, sizeof(gsn->gsnc)); - pdp->gsnlu.l = sizeof(gsn->gsnc); - memcpy(pdp->gsnlu.v, &gsn->gsnc, sizeof(gsn->gsnc)); - - pdp->msisdn.l = msisdnlen; - memcpy(pdp->msisdn.v, msisdn, msisdnlen); - - ipv42eua(&pdp->eua, NULL); /* Request dynamic IP address */ - - pdp->pco_req.l = pcolen; - memcpy(pdp->pco_req.v, pco, pcolen); - - return gtp_create_pdp_req(gsn, version, aid, inetaddr, pdp); -} - -int gtp_update_context(struct gsn_t *gsn, struct pdp_t *pdp, void *aid, - struct in_addr* inetaddr) { - int version = 0; - - return gtp_update_pdp_req(gsn, version, aid, inetaddr, pdp); -} - -int gtp_delete_context(struct gsn_t *gsn, struct pdp_t *pdp, void *aid) { - int version = 0; - return gtp_delete_pdp_req(gsn, version, aid, pdp); -} - /* gtp_gpdu */ extern int gtp_fd(struct gsn_t *gsn) { - return gsn->fd; + return gsn->fd0; } /* gtp_decaps */ /* gtp_retrans */ /* gtp_retranstimeout */ -int gtp_set_cb_delete_context(struct gsn_t *gsn, - int (*cb_delete_context) (struct pdp_t* pdp)) -{ - gsn->cb_delete_context = cb_delete_context; - return 0; -} -int gtp_set_cb_create_context(struct gsn_t *gsn, - int (*cb_create_context) (struct pdp_t* pdp)) -{ - gsn->cb_create_context = cb_create_context; +int gtp_set_cb_unsup_ind(struct gsn_t *gsn, + int (*cb) (struct sockaddr_in *peer)) { + gsn->cb_unsup_ind = cb; return 0; } -/* - int gtp_set_cb_create_pdp_conf(struct gsn_t *gsn, - int (*cb) (struct pdp_t*, int)) - { - gsn->cb_create_pdp_conf = cb; +/* API: Initialise delete context callback */ +/* Called whenever a pdp context is deleted for any reason */ +int gtp_set_cb_delete_context(struct gsn_t *gsn, + int (*cb) (struct pdp_t* pdp)) +{ + gsn->cb_delete_context = cb; return 0; - } - - int gtp_set_cb_update_pdp_conf(struct gsn_t *gsn, - int (*cb) (struct pdp_t*, int, int)) - { - gsn->cb_update_pdp_conf = cb; - return 0; -} - -in t gtp_set_cb_delete_pdp_conf(struct gsn_t *gsn, -int (*cb) (struct pdp_t*, int)) - { -gsn->cb_delete_pdp_conf = cb; -return 0; } -*/ - int gtp_set_cb_conf(struct gsn_t *gsn, int (*cb) (int type, int cause, - struct pdp_t* pdp, void *aid)) { + struct pdp_t* pdp, void *cbp)) { gsn->cb_conf = cb; return 0; } -extern int gtp_set_cb_gpdu(struct gsn_t *gsn, - int (*cb_gpdu) (struct pdp_t* pdp, +extern int gtp_set_cb_data_ind(struct gsn_t *gsn, + int (*cb_data_ind) (struct pdp_t* pdp, void* pack, unsigned len)) { - gsn->cb_gpdu = cb_gpdu; + gsn->cb_data_ind = cb_data_ind; return 0; } - -void get_default_gtp(int version, void *packet) { +/** + * get_default_gtp() + * Generate a GPRS Tunneling Protocol signalling packet header, depending + * on GTP version and message type. pdp is used for teid/flow label. + * *packet must be allocated by the calling function, and be large enough + * to hold the packet header. + * returns the length of the header. 0 on error. + **/ +static int get_default_gtp(int version, u_int8_t type, void *packet) { struct gtp0_header *gtp0_default = (struct gtp0_header*) packet; struct gtp1_header_long *gtp1_default = (struct gtp1_header_long*) packet; switch (version) { case 0: /* Initialise "standard" GTP0 header */ - memset(gtp0_default, 0, sizeof(gtp0_default)); + memset(gtp0_default, 0, sizeof(struct gtp0_header)); gtp0_default->flags=0x1e; + gtp0_default->type=hton8(type); gtp0_default->spare1=0xff; gtp0_default->spare2=0xff; gtp0_default->spare3=0xff; gtp0_default->number=0xff; - break; + return GTP0_HEADER_SIZE; case 1: /* Initialise "standard" GTP1 header */ - memset(gtp1_default, 0, sizeof(gtp1_default)); - gtp0_default->flags=0x1e; - break; + /* 29.060: 8.2: S=1 and PN=0 */ + /* 29.060 9.3.1: For GTP-U messages Echo Request, Echo Response */ + /* and Supported Extension Headers Notification, the S field shall be */ + /* set to 1 */ + /* Currently extension headers are not supported */ + memset(gtp1_default, 0, sizeof(struct gtp1_header_long)); + gtp1_default->flags=0x32; /* No extension, enable sequence, no N-PDU */ + gtp1_default->type=hton8(type); + return GTP1_HEADER_SIZE_LONG; + default: + gtp_err(LOG_ERR, __FILE__, __LINE__, "Unknown GTP packet version"); + return 0; + } +} + +/** + * get_seq() + * Get sequence number of a packet. + * Returns 0 on error + **/ +static uint16_t get_seq(void *pack) { + union gtp_packet *packet = (union gtp_packet *) pack; + + if ((packet->flags & 0xe0) == 0x00) { /* Version 0 */ + return ntoh16(packet->gtp0.h.seq); + } + else if ((packet->flags & 0xe2) == 0x22) { /* Version 1 with seq */ + return ntoh16(packet->gtp1l.h.seq); + } else { + gtp_err(LOG_ERR, __FILE__, __LINE__, "Unknown packet flag"); + return 0; + } +} + +/** + * get_tid() + * Get tunnel identifier of a packet. + * Returns 0 on error + **/ +static uint64_t get_tid(void *pack) { + union gtp_packet *packet = (union gtp_packet *) pack; + + if ((packet->flags & 0xe0) == 0x00) { /* Version 0 */ + return packet->gtp0.h.tid; + } + return 0; +} + +/** + * get_hlen() + * Get the header length of a packet. + * Returns 0 on error + **/ +static uint16_t get_hlen(void *pack) { + union gtp_packet *packet = (union gtp_packet *) pack; + + if ((packet->flags & 0xe0) == 0x00) { /* Version 0 */ + return GTP0_HEADER_SIZE; + } + else if ((packet->flags & 0xe2) == 0x22) { /* Version 1 with seq */ + return GTP1_HEADER_SIZE_LONG; + } + else if ((packet->flags & 0xe7) == 0x20) { /* Short version 1 */ + return GTP1_HEADER_SIZE_SHORT; + } else { + gtp_err(LOG_ERR, __FILE__, __LINE__, "Unknown packet flag"); + return 0; } } +/** + * get_tei() + * Get the tunnel endpoint identifier (flow label) of a packet. + * Returns 0xffffffff on error. + **/ +static uint32_t get_tei(void *pack) { + union gtp_packet *packet = (union gtp_packet *) pack; + + if ((packet->flags & 0xe0) == 0x00) { /* Version 0 */ + return ntoh16(packet->gtp0.h.flow); + } + else if ((packet->flags & 0xe0) == 0x20) { /* Version 1 */ + return ntoh32(packet->gtp1l.h.tei); + } + else { + gtp_err(LOG_ERR, __FILE__, __LINE__, "Unknown packet flag"); + return 0xffffffff; + } +} int print_packet(void *packet, unsigned len) @@ -362,8 +353,8 @@ char* snprint_packet(struct gsn_t *gsn, struct sockaddr_in *peer, * Create pdp context: The SGSN may send create context request even if * a context allready exist (imsi+nsapi?). This means that the reply will automatically dublicate the original response. It might however have - * sideeffects in the application which is asked twice to allocate - * validate the login. + * side effects in the application which is asked twice to validate + * the login. * Update pdp context: Automatically dublicates the original response??? * Delete pdp context. Automatically in gtp0, but in gtp1 will generate * a nonexist reply message. @@ -390,28 +381,57 @@ char* snprint_packet(struct gsn_t *gsn, struct sockaddr_in *peer, * gtp_conf: * Remove an incoming confirmation from the queue * gtp_resp: - * Send off a responce to a request. Use the same sequence + * Send off a response to a request. Use the same sequence * number in the response as in the request. * gtp_retrans: * Retransmit any outstanding packets which have exceeded * a predefined timeout. *************************************************************/ -int gtp_req(struct gsn_t *gsn, int version, union gtp_packet *packet, - int len, struct in_addr *inetaddr, void *aid) { +int gtp_req(struct gsn_t *gsn, int version, struct pdp_t *pdp, + union gtp_packet *packet, int len, + struct in_addr *inetaddr, void *cbp) { struct sockaddr_in addr; struct qmsg_t *qmsg; + int fd; + memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_addr = *inetaddr; - addr.sin_port = htons(GTP0_PORT); - packet->gtp0.h.seq = hton16(gsn->seq_next); + if ((packet->flags & 0xe0) == 0x00) { /* Version 0 */ + addr.sin_port = htons(GTP0_PORT); + packet->gtp0.h.length = hton16(len - GTP0_HEADER_SIZE); + packet->gtp0.h.seq = hton16(gsn->seq_next); + if (pdp) + packet->gtp0.h.tid = (pdp->imsi & 0x0fffffffffffffff) + + ((uint64_t)pdp->nsapi << 60); + if (pdp && ((packet->gtp0.h.type == GTP_GPDU) || + (packet->gtp0.h.type == GTP_ERROR))) + packet->gtp0.h.flow=hton16(pdp->flru); + else if (pdp) + packet->gtp0.h.flow=hton16(pdp->flrc); + fd = gsn->fd0; + } + else if ((packet->flags & 0xe2) == 0x22) { /* Version 1 with seq */ + addr.sin_port = htons(GTP1C_PORT); + packet->gtp1l.h.length = hton16(len - GTP1_HEADER_SIZE_SHORT); + packet->gtp1l.h.seq = hton16(gsn->seq_next); + if (pdp && ((packet->gtp1l.h.type == GTP_GPDU) || + (packet->gtp1l.h.type == GTP_ERROR))) + packet->gtp1l.h.tei=hton32(pdp->teid_gn); + else if (pdp) + packet->gtp1l.h.tei=hton32(pdp->teic_gn); + fd = gsn->fd1c; + } else { + gtp_err(LOG_ERR, __FILE__, __LINE__, "Unknown packet flag"); + return -1; + } - if (sendto(gsn->fd, packet, len, 0, + if (sendto(fd, packet, len, 0, (struct sockaddr *) &addr, sizeof(addr)) < 0) { gsn->err_sendto++; - gtp_err(LOG_ERR, __FILE__, __LINE__, "Sendto(fd=%d, msg=%lx, len=%d) failed: Error = %s", gsn->fd, (unsigned long) &packet, len, strerror(errno)); + gtp_err(LOG_ERR, __FILE__, __LINE__, "Sendto(fd=%d, msg=%lx, len=%d) failed: Error = %s", fd, (unsigned long) &packet, len, strerror(errno)); return -1; } @@ -425,8 +445,9 @@ int gtp_req(struct gsn_t *gsn, int version, union gtp_packet *packet, qmsg->l = len; qmsg->timeout = time(NULL) + 3; /* When to timeout */ qmsg->retrans = 0; /* No retransmissions so far */ - qmsg->aid = aid; + qmsg->cbp = cbp; qmsg->type = ntoh8(packet->gtp0.h.type); + qmsg->fd = fd; } gsn->seq_next++; /* Count up this time */ return 0; @@ -437,10 +458,21 @@ int gtp_req(struct gsn_t *gsn, int version, union gtp_packet *packet, * return 0 on success, EOF if packet was not found */ int gtp_conf(struct gsn_t *gsn, int version, struct sockaddr_in *peer, - union gtp_packet *packet, int len, uint8_t *type, void **aid) { - int seq = ntoh16(packet->gtp0.h.seq); + union gtp_packet *packet, int len, uint8_t *type, void **cbp) { + + uint16_t seq; + + if ((packet->gtp0.h.flags & 0xe0) == 0x00) + seq = ntoh16(packet->gtp0.h.seq); + else if ((packet->gtp1l.h.flags & 0xe2) == 0x22) + seq = ntoh16(packet->gtp1l.h.seq); + else { + gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, packet, len, + "Unknown GTP packet version"); + return EOF; + } - if (queue_freemsg_seq(gsn->queue_req, peer, seq, type, aid)) { + if (queue_freemsg_seq(gsn->queue_req, peer, seq, type, cbp)) { gsn->err_seq++; gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, packet, len, "Confirmation packet not found in queue"); @@ -462,14 +494,14 @@ int gtp_retrans(struct gsn_t *gsn) { (qmsg->timeout <= now)) { /*printf("Retrans timeout found: %d\n", (int) time(NULL));*/ if (qmsg->retrans > 3) { /* To many retrans */ - if (gsn->cb_conf) gsn->cb_conf(qmsg->type, EOF, NULL, qmsg->aid); + if (gsn->cb_conf) gsn->cb_conf(qmsg->type, EOF, NULL, qmsg->cbp); queue_freemsg(gsn->queue_req, qmsg); } else { - if (sendto(gsn->fd, &qmsg->p, qmsg->l, 0, + if (sendto(qmsg->fd, &qmsg->p, qmsg->l, 0, (struct sockaddr *) &qmsg->peer, sizeof(struct sockaddr_in)) < 0) { gsn->err_sendto++; - gtp_err(LOG_ERR, __FILE__, __LINE__, "Sendto(fd=%d, msg=%lx, len=%d) failed: Error = %s", gsn->fd, (unsigned long) &qmsg->p, qmsg->l, strerror(errno)); + gtp_err(LOG_ERR, __FILE__, __LINE__, "Sendto(fd0=%d, msg=%lx, len=%d) failed: Error = %s", gsn->fd0, (unsigned long) &qmsg->p, qmsg->l, strerror(errno)); } queue_back(gsn->queue_req, qmsg); qmsg->timeout = now + 3; @@ -506,30 +538,44 @@ int gtp_retranstimeout(struct gsn_t *gsn, struct timeval *timeout) { return 0; } -int gtp_resp(int version, struct gsn_t *gsn, union gtp_packet *packet, - int len, struct sockaddr_in *peer) { +int gtp_resp(int version, struct gsn_t *gsn, struct pdp_t *pdp, + union gtp_packet *packet, int len, + struct sockaddr_in *peer, int fd, + uint16_t seq, uint64_t tid) { struct qmsg_t *qmsg; - uint16_t seq; - seq = ntoh16(packet->gtp0.h.seq); + if ((packet->flags & 0xe0) == 0x00) { /* Version 0 */ + packet->gtp0.h.length = hton16(len - GTP0_HEADER_SIZE); + packet->gtp0.h.seq = hton16(seq); + packet->gtp0.h.tid = tid; + if (pdp && ((packet->gtp0.h.type == GTP_GPDU) || + (packet->gtp0.h.type == GTP_ERROR))) + packet->gtp0.h.flow=hton16(pdp->flru); + else if (pdp) + packet->gtp0.h.flow=hton16(pdp->flrc); + } + else if ((packet->flags & 0xe2) == 0x22) { /* Version 1 with seq */ + packet->gtp1l.h.length = hton16(len - GTP1_HEADER_SIZE_SHORT); + packet->gtp1l.h.seq = hton16(seq); + if (pdp && (fd == gsn->fd1u)) + packet->gtp1l.h.tei=hton32(pdp->teid_gn); + else if (pdp) + packet->gtp1l.h.tei=hton32(pdp->teic_gn); + } + else { + gtp_err(LOG_ERR, __FILE__, __LINE__, "Unknown packet flag"); + return -1; + } - /* print message */ - /* - printf("gtp_resp: to %s:UDP%u\n", - inet_ntoa(peer->sin_addr), - ntohs(peer->sin_port)); - print_packet(packet, len); - */ - - if (fcntl(gsn->fd, F_SETFL, 0)) { + if (fcntl(fd, F_SETFL, 0)) { gtp_err(LOG_ERR, __FILE__, __LINE__, "fnctl()"); return -1; } - - if (sendto(gsn->fd, packet, len, 0, + + if (sendto(fd, packet, len, 0, (struct sockaddr *) peer, sizeof(struct sockaddr_in)) < 0) { gsn->err_sendto++; - gtp_err(LOG_ERR, __FILE__, __LINE__, "Sendto(fd=%d, msg=%lx, len=%d) failed: Error = %s", gsn->fd, (unsigned long) &packet, len, strerror(errno)); + gtp_err(LOG_ERR, __FILE__, __LINE__, "Sendto(fd=%d, msg=%lx, len=%d) failed: Error = %s", fd, (unsigned long) &packet, len, strerror(errno)); return -1; } @@ -543,8 +589,9 @@ int gtp_resp(int version, struct gsn_t *gsn, union gtp_packet *packet, qmsg->l = len; qmsg->timeout = time(NULL) + 60; /* When to timeout */ qmsg->retrans = 0; /* No retransmissions so far */ - qmsg->aid = NULL; + qmsg->cbp = NULL; qmsg->type = 0; + qmsg->fd = fd; } return 0; } @@ -556,27 +603,18 @@ int gtp_dublicate(struct gsn_t *gsn, int version, if(queue_seqget(gsn->queue_resp, &qmsg, peer, seq)) { return EOF; /* Notfound */ } - else { - /* print message */ - - /*printf("gtp_dublicate: to %s:UDP%u\n", - inet_ntoa(peer->sin_addr), - ntohs(peer->sin_port)); - print_packet(&qmsg->p, qmsg->l); - */ - - if (fcntl(gsn->fd, F_SETFL, 0)) { - gtp_err(LOG_ERR, __FILE__, __LINE__, "fnctl()"); - return -1; - } - if (sendto(gsn->fd, &qmsg->p, qmsg->l, 0, - (struct sockaddr *) peer, sizeof(struct sockaddr_in)) < 0) { - gsn->err_sendto++; - gtp_err(LOG_ERR, __FILE__, __LINE__, "Sendto(fd=%d, msg=%lx, len=%d) failed: Error = %s", gsn->fd, (unsigned long) &qmsg->p, qmsg->l, strerror(errno)); - } - return 0; + if (fcntl(qmsg->fd, F_SETFL, 0)) { + gtp_err(LOG_ERR, __FILE__, __LINE__, "fnctl()"); + return -1; + } + + if (sendto(qmsg->fd, &qmsg->p, qmsg->l, 0, + (struct sockaddr *) peer, sizeof(struct sockaddr_in)) < 0) { + gsn->err_sendto++; + gtp_err(LOG_ERR, __FILE__, __LINE__, "Sendto(fd=%d, msg=%lx, len=%d) failed: Error = %s", qmsg->fd, (unsigned long) &qmsg->p, qmsg->l, strerror(errno)); } + return 0; } @@ -629,7 +667,6 @@ int gtp_new(struct gsn_t **gsn, char *statedir, struct in_addr *listen, int mode) { struct sockaddr_in addr; - int gtp_fd; syslog(LOG_ERR, "GTP: gtp_newgsn() started"); @@ -649,33 +686,69 @@ int gtp_new(struct gsn_t **gsn, char *statedir, struct in_addr *listen, pdp_init(); /* Initialise call back functions */ - (*gsn)->cb_create_context = 0; + (*gsn)->cb_create_context_ind = 0; (*gsn)->cb_delete_context = 0; + (*gsn)->cb_unsup_ind = 0; (*gsn)->cb_conf = 0; - (*gsn)->cb_gpdu = 0; + (*gsn)->cb_data_ind = 0; + + /* Store function parameters */ + (*gsn)->gsnc = *listen; + (*gsn)->gsnu = *listen; + (*gsn)->mode = mode; - if ((gtp_fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ) { + + /* Create GTP version 0 socket */ + if (((*gsn)->fd0 = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ) { (*gsn)->err_socket++; gtp_err(LOG_ERR, __FILE__, __LINE__, "socket(domain=%d, type=%d, protocol=%d) failed: Error = %s", AF_INET, SOCK_DGRAM, 0, strerror(errno)); return -1; } - (*gsn)->fd = gtp_fd; + + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_addr = *listen; /* Same IP for user traffic and signalling*/ + addr.sin_port = htons(GTP0_PORT); + + if (bind((*gsn)->fd0, (struct sockaddr *) &addr, sizeof(addr)) < 0) { + (*gsn)->err_socket++; + gtp_err(LOG_ERR, __FILE__, __LINE__, "bind(fd0=%d, addr=%lx, len=%d) failed: Error = %s", (*gsn)->fd0, (unsigned long) &addr, sizeof(addr), strerror(errno)); + return -1; + } - (*gsn)->gsnc = *listen; - (*gsn)->gsnu = *listen; + /* Create GTP version 1 control plane socket */ + if (((*gsn)->fd1c = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ) { + (*gsn)->err_socket++; + gtp_err(LOG_ERR, __FILE__, __LINE__, "socket(domain=%d, type=%d, protocol=%d) failed: Error = %s", AF_INET, SOCK_DGRAM, 0, strerror(errno)); + return -1; + } - (*gsn)->mode = mode; - memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_addr = *listen; /* Same IP for user traffic and signalling*/ + addr.sin_port = htons(GTP1C_PORT); + if (bind((*gsn)->fd1c, (struct sockaddr *) &addr, sizeof(addr)) < 0) { + (*gsn)->err_socket++; + gtp_err(LOG_ERR, __FILE__, __LINE__, "bind(fd1c=%d, addr=%lx, len=%d) failed: Error = %s", (*gsn)->fd1c, (unsigned long) &addr, sizeof(addr), strerror(errno)); + return -1; + } + + /* Create GTP version 1 user plane socket */ + if (((*gsn)->fd1u = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ) { + (*gsn)->err_socket++; + gtp_err(LOG_ERR, __FILE__, __LINE__, "socket(domain=%d, type=%d, protocol=%d) failed: Error = %s", AF_INET, SOCK_DGRAM, 0, strerror(errno)); + return -1; + } + + memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; - /* addr.sin_addr = *inetaddr; */ addr.sin_addr = *listen; /* Same IP for user traffic and signalling*/ - addr.sin_port = htons(GTP0_PORT); + addr.sin_port = htons(GTP1U_PORT); - if (bind(gtp_fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) { + if (bind((*gsn)->fd1u, (struct sockaddr *) &addr, sizeof(addr)) < 0) { (*gsn)->err_socket++; - gtp_err(LOG_ERR, __FILE__, __LINE__, "bind(fd=%d, addr=%lx, len=%d) failed: Error = %s", gtp_fd, (unsigned long) &addr, sizeof(addr), strerror(errno)); + gtp_err(LOG_ERR, __FILE__, __LINE__, "bind(fd1c=%d, addr=%lx, len=%d) failed: Error = %s", (*gsn)->fd1c, (unsigned long) &addr, sizeof(addr), strerror(errno)); return -1; } @@ -687,6 +760,10 @@ int gtp_free(struct gsn_t *gsn) { /* Clean up retransmit queues */ queue_free(gsn->queue_req); queue_free(gsn->queue_resp); + + close(gsn->fd0); + close(gsn->fd1c); + close(gsn->fd1u); free(gsn); return 0; @@ -722,67 +799,56 @@ int gtp_free(struct gsn_t *gsn) { *************************************************************/ /* Send off an echo request */ -int gtp_echo_req(struct gsn_t *gsn, struct in_addr *inetaddr) +int gtp_echo_req(struct gsn_t *gsn, int version, void *cbp, + struct in_addr *inetaddr) { union gtp_packet packet; - - get_default_gtp(0, &packet); - packet.gtp0.h.type = hton8(GTP_ECHO_REQ); - packet.gtp0.h.length = hton16(0); - - return gtp_req(gsn, 0, &packet, GTP0_HEADER_SIZE, inetaddr, NULL); + int length = get_default_gtp(version, GTP_ECHO_REQ, &packet); + return gtp_req(gsn, version, NULL, &packet, length, inetaddr, cbp); } -/* Send of an echo reply */ -int gtp_echo_resp(struct gsn_t *gsn, struct sockaddr_in *peer, +/* Send off an echo reply */ +int gtp_echo_resp(struct gsn_t *gsn, int version, + struct sockaddr_in *peer, int fd, void *pack, unsigned len) { union gtp_packet packet; - int length = 0; - - get_default_gtp(0, &packet); - - gtpie_tv1(packet.gtp0.p, &length, GTP_MAX, GTPIE_RECOVERY, - gsn->restart_counter); - - packet.gtp0.h.type = hton8(GTP_ECHO_RSP); - packet.gtp0.h.length = hton16(length); - packet.gtp0.h.seq = ((union gtp_packet*)pack)->gtp0.h.seq; - - return gtp_resp(0, gsn, &packet, GTP0_HEADER_SIZE+length, peer); + int length = get_default_gtp(version, GTP_ECHO_RSP, &packet); + gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_RECOVERY, gsn->restart_counter); + return gtp_resp(version, gsn, NULL, &packet, length, peer, fd, + get_seq(pack), get_tid(pack)); } /* Handle a received echo request */ -int gtp_echo_ind(struct gsn_t *gsn, struct sockaddr_in *peer, - void *pack, unsigned len) { +int gtp_echo_ind(struct gsn_t *gsn, int version, struct sockaddr_in *peer, + int fd, void *pack, unsigned len) { - uint16_t seq = ntoh16(((union gtp_packet*)pack)->gtp0.h.seq); + /* Check if it was a dublicate request */ + if(!gtp_dublicate(gsn, 0, peer, get_seq(pack))) return 0; - if(!gtp_dublicate(gsn, 0, peer, seq)) { - return 0; /* We allready send of response once */ - } - - - /* Now send off a reply to the peer */ - return gtp_echo_resp(gsn, peer, pack, len); + /* Send off reply to request */ + return gtp_echo_resp(gsn, version, peer, fd, pack, len); } /* Handle a received echo reply */ -int gtp_echo_conf(struct gsn_t *gsn, struct sockaddr_in *peer, +int gtp_echo_conf(struct gsn_t *gsn, int version, struct sockaddr_in *peer, void *pack, unsigned len) { union gtpie_member *ie[GTPIE_SIZE]; unsigned char recovery; - void *aid = NULL; + void *cbp = NULL; uint8_t type = 0; + int hlen = get_hlen(pack); /* Remove packet from queue */ - if (gtp_conf(gsn, 0, peer, pack, len, &type, &aid)) return EOF; + if (gtp_conf(gsn, version, peer, pack, len, &type, &cbp)) return EOF; - if (gtpie_decaps(ie, pack+sizeof(struct gtp0_header), len-sizeof(struct gtp0_header))) { + /* Extract information elements into a pointer array */ + if (gtpie_decaps(ie, version, pack+hlen, len-hlen)) { gsn->invalid++; gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, "Invalid message format"); + if (gsn->cb_conf) gsn->cb_conf(type, EOF, NULL, cbp); return EOF; } @@ -790,10 +856,13 @@ int gtp_echo_conf(struct gsn_t *gsn, struct sockaddr_in *peer, gsn->missing++; gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, "Missing mandatory field"); + if (gsn->cb_conf) gsn->cb_conf(type, EOF, NULL, cbp); return EOF; } - if (gsn->cb_conf) gsn->cb_conf(type, 0, NULL, aid); /* TODO: Should return recovery in callback */ + /* Echo reply packages does not have a cause information element */ + /* Instead we return the recovery number in the callback function */ + if (gsn->cb_conf) gsn->cb_conf(type, recovery, NULL, cbp); return 0; } @@ -809,34 +878,22 @@ int gtp_echo_conf(struct gsn_t *gsn, struct sockaddr_in *peer, * only listen to the GTP0 port, and therefore will never receive * anything else than GTP0 */ -int gtp_unsup_resp(struct gsn_t *gsn, struct sockaddr_in *peer, - void *pack, unsigned len) +int gtp_unsup_req(struct gsn_t *gsn, int version, struct sockaddr_in *peer, + int fd, void *pack, unsigned len) { union gtp_packet packet; - int length = 0; - get_default_gtp(0, &packet); - packet.gtp0.h.type = hton8(GTP_NOT_SUPPORTED); - packet.gtp0.h.length = hton16(0); - - return gtp_resp(0, gsn, &packet, GTP0_HEADER_SIZE+length, peer); + /* GTP 1 is the highest supported protocol */ + int hlen = get_default_gtp(1, GTP_NOT_SUPPORTED, &packet); + return gtp_resp(version, gsn, NULL, &packet, hlen, peer, fd, 0, 0); } /* Handle a Version Not Supported message */ -int gtp_unsup_conf(struct gsn_t *gsn, struct sockaddr_in *peer, void *pack, unsigned len) { +int gtp_unsup_ind(struct gsn_t *gsn, struct sockaddr_in *peer, + void *pack, unsigned len) { - /* TODO: Need to check the validity of header and information elements */ - /* TODO: Implement callback to application */ - /* As long as we only support GTP0 we should never receive this message */ - /* Should be implemented as part of GTP1 support */ + if (gsn->cb_unsup_ind) gsn->cb_unsup_ind(peer); - /* print received message */ - /* - printf("gtp_unsup_ind: from %s:UDP%u\n", - inet_ntoa(peer->sin_addr), - ntohs(peer->sin_port)); - print_packet(pack, len); - */ return 0; } @@ -852,284 +909,404 @@ int gtp_unsup_conf(struct gsn_t *gsn, struct sockaddr_in *peer, void *pack, unsi * information. *************************************************************/ -/* Send Create PDP Context Request */ -extern int gtp_create_pdp_req(struct gsn_t *gsn, int version, void *aid, - struct in_addr* inetaddr, struct pdp_t *pdp) { +/* API: Send Create PDP Context Request */ +extern int gtp_create_context_req(struct gsn_t *gsn, struct pdp_t *pdp, + void *cbp, struct in_addr* inetaddr) { union gtp_packet packet; - int length = 0; + int length = get_default_gtp(pdp->version, GTP_CREATE_PDP_REQ, &packet); - get_default_gtp(0, &packet); - - if (0==0) { /* Always GTP0 */ - - gtpie_tv0(packet.gtp0.p, &length, GTP_MAX, GTPIE_QOS_PROFILE0, + if (pdp->version == 0) + gtpie_tv0(&packet, &length, GTP_MAX, GTPIE_QOS_PROFILE0, sizeof(pdp->qos_req0), pdp->qos_req0); - gtpie_tv1(packet.gtp0.p, &length, GTP_MAX, GTPIE_RECOVERY, - gsn->restart_counter); - gtpie_tv1(packet.gtp0.p, &length, GTP_MAX, GTPIE_SELECTION_MODE, - pdp->selmode); - gtpie_tv2(packet.gtp0.p, &length, GTP_MAX, GTPIE_FL_DI, - pdp->fllu); - gtpie_tv2(packet.gtp0.p, &length, GTP_MAX, GTPIE_FL_C, - pdp->fllc); - gtpie_tlv(packet.gtp0.p, &length, GTP_MAX, GTPIE_EUA, - pdp->eua.l, pdp->eua.v); - gtpie_tlv(packet.gtp0.p, &length, GTP_MAX, GTPIE_APN, - pdp->apn_use.l, pdp->apn_use.v); - if (pdp->pco_req.l) { /* Optional PCO */ - gtpie_tlv(packet.gtp0.p, &length, GTP_MAX, GTPIE_PCO, - pdp->pco_req.l, pdp->pco_req.v); - } + if (pdp->version == 1) + gtpie_tv0(&packet, &length, GTP_MAX, GTPIE_IMSI, + sizeof(pdp->imsi), (uint8_t*) &pdp->imsi); - gtpie_tlv(packet.gtp0.p, &length, GTP_MAX, GTPIE_GSN_ADDR, - pdp->gsnlc.l, pdp->gsnlc.v); - gtpie_tlv(packet.gtp0.p, &length, GTP_MAX, GTPIE_GSN_ADDR, - pdp->gsnlu.l, pdp->gsnlu.v); - gtpie_tlv(packet.gtp0.p, &length, GTP_MAX, GTPIE_MSISDN, - pdp->msisdn.l, pdp->msisdn.v); - + gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_RECOVERY, + gsn->restart_counter); + gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_SELECTION_MODE, + pdp->selmode); + if (pdp->version == 0) { + gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_FL_DI, + pdp->fllu); + gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_FL_C, + pdp->fllc); + } - } else { /* GTP1 */ - gtpie_tv0(packet.gtp1s.p, &length, GTP_MAX, GTPIE_IMSI, - sizeof(pdp->imsi), (uint8_t*) &pdp->imsi); - gtpie_tv1(packet.gtp1s.p, &length, GTP_MAX, GTPIE_RECOVERY, - gsn->restart_counter); - gtpie_tv1(packet.gtp1s.p, &length, GTP_MAX, GTPIE_SELECTION_MODE, - pdp->selmode); - gtpie_tv4(packet.gtp1s.p, &length, GTP_MAX, GTPIE_TEI_DI, + if (pdp->version == 1) { + gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_TEI_DI, pdp->teid_own); - gtpie_tv4(packet.gtp1s.p, &length, GTP_MAX, GTPIE_TEI_C, + gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_TEI_C, pdp->teic_own); - gtpie_tv1(packet.gtp1s.p, &length, GTP_MAX, GTPIE_NSAPI, - pdp->nsapi); - /*gtpie_tv1(packet.gtp1s.p, &length, GTP_MAX, GTPIE_NSAPI, - pdp->nsapil); For use by several QoS profiles for the same address */ - gtpie_tv2(packet.gtp1s.p, &length, GTP_MAX, GTPIE_CHARGING_C, + } + + gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_NSAPI, + pdp->nsapi); + + /*gtpie_tv1(packet.gtp1l.p, &length, GTP_MAX, GTPIE_NSAPI, + pdp->nsapil); For use by several QoS profiles for the same address */ + + if (pdp->version == 1) { + gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_CHARGING_C, pdp->cch_pdp); - gtpie_tv2(packet.gtp1s.p, &length, GTP_MAX, GTPIE_TRACE_REF, - pdp->traceref); - gtpie_tv2(packet.gtp1s.p, &length, GTP_MAX, GTPIE_TRACE_TYPE, - pdp->tracetype); - gtpie_tlv(packet.gtp1s.p, &length, GTP_MAX, GTPIE_EUA, - pdp->eua.l, pdp->eua.v); - gtpie_tlv(packet.gtp1s.p, &length, GTP_MAX, GTPIE_APN, - pdp->apn_use.l, pdp->apn_use.v); - gtpie_tlv(packet.gtp1s.p, &length, GTP_MAX, GTPIE_PCO, + } + + /* TODO + gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_TRACE_REF, + pdp->traceref); + gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_TRACE_TYPE, + pdp->tracetype); */ + + gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_EUA, + pdp->eua.l, pdp->eua.v); + gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_APN, + pdp->apn_use.l, pdp->apn_use.v); + + if (pdp->pco_req.l) + gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_PCO, pdp->pco_req.l, pdp->pco_req.v); - gtpie_tlv(packet.gtp1s.p, &length, GTP_MAX, GTPIE_GSN_ADDR, - pdp->gsnlc.l, pdp->gsnlc.v); - gtpie_tlv(packet.gtp1s.p, &length, GTP_MAX, GTPIE_GSN_ADDR, - pdp->gsnlu.l, pdp->gsnlu.v); - gtpie_tlv(packet.gtp1s.p, &length, GTP_MAX, GTPIE_MSISDN, - pdp->msisdn.l, pdp->msisdn.v); - gtpie_tlv(packet.gtp1s.p, &length, GTP_MAX, GTPIE_QOS_PROFILE, + + gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_GSN_ADDR, + pdp->gsnlc.l, pdp->gsnlc.v); + gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_GSN_ADDR, + pdp->gsnlu.l, pdp->gsnlu.v); + gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_MSISDN, + pdp->msisdn.l, pdp->msisdn.v); + + if (pdp->version == 1) + gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_QOS_PROFILE, pdp->qos_req.l, pdp->qos_req.v); - gtpie_tlv(packet.gtp1s.p, &length, GTP_MAX, GTPIE_TFT, + + + if ((pdp->version == 1) && pdp->tft.l) + gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_TFT, pdp->tft.l, pdp->tft.v); - gtpie_tlv(packet.gtp1s.p, &length, GTP_MAX, GTPIE_TRIGGER_ID, + + if ((pdp->version == 1) && pdp->triggerid.l) + gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_TRIGGER_ID, pdp->triggerid.l, pdp->triggerid.v); - gtpie_tlv(packet.gtp1s.p, &length, GTP_MAX, GTPIE_OMC_ID, + + if ((pdp->version == 1) && pdp->omcid.l) + gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_OMC_ID, pdp->omcid.l, pdp->omcid.v); - } - packet.gtp0.h.type = hton8(GTP_CREATE_PDP_REQ); - packet.gtp0.h.length = hton16(length); - packet.gtp0.h.flow = 0; - packet.gtp0.h.tid = pdp->tid; + + gtp_req(gsn, pdp->version, pdp, &packet, length, inetaddr, cbp); + + return 0; +} + - gtp_req(gsn, 0, &packet, GTP0_HEADER_SIZE+length, inetaddr, aid); +/* API: Application response to context indication */ +int gtp_create_context_resp(struct gsn_t *gsn, struct pdp_t *pdp, int cause) { + /* Now send off a reply to the peer */ + gtp_create_pdp_resp(gsn, pdp->version, pdp, cause); + + if (cause != GTPCAUSE_ACC_REQ) { + pdp_freepdp(pdp); + } + return 0; } -/* Send Create PDP Context Response */ -int gtp_create_pdp_resp(struct gsn_t *gsn, int version, - struct sockaddr_in *peer, - void *pack, unsigned len, - struct pdp_t *pdp, uint8_t cause) +/* API: Register create context indication callback */ +int gtp_set_cb_create_context_ind(struct gsn_t *gsn, + int (*cb_create_context_ind) (struct pdp_t* pdp)) { - union gtp_packet packet; - int length = 0; + gsn->cb_create_context_ind = cb_create_context_ind; + return 0; +} - get_default_gtp(0, &packet); - gtpie_tv1(packet.gtp0.p, &length, GTP_MAX, GTPIE_CAUSE, cause); +/* Send Create PDP Context Response */ +int gtp_create_pdp_resp(struct gsn_t *gsn, int version, struct pdp_t *pdp, + uint8_t cause) { + union gtp_packet packet; + int length = get_default_gtp(version, GTP_CREATE_PDP_RSP, &packet); + + gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_CAUSE, cause); if (cause == GTPCAUSE_ACC_REQ) { - gtpie_tv0(packet.gtp0.p, &length, GTP_MAX, GTPIE_QOS_PROFILE0, - sizeof(pdp->qos_neg0), pdp->qos_neg0); - gtpie_tv1(packet.gtp0.p, &length, GTP_MAX, GTPIE_REORDER, + + if (version == 0) + gtpie_tv0(&packet, &length, GTP_MAX, GTPIE_QOS_PROFILE0, + sizeof(pdp->qos_neg0), pdp->qos_neg0); + + gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_REORDER, pdp->reorder); - gtpie_tv1(packet.gtp0.p, &length, GTP_MAX, GTPIE_RECOVERY, + gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_RECOVERY, gsn->restart_counter); - gtpie_tv2(packet.gtp0.p, &length, GTP_MAX, GTPIE_FL_DI, - pdp->fllu); - gtpie_tv2(packet.gtp0.p, &length, GTP_MAX, GTPIE_FL_C, - pdp->fllc); - gtpie_tv4(packet.gtp0.p, &length, GTP_MAX, GTPIE_CHARGING_ID, + + if (version == 0) { + gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_FL_DI, + pdp->fllu); + gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_FL_C, + pdp->fllc); + } + + if (version == 1) { + gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_TEI_DI, + pdp->teid_own); + gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_TEI_C, + pdp->teic_own); + } + + gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_CHARGING_ID, 0x12345678); - gtpie_tlv(packet.gtp0.p, &length, GTP_MAX, GTPIE_EUA, + gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_EUA, pdp->eua.l, pdp->eua.v); if (pdp->pco_neg.l) { /* Optional PCO */ - gtpie_tlv(packet.gtp0.p, &length, GTP_MAX, GTPIE_PCO, + gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_PCO, pdp->pco_neg.l, pdp->pco_neg.v); } - gtpie_tlv(packet.gtp0.p, &length, GTP_MAX, GTPIE_GSN_ADDR, + gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_GSN_ADDR, pdp->gsnlc.l, pdp->gsnlc.v); - gtpie_tlv(packet.gtp0.p, &length, GTP_MAX, GTPIE_GSN_ADDR, + gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_GSN_ADDR, pdp->gsnlu.l, pdp->gsnlu.v); - } - packet.gtp0.h.type = hton8(GTP_CREATE_PDP_RSP); - packet.gtp0.h.length = hton16(length); - packet.gtp0.h.flow = hton16(pdp->flrc); - packet.gtp0.h.seq = ((union gtp_packet*)pack)->gtp0.h.seq; - packet.gtp0.h.tid = ((union gtp_packet*)pack)->gtp0.h.tid; + if (version == 1) + gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_QOS_PROFILE, + pdp->qos_neg.l, pdp->qos_neg.v); + + /* TODO: Charging gateway address */ + } - return gtp_resp(0, gsn, &packet, GTP0_HEADER_SIZE+length, peer); + return gtp_resp(version, gsn, pdp, &packet, length, &pdp->sa_peer, + pdp->fd, pdp->seq, pdp->tid); } /* Handle Create PDP Context Request */ int gtp_create_pdp_ind(struct gsn_t *gsn, int version, - struct sockaddr_in *peer, void *pack, unsigned len) { + struct sockaddr_in *peer, int fd, + void *pack, unsigned len) { struct pdp_t *pdp, *pdp_old; struct pdp_t pdp_buf; union gtpie_member* ie[GTPIE_SIZE]; uint8_t recovery; - uint64_t imsi; - uint8_t nsapi; - int auth = 0; /* Allow access if no callback is defined */ - uint16_t seq = ntoh16(((union gtp_packet*)pack)->gtp0.h.seq); + uint16_t seq = get_seq(pack); + int hlen = get_hlen(pack); - if(!gtp_dublicate(gsn, 0, peer, seq)) { - return 0; /* We allready send of response once */ + if(!gtp_dublicate(gsn, 0, peer, seq)) return 0; + + pdp = &pdp_buf; + memset(pdp, 0, sizeof(struct pdp_t)); + + if (version == 0) { + pdp->imsi = ((union gtp_packet*)pack)->gtp0.h.tid & 0x0fffffffffffffff; + pdp->nsapi = (((union gtp_packet*)pack)->gtp0.h.tid & 0xf000000000000000) >> 60; } + pdp->seq = seq; + pdp->sa_peer = *peer; + pdp->fd = fd; + pdp->version = version; + /* Decode information elements */ - if (gtpie_decaps(ie, pack+GTP0_HEADER_SIZE, len-GTP0_HEADER_SIZE)) { + if (gtpie_decaps(ie, version, pack+hlen, len-hlen)) { gsn->invalid++; gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, "Invalid message format"); if (0 == version) return EOF; else - return gtp_create_pdp_resp(gsn, version, peer, pack, len, pdp, - GTPCAUSE_INVALID_MESSAGE); + return gtp_create_pdp_resp(gsn, version, pdp, GTPCAUSE_INVALID_MESSAGE); } - pdp = &pdp_buf; - memset(pdp, 0, sizeof(struct pdp_t)); - - /* Extract IMSI and NSAPI from header */ - imsi = ((union gtp_packet*)pack)->gtp0.h.tid & 0x0fffffffffffffff; - nsapi = (((union gtp_packet*)pack)->gtp0.h.tid & 0xf000000000000000) >> 60; + if (version == 0) { + if (gtpie_gettv0(ie, GTPIE_QOS_PROFILE0, 0, + pdp->qos_req0, sizeof(pdp->qos_req0))) { + gsn->missing++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, + "Missing mandatory information field"); + return gtp_create_pdp_resp(gsn, version, pdp, GTPCAUSE_MAN_IE_MISSING); + } + } - /* pdp_newpdp(&pdp, imsi, nsapi); TODO: Need to remove again */ - if (gtpie_gettv0(ie, GTPIE_QOS_PROFILE0, 0, - pdp->qos_req0, sizeof(pdp->qos_req0))) { - gsn->missing++; - gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, - "Missing mandatory information field"); - return gtp_create_pdp_resp(gsn, version, peer, pack, len, pdp, - GTPCAUSE_MAN_IE_MISSING); + if (version == 1) { + /* IMSI (conditional) */ + if (gtpie_gettv0(ie, GTPIE_IMSI, 0, &pdp->imsi, sizeof(pdp->imsi))) { + gsn->missing++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, + "Missing mandatory information field"); + return gtp_create_pdp_resp(gsn, version, pdp, + GTPCAUSE_MAN_IE_MISSING); + } } - /* Extract recovery (optional) */ + /* Recovery (optional) */ if (!gtpie_gettv1(ie, GTPIE_RECOVERY, 0, &recovery)) { /* TODO: Handle received recovery IE */ } + /* Selection mode (conditional) */ if (gtpie_gettv0(ie, GTPIE_SELECTION_MODE, 0, &pdp->selmode, sizeof(pdp->selmode))) { gsn->missing++; gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, "Missing mandatory information field"); - return gtp_create_pdp_resp(gsn, version, peer, pack, len, pdp, + return gtp_create_pdp_resp(gsn, version, pdp, GTPCAUSE_MAN_IE_MISSING); } - if (gtpie_gettv2(ie, GTPIE_FL_DI, 0, &pdp->flru)) { - gsn->missing++; - gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, - "Missing mandatory information field"); - return gtp_create_pdp_resp(gsn, version, peer, pack, len, pdp, - GTPCAUSE_MAN_IE_MISSING); + if (version == 0) { + if (gtpie_gettv2(ie, GTPIE_FL_DI, 0, &pdp->flru)) { + gsn->missing++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, + "Missing mandatory information field"); + return gtp_create_pdp_resp(gsn, version, pdp, + GTPCAUSE_MAN_IE_MISSING); + } + + if (gtpie_gettv2(ie, GTPIE_FL_C, 0, &pdp->flrc)) { + gsn->missing++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, + "Missing mandatory information field"); + return gtp_create_pdp_resp(gsn, version, pdp, + GTPCAUSE_MAN_IE_MISSING); + } } - if (gtpie_gettv2(ie, GTPIE_FL_C, 0, &pdp->flrc)) { - gsn->missing++; - gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, - "Missing mandatory information field"); - return gtp_create_pdp_resp(gsn, version, peer, pack, len, pdp, - GTPCAUSE_MAN_IE_MISSING); + + if (version == 1) { + /* TEID (mandatory) */ + if (gtpie_gettv4(ie, GTPIE_TEI_DI, 0, &pdp->teid_gn)) { + gsn->missing++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, + "Missing mandatory information field"); + return gtp_create_pdp_resp(gsn, version, pdp, + GTPCAUSE_MAN_IE_MISSING); + } + + /* TEIC (conditional) */ + if (gtpie_gettv4(ie, GTPIE_TEI_C, 0, &pdp->teic_gn)) { + gsn->missing++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, + "Missing mandatory information field"); + return gtp_create_pdp_resp(gsn, version, pdp, + GTPCAUSE_MAN_IE_MISSING); + } + + /* NSAPI (mandatory) */ + if (gtpie_gettv1(ie, GTPIE_NSAPI, 0, &pdp->nsapi)) { + gsn->missing++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, + "Missing mandatory information field"); + return gtp_create_pdp_resp(gsn, version, pdp, + GTPCAUSE_MAN_IE_MISSING); + } + + /* Linked NSAPI (conditional) */ + if (gtpie_gettv1(ie, GTPIE_NSAPI, 1, &pdp->linked_nsapi)) { + /* TODO: Handle linked NSAPI */ + /* Currently the Secondary PDP Context Activation Procedure is not */ + /* supported */ + } else { + gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, + "Found Linked NSAPI"); + return gtp_create_pdp_resp(gsn, version, pdp, + GTPCAUSE_NOT_SUPPORTED); + } } + /* Charging Characteriatics (optional) */ + /* Trace reference (optional) */ + /* Trace type (optional) */ + /* Charging Characteriatics (optional) */ + + /* End User Address (conditional) */ if (gtpie_gettlv(ie, GTPIE_EUA, 0, &pdp->eua.l, &pdp->eua.v, sizeof(pdp->eua.v))) { gsn->missing++; gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, "Missing mandatory information field"); - return gtp_create_pdp_resp(gsn, version, peer, pack, len, pdp, + return gtp_create_pdp_resp(gsn, version, pdp, GTPCAUSE_MAN_IE_MISSING); } + /* APN */ if (gtpie_gettlv(ie, GTPIE_APN, 0, &pdp->apn_req.l, &pdp->apn_req.v, sizeof(pdp->apn_req.v))) { gsn->missing++; gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, "Missing mandatory information field"); - return gtp_create_pdp_resp(gsn, version, peer, pack, len, pdp, + return gtp_create_pdp_resp(gsn, version, pdp, GTPCAUSE_MAN_IE_MISSING); } /* Extract protocol configuration options (optional) */ if (!gtpie_gettlv(ie, GTPIE_PCO, 0, &pdp->pco_req.l, &pdp->pco_req.v, sizeof(pdp->pco_req.v))) { - /* TODO: Handle PCO IE */ } + /* SGSN address for signalling (mandatory) */ if (gtpie_gettlv(ie, GTPIE_GSN_ADDR, 0, &pdp->gsnrc.l, &pdp->gsnrc.v, sizeof(pdp->gsnrc.v))) { gsn->missing++; gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, "Missing mandatory information field"); - return gtp_create_pdp_resp(gsn, version, peer, pack, len, pdp, + return gtp_create_pdp_resp(gsn, version, pdp, GTPCAUSE_MAN_IE_MISSING); } + /* SGSN address for user traffic (mandatory) */ if (gtpie_gettlv(ie, GTPIE_GSN_ADDR, 1, &pdp->gsnru.l, &pdp->gsnru.v, sizeof(pdp->gsnru.v))) { gsn->missing++; gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, "Missing mandatory information field"); - return gtp_create_pdp_resp(gsn, version, peer, pack, len, pdp, + return gtp_create_pdp_resp(gsn, version, pdp, GTPCAUSE_MAN_IE_MISSING); } + /* MSISDN (conditional) */ if (gtpie_gettlv(ie, GTPIE_MSISDN, 0, &pdp->msisdn.l, &pdp->msisdn.v, sizeof(pdp->msisdn.v))) { gsn->missing++; gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, "Missing mandatory information field"); - return gtp_create_pdp_resp(gsn, version, peer, pack, len, pdp, + return gtp_create_pdp_resp(gsn, version, pdp, GTPCAUSE_MAN_IE_MISSING); } + if (version == 1) { + /* QoS (mandatory) */ + if (gtpie_gettlv(ie, GTPIE_QOS_PROFILE, 0, &pdp->qos_req.l, + &pdp->qos_req.v, sizeof(pdp->qos_req.v))) { + gsn->missing++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, + "Missing mandatory information field"); + return gtp_create_pdp_resp(gsn, version, pdp, + GTPCAUSE_MAN_IE_MISSING); + } + + /* TFT (conditional) */ + if (gtpie_gettlv(ie, GTPIE_TFT, 0, &pdp->tft.l, + &pdp->tft.v, sizeof(pdp->tft.v))) { + } + + /* Trigger ID */ + /* OMC identity */ + } + + /* Initialize our own IP addresses */ in_addr2gsna(&pdp->gsnlc, &gsn->gsnc); in_addr2gsna(&pdp->gsnlu, &gsn->gsnu); if (GTP_DEBUG) printf("gtp_create_pdp_ind: Before pdp_tidget\n"); - if (!pdp_tidget(&pdp_old, ((union gtp_packet*)pack)->gtp0.h.tid)) { + if (!pdp_getimsi(&pdp_old, pdp->imsi, pdp->nsapi)) { /* Found old pdp with same tid. Now the voodoo begins! */ + /* 09.60 / 29.060 allows create on existing context to "steal" */ + /* the context which was allready established */ /* We check that the APN, selection mode and MSISDN is the same */ if (GTP_DEBUG) printf("gtp_create_pdp_ind: Old context found\n"); - if ( (pdp->apn_req.l == pdp_old->apn_req.l) + if ((pdp->apn_req.l == pdp_old->apn_req.l) && (!memcmp(pdp->apn_req.v, pdp_old->apn_req.v, pdp->apn_req.l)) && (pdp->selmode == pdp_old->selmode) && (pdp->msisdn.l == pdp_old->msisdn.l) @@ -1147,18 +1324,20 @@ int gtp_create_pdp_ind(struct gsn_t *gsn, int version, pdp_old->flru = pdp->flru; pdp_old->flrc = pdp->flrc; + /* Copy remote tei */ + pdp_old->teid_gn = pdp->teid_gn; + pdp_old->teic_gn = pdp->teic_gn; + /* Copy peer GSN address */ pdp_old->gsnrc.l = pdp->gsnrc.l; memcpy(&pdp_old->gsnrc.v, &pdp->gsnrc.v, pdp->gsnrc.l); pdp_old->gsnru.l = pdp->gsnru.l; memcpy(&pdp_old->gsnru.v, &pdp->gsnru.v, pdp->gsnru.l); - /* pdp_freepdp(pdp); not nessasary anymore since never allocated */ pdp = pdp_old; /* Confirm to peer that things were "successful" */ - return gtp_create_pdp_resp(gsn, version, peer, pack, len, pdp, - GTPCAUSE_ACC_REQ); + return gtp_create_pdp_resp(gsn, version, pdp, GTPCAUSE_ACC_REQ); } else { /* This is not the same PDP context. Delete the old one. */ @@ -1166,59 +1345,53 @@ int gtp_create_pdp_ind(struct gsn_t *gsn, int version, if (gsn->cb_delete_context) gsn->cb_delete_context(pdp_old); pdp_freepdp(pdp_old); - + if (GTP_DEBUG) printf("gtp_create_pdp_ind: Deleted...\n"); } } - pdp_newpdp(&pdp, imsi, nsapi, pdp); + pdp_newpdp(&pdp, pdp->imsi, pdp->nsapi, pdp); /* Callback function to validata login */ - if (gsn->cb_create_context !=0) - auth = gsn->cb_create_context(pdp); - - /* Now send off a reply to the peer */ - if (!auth) { - return gtp_create_pdp_resp(gsn, version, peer, pack, len, pdp, - GTPCAUSE_ACC_REQ); - } + if (gsn->cb_create_context_ind !=0) + return gsn->cb_create_context_ind(pdp); else { - gtp_create_pdp_resp(gsn, version, peer, pack, len, pdp, - GTPCAUSE_USER_AUTH_FAIL); - pdp_freepdp(pdp); - return 0; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, + "No create_context_ind callback defined"); + return gtp_create_pdp_resp(gsn, version, pdp, GTPCAUSE_NOT_SUPPORTED); } } /* Handle Create PDP Context Response */ int gtp_create_pdp_conf(struct gsn_t *gsn, int version, - struct sockaddr_in *peer, - void *pack, unsigned len) { + struct sockaddr_in *peer, + void *pack, unsigned len) { struct pdp_t *pdp; union gtpie_member *ie[GTPIE_SIZE]; uint8_t cause, recovery; - void *aid = NULL; + void *cbp = NULL; uint8_t type = 0; + int hlen = get_hlen(pack); /* Remove packet from queue */ - if (gtp_conf(gsn, 0, peer, pack, len, &type, &aid)) return EOF; + if (gtp_conf(gsn, version, peer, pack, len, &type, &cbp)) return EOF; /* Find the context in question */ - if (pdp_getgtp0(&pdp, ntoh16(((union gtp_packet*)pack)->gtp0.h.flow))) { + if (pdp_getgtp1(&pdp, get_tei(pack))) { gsn->err_unknownpdp++; gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, "Unknown PDP context"); - if (gsn->cb_conf) gsn->cb_conf(type, EOF, NULL, aid); + if (gsn->cb_conf) gsn->cb_conf(type, EOF, NULL, cbp); return EOF; } /* Decode information elements */ - if (gtpie_decaps(ie, pack+GTP0_HEADER_SIZE, len-GTP0_HEADER_SIZE)) { + if (gtpie_decaps(ie, version, pack+hlen, len-hlen)) { gsn->invalid++; gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, "Invalid message format"); - if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, aid); + if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, cbp); return EOF; } @@ -1227,7 +1400,7 @@ int gtp_create_pdp_conf(struct gsn_t *gsn, int version, gsn->missing++; gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, "Missing mandatory information field"); - if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, aid); + if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, cbp); return EOF; } @@ -1239,53 +1412,71 @@ int gtp_create_pdp_conf(struct gsn_t *gsn, int version, /* Extract protocol configuration options (optional) */ if (!gtpie_gettlv(ie, GTPIE_PCO, 0, &pdp->pco_req.l, &pdp->pco_req.v, sizeof(pdp->pco_req.v))) { - /* TODO: Handle PCO IE */ } /* Check all conditional information elements */ if (GTPCAUSE_ACC_REQ == cause) { - if (gtpie_gettv0(ie, GTPIE_QOS_PROFILE0, 0, /* TODO: HACK only gtp0 */ - &pdp->qos_neg0, sizeof(pdp->qos_neg0))) { - gsn->missing++; - gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, - "Missing conditional information field"); - if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, aid); - return EOF; + if (version == 0) { + if (gtpie_gettv0(ie, GTPIE_QOS_PROFILE0, 0, + &pdp->qos_neg0, sizeof(pdp->qos_neg0))) { + gsn->missing++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, + "Missing conditional information field"); + if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, cbp); + return EOF; + } } - /* pdp->qos_neg.l = 3; * TODO: HACK only gtp0 */ if (gtpie_gettv1(ie, GTPIE_REORDER, 0, &pdp->reorder)) { gsn->missing++; gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, "Missing conditional information field"); - if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, aid); + if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, cbp); return EOF; } - if (gtpie_gettv2(ie, GTPIE_FL_DI, 0, &pdp->flru)) { - gsn->missing++; - gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, - "Missing conditional information field"); - if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, aid); - return EOF; + if (version == 0) { + if (gtpie_gettv2(ie, GTPIE_FL_DI, 0, &pdp->flru)) { + gsn->missing++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, + "Missing conditional information field"); + if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, cbp); + return EOF; + } + + if (gtpie_gettv2(ie, GTPIE_FL_C, 0, &pdp->flrc)) { + gsn->missing++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, + "Missing conditional information field"); + if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, cbp); + return EOF; + } } + + if (version == 1) { + if (gtpie_gettv4(ie, GTPIE_TEI_DI, 0, &pdp->teid_gn)) { + gsn->missing++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, + "Missing conditional information field"); + if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, cbp); + return EOF; + } - if (gtpie_gettv2(ie, GTPIE_FL_C, 0, &pdp->flrc)) { - gsn->missing++; - gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, - "Missing conditional information field"); - if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, aid); - return EOF; + if (gtpie_gettv4(ie, GTPIE_TEI_C, 0, &pdp->teic_gn)) { + gsn->missing++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, + "Missing conditional information field"); + if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, cbp); + return EOF; + } } if (gtpie_gettv4(ie, GTPIE_CHARGING_ID, 0, &pdp->cid)) { gsn->missing++; gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, "Missing conditional information field"); - if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, aid); - return gtp_create_pdp_resp(gsn, version, peer, pack, len, pdp, - GTPCAUSE_MAN_IE_MISSING); + if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, cbp); } if (gtpie_gettlv(ie, GTPIE_EUA, 0, &pdp->eua.l, @@ -1293,7 +1484,7 @@ int gtp_create_pdp_conf(struct gsn_t *gsn, int version, gsn->missing++; gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, "Missing conditional information field"); - if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, aid); + if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, cbp); return EOF; } @@ -1302,7 +1493,7 @@ int gtp_create_pdp_conf(struct gsn_t *gsn, int version, gsn->missing++; gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, "Missing conditional information field"); - if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, aid); + if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, cbp); return EOF; } @@ -1311,178 +1502,375 @@ int gtp_create_pdp_conf(struct gsn_t *gsn, int version, gsn->missing++; gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, "Missing conditional information field"); - if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, aid); + if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, cbp); return EOF; } - } - if (gsn->cb_conf) gsn->cb_conf(type, cause, pdp, aid); + if (version == 1) { + if (gtpie_gettlv(ie, GTPIE_QOS_PROFILE, 0, &pdp->qos_neg.l, + &pdp->qos_neg.v, sizeof(pdp->qos_neg.v))) { + gsn->missing++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, + "Missing conditional information field"); + if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, cbp); + return EOF; + } + } + + } + + if (gsn->cb_conf) gsn->cb_conf(type, cause, pdp, cbp); return 0; } -/* Send Update PDP Context Request */ -extern int gtp_update_pdp_req(struct gsn_t *gsn, int version, void *aid, - struct in_addr* inetaddr, struct pdp_t *pdp) { - union gtp_packet packet; - int length = 0; - get_default_gtp(0, &packet); +/* API: Send Update PDP Context Request */ +int gtp_update_context(struct gsn_t *gsn, struct pdp_t *pdp, void *cbp, + struct in_addr* inetaddr) { + union gtp_packet packet; + int length = get_default_gtp(pdp->version, GTP_UPDATE_PDP_REQ, &packet); - gtpie_tv0(packet.gtp0.p, &length, GTP_MAX, GTPIE_QOS_PROFILE0, - sizeof(pdp->qos_req0), pdp->qos_req0); - gtpie_tv1(packet.gtp0.p, &length, GTP_MAX, GTPIE_RECOVERY, + if (pdp->version == 0) + gtpie_tv0(&packet, &length, GTP_MAX, GTPIE_QOS_PROFILE0, + sizeof(pdp->qos_req0), pdp->qos_req0); + + if (pdp->version == 1) + gtpie_tv0(&packet, &length, GTP_MAX, GTPIE_IMSI, + sizeof(pdp->imsi), (uint8_t*) &pdp->imsi); + + gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_RECOVERY, gsn->restart_counter); - gtpie_tv2(packet.gtp0.p, &length, GTP_MAX, GTPIE_FL_DI, - pdp->fllu); - gtpie_tv2(packet.gtp0.p, &length, GTP_MAX, GTPIE_FL_C, - pdp->fllc); - gtpie_tlv(packet.gtp0.p, &length, GTP_MAX, GTPIE_GSN_ADDR, + + if (pdp->version == 0) { + gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_FL_DI, + pdp->fllu); + gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_FL_C, + pdp->fllc); + } + + if (pdp->version == 1) { + gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_TEI_DI, + pdp->teid_own); + gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_TEI_C, + pdp->teic_own); + } + + gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_NSAPI, + pdp->nsapi); + + /* TODO + gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_TRACE_REF, + pdp->traceref); + gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_TRACE_TYPE, + pdp->tracetype); */ + + /* TODO if ggsn update message + gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_EUA, + pdp->eua.l, pdp->eua.v); + */ + + gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_GSN_ADDR, pdp->gsnlc.l, pdp->gsnlc.v); - gtpie_tlv(packet.gtp0.p, &length, GTP_MAX, GTPIE_GSN_ADDR, + gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_GSN_ADDR, pdp->gsnlu.l, pdp->gsnlu.v); + + if (pdp->version == 1) + gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_QOS_PROFILE, + pdp->qos_req.l, pdp->qos_req.v); + + + if ((pdp->version == 1) && pdp->tft.l) + gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_TFT, + pdp->tft.l, pdp->tft.v); - packet.gtp0.h.type = hton8(GTP_UPDATE_PDP_REQ); - packet.gtp0.h.length = hton16(length); - packet.gtp0.h.flow = 0; - packet.gtp0.h.tid = (pdp->imsi & 0x0fffffffffffffff) + ((uint64_t)pdp->nsapi << 60); + if ((pdp->version == 1) && pdp->triggerid.l) + gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_TRIGGER_ID, + pdp->triggerid.l, pdp->triggerid.v); + + if ((pdp->version == 1) && pdp->omcid.l) + gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_OMC_ID, + pdp->omcid.l, pdp->omcid.v); + + gtp_req(gsn, pdp->version, NULL, &packet, length, inetaddr, cbp); - return gtp_req(gsn, 0, &packet, GTP0_HEADER_SIZE+length, inetaddr, aid); + return 0; } + /* Send Update PDP Context Response */ -int gtp_update_pdp_resp(struct gsn_t *gsn, int version, - struct sockaddr_in *peer, - void *pack, unsigned len, - struct pdp_t *pdp, uint8_t cause) -{ +int gtp_update_pdp_resp(struct gsn_t *gsn, int version, + struct sockaddr_in *peer, int fd, + void *pack, unsigned len, + struct pdp_t *pdp, uint8_t cause) { + union gtp_packet packet; - int length = 0; + int length = get_default_gtp(version, GTP_CREATE_PDP_RSP, &packet); + + gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_CAUSE, cause); + + if (cause == GTPCAUSE_ACC_REQ) { + + if (version == 0) + gtpie_tv0(&packet, &length, GTP_MAX, GTPIE_QOS_PROFILE0, + sizeof(pdp->qos_neg0), pdp->qos_neg0); - get_default_gtp(0, &packet); + gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_RECOVERY, + gsn->restart_counter); - gtpie_tv1(packet.gtp0.p, &length, GTP_MAX, GTPIE_CAUSE, cause); + if (version == 0) { + gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_FL_DI, + pdp->fllu); + gtpie_tv2(&packet, &length, GTP_MAX, GTPIE_FL_C, + pdp->fllc); + } - if (cause == GTPCAUSE_ACC_REQ) { - gtpie_tv0(packet.gtp0.p, &length, GTP_MAX, GTPIE_QOS_PROFILE0, - sizeof(pdp->qos_sub0), pdp->qos_sub0); - gtpie_tv1(packet.gtp0.p, &length, GTP_MAX, GTPIE_RECOVERY, - gsn->restart_counter); - gtpie_tv2(packet.gtp0.p, &length, GTP_MAX, GTPIE_FL_DI, - pdp->fllu); - gtpie_tv2(packet.gtp0.p, &length, GTP_MAX, GTPIE_FL_C, - pdp->fllc); - gtpie_tv4(packet.gtp0.p, &length, GTP_MAX, GTPIE_CHARGING_ID, - 0x12345678); - gtpie_tlv(packet.gtp0.p, &length, GTP_MAX, GTPIE_GSN_ADDR, + if (version == 1) { + gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_TEI_DI, + pdp->teid_own); + gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_TEI_C, + pdp->teic_own); + } + + gtpie_tv4(&packet, &length, GTP_MAX, GTPIE_CHARGING_ID, + 0x12345678); /* TODO */ + + /* If ggsn + gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_EUA, + pdp->eua.l, pdp->eua.v); */ + + gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_GSN_ADDR, pdp->gsnlc.l, pdp->gsnlc.v); - gtpie_tlv(packet.gtp0.p, &length, GTP_MAX, GTPIE_GSN_ADDR, + gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_GSN_ADDR, pdp->gsnlu.l, pdp->gsnlu.v); - } - packet.gtp0.h.type = hton8(GTP_UPDATE_PDP_RSP); - packet.gtp0.h.length = hton16(length); - packet.gtp0.h.flow = hton16(pdp->flrc); - packet.gtp0.h.seq = ((union gtp_packet*)pack)->gtp0.h.seq; - packet.gtp0.h.tid = (pdp->imsi & 0x0fffffffffffffff) + ((uint64_t)pdp->nsapi << 60); + if (version == 1) + gtpie_tlv(&packet, &length, GTP_MAX, GTPIE_QOS_PROFILE, + pdp->qos_neg.l, pdp->qos_neg.v); + + /* TODO: Charging gateway address */ + } - return gtp_resp(0, gsn, &packet, GTP0_HEADER_SIZE+length, peer); + return gtp_resp(version, gsn, pdp, &packet, length, &pdp->sa_peer, + pdp->fd, pdp->seq, pdp->tid); } + /* Handle Update PDP Context Request */ int gtp_update_pdp_ind(struct gsn_t *gsn, int version, - struct sockaddr_in *peer, void *pack, unsigned len) { - struct pdp_t *pdp, *pdp2; - struct pdp_t pdp_buf; + struct sockaddr_in *peer, int fd, + void *pack, unsigned len) { + struct pdp_t *pdp; + struct pdp_t pdp_backup; union gtpie_member* ie[GTPIE_SIZE]; uint8_t recovery; - uint16_t seq = ntoh16(((union gtp_packet*)pack)->gtp0.h.seq); + uint16_t seq = get_seq(pack); + int hlen = get_hlen(pack); + uint64_t imsi; + uint8_t nsapi; + /* Is this a dublicate ? */ - if(!gtp_dublicate(gsn, 0, peer, seq)) { + if(!gtp_dublicate(gsn, version, peer, seq)) { return 0; /* We allready send of response once */ } - /* Find the pdp context in question */ - if (pdp_getgtp0(&pdp, ntoh16(((union gtp_packet*)pack)->gtp0.h.flow))) { - gsn->err_unknownpdp++; - gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, - "Unknown PDP context"); - return gtp_update_pdp_resp(gsn, version, peer, pack, len, NULL, - GTPCAUSE_NON_EXIST); - } /* Decode information elements */ - if (gtpie_decaps(ie, pack+GTP0_HEADER_SIZE, len-GTP0_HEADER_SIZE)) { + if (gtpie_decaps(ie, version, pack+hlen, len-hlen)) { gsn->invalid++; gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, "Invalid message format"); if (0 == version) return EOF; else - return gtp_update_pdp_resp(gsn, version, peer, pack, len, pdp, - GTPCAUSE_INVALID_MESSAGE); + return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len, + NULL, GTPCAUSE_INVALID_MESSAGE); } - pdp2 = &pdp_buf; - memcpy(pdp2, pdp, sizeof (struct pdp_t)); /* Generate local copy */ + /* Finding PDP: */ + /* For GTP0 we use the tunnel identifier to provide imsi and nsapi. */ + /* For GTP1 we must use imsi and nsapi if imsi is present. Otherwise */ + /* we have to use the tunnel endpoint identifier */ + if (version == 0) { + imsi = ((union gtp_packet*)pack)->gtp0.h.tid & 0x0fffffffffffffff; + nsapi = (((union gtp_packet*)pack)->gtp0.h.tid & 0xf000000000000000) >> 60; - if (gtpie_gettv0(ie, GTPIE_QOS_PROFILE0, 0, /* TODO: HACK only gtp0 */ - &pdp2->qos_req0, sizeof(pdp2->qos_req0))) { - gsn->missing++; - gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, - "Missing mandatory information field"); - return gtp_update_pdp_resp(gsn, version, peer, pack, len, pdp2, - GTPCAUSE_MAN_IE_MISSING); + /* Find the context in question */ + if (pdp_getimsi(&pdp, imsi, nsapi)) { + gsn->err_unknownpdp++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, + "Unknown PDP context"); + return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len, + NULL, GTPCAUSE_NON_EXIST); + } } - /* pdp2->qos_req.l = 3; * TODO: HACK only gtp0 */ + else if (version == 1) { + /* NSAPI (mandatory) */ + if (gtpie_gettv1(ie, GTPIE_NSAPI, 0, &nsapi)) { + gsn->missing++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, + "Missing mandatory information field"); + return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len, + NULL, GTPCAUSE_MAN_IE_MISSING); + } - /* Extract recovery (optional) */ + /* IMSI (conditional) */ + if (gtpie_gettv0(ie, GTPIE_IMSI, 0, &imsi, sizeof(imsi))) { + /* Find the context in question */ + if (pdp_getgtp1(&pdp, get_tei(pack))) { + gsn->err_unknownpdp++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, + "Unknown PDP context"); + return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len, + NULL, GTPCAUSE_NON_EXIST); + } + } + else { + /* Find the context in question */ + if (pdp_getimsi(&pdp, imsi, nsapi)) { + gsn->err_unknownpdp++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, + "Unknown PDP context"); + return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len, + NULL, GTPCAUSE_NON_EXIST); + } + } + } + else { + gtp_err(LOG_ERR, __FILE__, __LINE__, "Unknown version"); + return EOF; + } + + /* Make a backup copy in case anything is wrong */ + memcpy(&pdp_backup, pdp, sizeof(pdp_backup)); + + if (version == 0) { + if (gtpie_gettv0(ie, GTPIE_QOS_PROFILE0, 0, + pdp->qos_req0, sizeof(pdp->qos_req0))) { + gsn->missing++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, + "Missing mandatory information field"); + memcpy(pdp, &pdp_backup, sizeof(pdp_backup)); + return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len, + pdp, GTPCAUSE_MAN_IE_MISSING); + } + } + + /* Recovery (optional) */ if (!gtpie_gettv1(ie, GTPIE_RECOVERY, 0, &recovery)) { /* TODO: Handle received recovery IE */ } - if (gtpie_gettv2(ie, GTPIE_FL_DI, 0, &pdp2->flru)) { - gsn->missing++; - gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, - "Missing mandatory information field"); - return gtp_update_pdp_resp(gsn, version, peer, pack, len, pdp2, - GTPCAUSE_MAN_IE_MISSING); + if (version == 0) { + if (gtpie_gettv2(ie, GTPIE_FL_DI, 0, &pdp->flru)) { + gsn->missing++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, + "Missing mandatory information field"); + memcpy(pdp, &pdp_backup, sizeof(pdp_backup)); + return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len, pdp, + GTPCAUSE_MAN_IE_MISSING); + } + + if (gtpie_gettv2(ie, GTPIE_FL_C, 0, &pdp->flrc)) { + gsn->missing++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, + "Missing mandatory information field"); + memcpy(pdp, &pdp_backup, sizeof(pdp_backup)); + return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len, pdp, + GTPCAUSE_MAN_IE_MISSING); + } } - if (gtpie_gettv2(ie, GTPIE_FL_C, 0, &pdp2->flrc)) { + + if (version == 1) { + /* TEID (mandatory) */ + if (gtpie_gettv4(ie, GTPIE_TEI_DI, 0, &pdp->teid_gn)) { + gsn->missing++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, + "Missing mandatory information field"); + memcpy(pdp, &pdp_backup, sizeof(pdp_backup)); + return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len, pdp, + GTPCAUSE_MAN_IE_MISSING); + } + + /* TEIC (conditional) */ + /* If TEIC is not included it means that we have allready received it */ + if (gtpie_gettv4(ie, GTPIE_TEI_C, 0, &pdp->teic_gn)) { + } + + /* NSAPI (mandatory) */ + if (gtpie_gettv1(ie, GTPIE_NSAPI, 0, &pdp->nsapi)) { + gsn->missing++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, + "Missing mandatory information field"); + memcpy(pdp, &pdp_backup, sizeof(pdp_backup)); + return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len, pdp, + GTPCAUSE_MAN_IE_MISSING); + } + } + + /* Trace reference (optional) */ + /* Trace type (optional) */ + + /* End User Address (conditional) TODO: GGSN Initiated + if (gtpie_gettlv(ie, GTPIE_EUA, 0, &pdp->eua.l, + &pdp->eua.v, sizeof(pdp->eua.v))) { gsn->missing++; gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, "Missing mandatory information field"); - return gtp_update_pdp_resp(gsn, version, peer, pack, len, pdp2, + memcpy(pdp, &pdp_backup, sizeof(pdp_backup)); + return gtp_update_pdp_resp(gsn, version, pdp, GTPCAUSE_MAN_IE_MISSING); - } + } */ - if (gtpie_gettlv(ie, GTPIE_GSN_ADDR, 0, &pdp2->gsnrc.l, - &pdp2->gsnrc.v, sizeof(pdp2->gsnrc.v))) { + + /* SGSN address for signalling (mandatory) */ + /* It is weird that this is mandatory when TEIC is conditional */ + if (gtpie_gettlv(ie, GTPIE_GSN_ADDR, 0, &pdp->gsnrc.l, + &pdp->gsnrc.v, sizeof(pdp->gsnrc.v))) { gsn->missing++; gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, "Missing mandatory information field"); - return gtp_update_pdp_resp(gsn, version, peer, pack, len, pdp2, + memcpy(pdp, &pdp_backup, sizeof(pdp_backup)); + return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len, pdp, GTPCAUSE_MAN_IE_MISSING); } - if (gtpie_gettlv(ie, GTPIE_GSN_ADDR, 1, &pdp2->gsnru.l, - &pdp2->gsnru.v, sizeof(pdp2->gsnru.v))) { + /* SGSN address for user traffic (mandatory) */ + if (gtpie_gettlv(ie, GTPIE_GSN_ADDR, 1, &pdp->gsnru.l, + &pdp->gsnru.v, sizeof(pdp->gsnru.v))) { gsn->missing++; gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, "Missing mandatory information field"); - return gtp_update_pdp_resp(gsn, version, peer, pack, len, pdp2, + memcpy(pdp, &pdp_backup, sizeof(pdp_backup)); + return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len, pdp, GTPCAUSE_MAN_IE_MISSING); } + + if (version == 1) { + /* QoS (mandatory) */ + if (gtpie_gettlv(ie, GTPIE_QOS_PROFILE, 0, &pdp->qos_req.l, + &pdp->qos_req.v, sizeof(pdp->qos_req.v))) { + gsn->missing++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, + "Missing mandatory information field"); + memcpy(pdp, &pdp_backup, sizeof(pdp_backup)); + return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len, pdp, + GTPCAUSE_MAN_IE_MISSING); + } - /* OK! It seames as if we received a valid message */ - - memcpy(pdp, pdp2, sizeof (struct pdp_t)); /* Update original pdp */ + /* TFT (conditional) */ + if (gtpie_gettlv(ie, GTPIE_TFT, 0, &pdp->tft.l, + &pdp->tft.v, sizeof(pdp->tft.v))) { + } + + /* OMC identity */ + } /* Confirm to peer that things were "successful" */ - return gtp_update_pdp_resp(gsn, version, peer, pack, len, pdp, + return gtp_update_pdp_resp(gsn, version, peer, fd, pack, len, pdp, GTPCAUSE_ACC_REQ); } @@ -1494,27 +1882,27 @@ int gtp_update_pdp_conf(struct gsn_t *gsn, int version, struct pdp_t *pdp; union gtpie_member *ie[GTPIE_SIZE]; uint8_t cause, recovery; - void *aid = NULL; + void *cbp = NULL; uint8_t type = 0; /* Remove packet from queue */ - if (gtp_conf(gsn, 0, peer, pack, len, &type, &aid)) return EOF; + if (gtp_conf(gsn, 0, peer, pack, len, &type, &cbp)) return EOF; /* Find the context in question */ if (pdp_getgtp0(&pdp, ntoh16(((union gtp_packet*)pack)->gtp0.h.flow))) { gsn->err_unknownpdp++; gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, "Unknown PDP context"); - if (gsn->cb_conf) gsn->cb_conf(type, cause, NULL, aid); + if (gsn->cb_conf) gsn->cb_conf(type, cause, NULL, cbp); return EOF; } /* Decode information elements */ - if (gtpie_decaps(ie, pack+GTP0_HEADER_SIZE, len-GTP0_HEADER_SIZE)) { + if (gtpie_decaps(ie, 0, pack+GTP0_HEADER_SIZE, len-GTP0_HEADER_SIZE)) { gsn->invalid++; gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, "Invalid message format"); - if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, aid); + if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, cbp); if (gsn->cb_delete_context) gsn->cb_delete_context(pdp); pdp_freepdp(pdp); return EOF; @@ -1525,7 +1913,7 @@ int gtp_update_pdp_conf(struct gsn_t *gsn, int version, gsn->missing++; gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, "Missing mandatory information field"); - if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, aid); + if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, cbp); if (gsn->cb_delete_context) gsn->cb_delete_context(pdp); pdp_freepdp(pdp); return EOF; @@ -1538,7 +1926,7 @@ int gtp_update_pdp_conf(struct gsn_t *gsn, int version, /* Check all conditional information elements */ if (GTPCAUSE_ACC_REQ != cause) { - if (gsn->cb_conf) gsn->cb_conf(type, cause, pdp, aid); + if (gsn->cb_conf) gsn->cb_conf(type, cause, pdp, cbp); if (gsn->cb_delete_context) gsn->cb_delete_context(pdp); pdp_freepdp(pdp); return 0; @@ -1556,7 +1944,7 @@ int gtp_update_pdp_conf(struct gsn_t *gsn, int version, gsn->missing++; gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, "Missing conditional information field"); - if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, aid); + if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, cbp); if (gsn->cb_delete_context) gsn->cb_delete_context(pdp); pdp_freepdp(pdp); return EOF; @@ -1576,55 +1964,51 @@ int gtp_update_pdp_conf(struct gsn_t *gsn, int version, gtpie_gettlv(ie, GTPIE_GSN_ADDR, 1, &pdp->gsnru.l, &pdp->gsnru.v, sizeof(pdp->gsnru.v)); - if (gsn->cb_conf) gsn->cb_conf(type, cause, pdp, aid); + if (gsn->cb_conf) gsn->cb_conf(type, cause, pdp, cbp); return 0; /* Succes */ } } -/* Send Delete PDP Context Request */ -extern int gtp_delete_pdp_req(struct gsn_t *gsn, int version, void *aid, - struct pdp_t *pdp) { + +/* API: Send Delete PDP Context Request */ +int gtp_delete_context_req(struct gsn_t *gsn, struct pdp_t *pdp, void *cbp) { union gtp_packet packet; - int length = 0; + int length = get_default_gtp(pdp->version, GTP_CREATE_PDP_REQ, &packet); struct in_addr addr; - + if (gsna2in_addr(&addr, &pdp->gsnrc)) { gsn->err_address++; gtp_err(LOG_ERR, __FILE__, __LINE__, "GSN address conversion failed"); return EOF; } + + if (pdp->version == 1) { + gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_NSAPI, + pdp->nsapi); - get_default_gtp(0, &packet); - - packet.gtp0.h.type = hton8(GTP_DELETE_PDP_REQ); - packet.gtp0.h.length = hton16(length); - packet.gtp0.h.flow = hton16(pdp->flrc); - packet.gtp0.h.tid = (pdp->imsi & 0x0fffffffffffffff) + ((uint64_t)pdp->nsapi << 60); + gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_TEARDOWN, + 0xff); + } - return gtp_req(gsn, 0, &packet, GTP0_HEADER_SIZE+length, &addr, aid); + get_default_gtp(pdp->version, GTP_DELETE_PDP_REQ, &packet); + + return gtp_req(gsn, pdp->version, pdp, &packet, length, &addr, cbp); } + /* Send Delete PDP Context Response */ int gtp_delete_pdp_resp(struct gsn_t *gsn, int version, - struct sockaddr_in *peer, + struct sockaddr_in *peer, int fd, void *pack, unsigned len, struct pdp_t *pdp, uint8_t cause) { union gtp_packet packet; - int length = 0; - uint16_t flow = 0; - - if (pdp) flow = hton16(pdp->flrc); - - get_default_gtp(0, &packet); + int length = get_default_gtp(version, GTP_DELETE_PDP_RSP, &packet); - gtpie_tv1(packet.gtp0.p, &length, GTP_MAX, GTPIE_CAUSE, cause); + gtpie_tv1(&packet, &length, GTP_MAX, GTPIE_CAUSE, cause); - packet.gtp0.h.type = hton8(GTP_DELETE_PDP_RSP); - packet.gtp0.h.length = hton16(length); - packet.gtp0.h.flow = flow; - packet.gtp0.h.seq = ((union gtp_packet*)pack)->gtp0.h.seq; - packet.gtp0.h.tid = ((union gtp_packet*)pack)->gtp0.h.tid; + gtp_resp(version, gsn, pdp, &packet, length, peer, fd, + get_seq(pack),get_tid(pack)); if (pdp) { /* Callback function to allow application to clean up */ @@ -1632,47 +2016,74 @@ int gtp_delete_pdp_resp(struct gsn_t *gsn, int version, pdp_freepdp(pdp); /* Clean up PDP context */ } - return gtp_resp(0, gsn, &packet, GTP0_HEADER_SIZE+length, peer); + return 0; } /* Handle Delete PDP Context Request */ int gtp_delete_pdp_ind(struct gsn_t *gsn, int version, - struct sockaddr_in *peer, void *pack, unsigned len) { - struct pdp_t *pdp; + struct sockaddr_in *peer, int fd, + void *pack, unsigned len) { + struct pdp_t *pdp; union gtpie_member* ie[GTPIE_SIZE]; - uint16_t seq = ntoh16(((union gtp_packet*)pack)->gtp0.h.seq); + + uint16_t seq = get_seq(pack); + int hlen = get_hlen(pack); + uint8_t nsapi; + uint8_t teardown; + /* Is this a dublicate ? */ - if(!gtp_dublicate(gsn, 0, peer, seq)) { - return 0; + if(!gtp_dublicate(gsn, version, peer, seq)) { + return 0; /* We allready send off response once */ } - /* Find the pdp context in question */ - if (pdp_getgtp0(&pdp, ntoh16(((union gtp_packet*)pack)->gtp0.h.flow))) { + /* Find the context in question */ + if (pdp_getgtp1(&pdp, get_tei(pack))) { gsn->err_unknownpdp++; gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, "Unknown PDP context"); - if (0 == version) - return gtp_delete_pdp_resp(gsn, version, peer, pack, len, NULL, - GTPCAUSE_ACC_REQ); - else - return gtp_delete_pdp_resp(gsn, version, peer, pack, len, NULL, - GTPCAUSE_NON_EXIST); + return gtp_delete_pdp_resp(gsn, version, peer, fd, pack, len, + NULL, GTPCAUSE_NON_EXIST); } /* Decode information elements */ - if (gtpie_decaps(ie, pack+GTP0_HEADER_SIZE, len-GTP0_HEADER_SIZE)) { + if (gtpie_decaps(ie, version, pack+hlen, len-hlen)) { gsn->invalid++; gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, "Invalid message format"); if (0 == version) return EOF; else - return gtp_delete_pdp_resp(gsn, version, peer, pack, len, pdp, - GTPCAUSE_INVALID_MESSAGE); + return gtp_delete_pdp_resp(gsn, version, peer, fd, pack, len, + NULL, GTPCAUSE_INVALID_MESSAGE); } - return gtp_delete_pdp_resp(gsn, version, peer, pack, len, pdp, + if (version == 1) { + /* NSAPI (mandatory) */ + if (gtpie_gettv1(ie, GTPIE_NSAPI, 0, &nsapi)) { + gsn->missing++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, + "Missing mandatory information field"); + return gtp_delete_pdp_resp(gsn, version, peer, fd, pack, len, + NULL, GTPCAUSE_MAN_IE_MISSING); + } + + /* TODO: When multiple contexts with the same IP address exists + we need to tear down each one individually or as a group depending + on the value of teardown */ + + /* Teardown (conditional) */ + if (gtpie_gettv1(ie, GTPIE_TEARDOWN, 0, &teardown)) { + return 0; /* 29.060 7.3.5 Ignore message */ + /* gsn->missing++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, + "Missing mandatory information field"); + return gtp_delete_pdp_resp(gsn, version, peer, fd, pack, len, + NULL, GTPCAUSE_MAN_IE_MISSING); */ + } + } + + return gtp_delete_pdp_resp(gsn, version, peer, fd, pack, len, pdp, GTPCAUSE_ACC_REQ); } @@ -1684,33 +2095,37 @@ int gtp_delete_pdp_conf(struct gsn_t *gsn, int version, struct pdp_t *pdp; union gtpie_member *ie[GTPIE_SIZE]; uint8_t cause; - void *aid = NULL; + void *cbp = NULL; uint8_t type = 0; - + int hlen = get_hlen(pack); + /* Remove packet from queue */ - if (gtp_conf(gsn, 0, peer, pack, len, &type, &aid)) return EOF; + if (gtp_conf(gsn, version, peer, pack, len, &type, &cbp)) return EOF; /* Find the context in question */ - if (pdp_getgtp0(&pdp, ntoh16(((union gtp_packet*)pack)->gtp0.h.flow))) { + if (pdp_getgtp1(&pdp, get_tei(pack))) { gsn->err_unknownpdp++; gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, "Unknown PDP context"); + if (gsn->cb_conf) gsn->cb_conf(type, EOF, NULL, cbp); return EOF; } /* Decode information elements */ - if (gtpie_decaps(ie, pack+GTP0_HEADER_SIZE, len-GTP0_HEADER_SIZE)) { + if (gtpie_decaps(ie, version, pack+hlen, len-hlen)) { gsn->invalid++; gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, "Invalid message format"); + if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, cbp); return EOF; } - /* Extract cause value */ + /* Extract cause value (mandatory) */ if (gtpie_gettv1(ie, GTPIE_CAUSE, 0, &cause)) { gsn->missing++; gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, "Missing mandatory information field"); + if (gsn->cb_conf) gsn->cb_conf(type, EOF, pdp, cbp); return EOF; } @@ -1719,12 +2134,12 @@ int gtp_delete_pdp_conf(struct gsn_t *gsn, int version, gsn->err_cause++; gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, "Unexpected cause value received: %d", cause); - return EOF; } - /* Callback function to allow application to clean up */ - if (gsn->cb_conf) gsn->cb_conf(type, cause, pdp, aid); + /* Callback function to notify application */ + if (gsn->cb_conf) gsn->cb_conf(type, cause, pdp, cbp); + /* Callback function to allow application to clean up */ if (gsn->cb_delete_context) gsn->cb_delete_context(pdp); pdp_freepdp(pdp); @@ -1733,21 +2148,14 @@ int gtp_delete_pdp_conf(struct gsn_t *gsn, int version, /* Send Error Indication (response to a GPDU message */ int gtp_error_ind_resp(struct gsn_t *gsn, int version, - struct sockaddr_in *peer, + struct sockaddr_in *peer, int fd, void *pack, unsigned len) { union gtp_packet packet; - int length = 0; - - get_default_gtp(0, &packet); + int length = get_default_gtp(version, GTP_ERROR, &packet); - packet.gtp0.h.type = hton8(GTP_ERROR); - packet.gtp0.h.length = hton16(length); - packet.gtp0.h.flow = 0; - packet.gtp0.h.seq = ((union gtp_packet*)pack)->gtp0.h.seq; - packet.gtp0.h.tid = ((union gtp_packet*)pack)->gtp0.h.tid; - - return gtp_resp(0, gsn, &packet, GTP0_HEADER_SIZE+length, peer); + return gtp_resp(version, gsn, NULL, &packet, length, peer, fd, + get_seq(pack), get_tid(pack)); } /* Handle Error Indication */ @@ -1774,78 +2182,93 @@ int gtp_error_ind_conf(struct gsn_t *gsn, int version, } int gtp_gpdu_ind(struct gsn_t *gsn, int version, - struct sockaddr_in *peer, - void *pack, - unsigned len) { + struct sockaddr_in *peer, int fd, + void *pack, unsigned len) { + + int hlen = GTP1_HEADER_SIZE_SHORT; /* Need to include code to verify packet src and dest addresses */ struct pdp_t *pdp; - - if (pdp_getgtp0(&pdp, ntoh16(((union gtp_packet*)pack)->gtp0.h.flow))) { - gsn->err_unknownpdp++; - gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, - "Unknown PDP context"); - return gtp_error_ind_resp(gsn, version, peer, pack, len); - + + if (version == 0) { + if (pdp_getgtp0(&pdp, ntoh16(((union gtp_packet*)pack)->gtp0.h.flow))) { + gsn->err_unknownpdp++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, + "Unknown PDP context"); + return gtp_error_ind_resp(gsn, version, peer, fd, pack, len); + } + hlen = GTP0_HEADER_SIZE; } + else if (version == 1) { + if (pdp_getgtp1(&pdp, ntoh32(((union gtp_packet*)pack)->gtp1l.h.tei))) { + gsn->err_unknownpdp++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, + "Unknown PDP context"); + return gtp_error_ind_resp(gsn, version, peer, fd, pack, len); + } + /* Is this a long or a short header ? */ + if (((union gtp_packet*)pack)->gtp1l.h.flags & 0x07) + hlen = GTP1_HEADER_SIZE_LONG; + else + hlen = GTP1_HEADER_SIZE_SHORT; + } + else { + gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, + "Unknown version"); + } + /* If the GPDU was not from the peer GSN tell him to delete context */ if (memcmp(&peer->sin_addr, pdp->gsnru.v, pdp->gsnru.l)) { /* TODO Range? */ gsn->err_unknownpdp++; gtp_errpack(LOG_ERR, __FILE__, __LINE__, peer, pack, len, "Unknown PDP context"); - return gtp_error_ind_resp(gsn, version, peer, pack, len); + return gtp_error_ind_resp(gsn, version, peer, fd, pack, len); } - + /* Callback function */ - if (gsn->cb_gpdu !=0) - return gsn->cb_gpdu(pdp, pack+20, len-20); /* TODO ???? */ + if (gsn->cb_data_ind !=0) + return gsn->cb_data_ind(pdp, pack+hlen, len-hlen); return 0; } + /* Receives GTP packet and sends off for further processing * Function will check the validity of the header. If the header * is not valid the packet is either dropped or a version not * supported is returned to the peer. * TODO: Need to decide on return values! */ -int gtp_decaps(struct gsn_t *gsn) +int gtp_decaps0(struct gsn_t *gsn) { unsigned char buffer[PACKET_MAX + 64 /*TODO: ip header */ ]; - int status, ip_len = 0; struct sockaddr_in peer; int peerlen; + int status; struct gtp0_header *pheader; int version = 0; /* GTP version should be determined from header!*/ + int fd = gsn->fd0; /* TODO: Need strategy of userspace buffering and blocking */ /* Currently read is non-blocking and send is blocking. */ /* This means that the program have to wait for busy send calls...*/ while (1) { /* Loop until no more to read */ - if (fcntl(gsn->fd, F_SETFL, O_NONBLOCK)) { + if (fcntl(gsn->fd0, F_SETFL, O_NONBLOCK)) { gtp_err(LOG_ERR, __FILE__, __LINE__, "fnctl()"); return -1; } peerlen = sizeof(peer); if ((status = - recvfrom(gsn->fd, buffer, sizeof(buffer), 0, + recvfrom(gsn->fd0, buffer, sizeof(buffer), 0, (struct sockaddr *) &peer, &peerlen)) < 0 ) { - if (errno == EAGAIN) return -1; + if (errno == EAGAIN) return 0; gsn->err_readfrom++; - gtp_err(LOG_ERR, __FILE__, __LINE__, "recvfrom(fd=%d, buffer=%lx, len=%d) failed: status = %d error = %s", gsn->fd, (unsigned long) buffer, sizeof(buffer), status, status ? strerror(errno) : "No error"); + gtp_err(LOG_ERR, __FILE__, __LINE__, "recvfrom(fd0=%d, buffer=%lx, len=%d) failed: status = %d error = %s", gsn->fd0, (unsigned long) buffer, sizeof(buffer), status, status ? strerror(errno) : "No error"); return -1; } - /* Strip off IP header, if present: TODO Is this nessesary? */ - if ((buffer[0] & 0xF0) == 0x40) { - ip_len = (buffer[0] & 0xF) * 4; - gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status, - "IP header found in return from read"); - continue; - } - /* Need at least 1 byte in order to check version */ if (status < (1)) { gsn->empty++; @@ -1854,30 +2277,37 @@ int gtp_decaps(struct gsn_t *gsn) continue; } - /* TODO: Remove these ERROR MESSAGES - gtp_err(LOG_ERR, __FILE__, __LINE__, "Discarding packet - too small"); - gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status, - "Discarding packet - too small"); */ - - pheader = (struct gtp0_header *) (buffer + ip_len); + pheader = (struct gtp0_header *) (buffer); - /* Version should be gtp0 (or earlier in theory) */ + /* Version should be gtp0 (or earlier) */ + /* 09.60 is somewhat unclear on this issue. On gsn->fd0 we expect only */ + /* GTP 0 messages. If other version message is received we reply that we */ + /* only support version 0, implying that this is the only version */ + /* supported on this port */ if (((pheader->flags & 0xe0) > 0x00)) { gsn->unsup++; gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status, "Unsupported GTP version"); - gtp_unsup_resp(gsn, &peer, buffer, status); /* 29.60: 11.1.1 */ + gtp_unsup_req(gsn, 0, &peer, gsn->fd0, buffer, status); /* 29.60: 11.1.1 */ continue; } /* Check length of gtp0 packet */ - if (((pheader->flags & 0xe0) == 0x00) && (status < GTP0_HEADER_SIZE)) { + if (status < GTP0_HEADER_SIZE) { gsn->tooshort++; gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status, "GTP0 packet too short"); continue; /* Silently discard 29.60: 11.1.2 */ } + /* Check packet length field versus length of packet */ + if (status != (ntoh16(pheader->length) + GTP0_HEADER_SIZE)) { + gsn->tooshort++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status, + "GTP packet length field does not match actual length"); + continue; /* Silently discard */ + } + if ((gsn->mode == GTP_MODE_GGSN) && ((pheader->type == GTP_CREATE_PDP_RSP) || (pheader->type == GTP_UPDATE_PDP_RSP) || @@ -1898,48 +2328,289 @@ int gtp_decaps(struct gsn_t *gsn) continue; /* Silently discard 29.60: 11.1.4 */ } + switch (pheader->type) { + case GTP_ECHO_REQ: + gtp_echo_ind(gsn, version, &peer, fd, buffer, status); + break; + case GTP_ECHO_RSP: + gtp_echo_conf(gsn, version, &peer, buffer, status); + break; + case GTP_NOT_SUPPORTED: + gtp_unsup_ind(gsn, &peer, buffer, status); + break; + case GTP_CREATE_PDP_REQ: + gtp_create_pdp_ind(gsn, version, &peer, fd, buffer, status); + break; + case GTP_CREATE_PDP_RSP: + gtp_create_pdp_conf(gsn, version, &peer, buffer, status); + break; + case GTP_UPDATE_PDP_REQ: + gtp_update_pdp_ind(gsn, version, &peer, fd, buffer, status); + break; + case GTP_UPDATE_PDP_RSP: + gtp_update_pdp_conf(gsn, version, &peer, buffer, status); + break; + case GTP_DELETE_PDP_REQ: + gtp_delete_pdp_ind(gsn, version, &peer, fd, buffer, status); + break; + case GTP_DELETE_PDP_RSP: + gtp_delete_pdp_conf(gsn, version, &peer, buffer, status); + break; + case GTP_ERROR: + gtp_error_ind_conf(gsn, version, &peer, buffer, status); + break; + case GTP_GPDU: + gtp_gpdu_ind(gsn, version, &peer, fd, buffer, status); + break; + default: + gsn->unknown++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status, + "Unknown GTP message type received"); + break; + } + } +} + +int gtp_decaps1c(struct gsn_t *gsn) +{ + unsigned char buffer[PACKET_MAX + 64 /*TODO: ip header */ ]; + struct sockaddr_in peer; + int peerlen; + int status; + struct gtp1_header_short *pheader; + int version = 1; /* GTP version should be determined from header!*/ + int fd = gsn->fd1c; + + /* TODO: Need strategy of userspace buffering and blocking */ + /* Currently read is non-blocking and send is blocking. */ + /* This means that the program have to wait for busy send calls...*/ + + while (1) { /* Loop until no more to read */ + if (fcntl(gsn->fd1c, F_SETFL, O_NONBLOCK)) { + gtp_err(LOG_ERR, __FILE__, __LINE__, "fnctl()"); + return -1; + } + peerlen = sizeof(peer); + if ((status = + recvfrom(gsn->fd1c, buffer, sizeof(buffer), 0, + (struct sockaddr *) &peer, &peerlen)) < 0 ) { + if (errno == EAGAIN) return 0; + gsn->err_readfrom++; + gtp_err(LOG_ERR, __FILE__, __LINE__, "recvfrom(fd1c=%d, buffer=%lx, len=%d) failed: status = %d error = %s", gsn->fd1c, (unsigned long) buffer, sizeof(buffer), status, status ? strerror(errno) : "No error"); + return -1; + } + + /* Need at least 1 byte in order to check version */ + if (status < (1)) { + gsn->empty++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status, + "Discarding packet - too small"); + continue; + } + + pheader = (struct gtp1_header_short *) (buffer); + /* Version must be no larger than GTP 1 */ + if (((pheader->flags & 0xe0) > 0x20)) { + gsn->unsup++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status, + "Unsupported GTP version"); + gtp_unsup_req(gsn, 1, &peer, gsn->fd1c, buffer, status);/*29.60: 11.1.1*/ + continue; + } + + /* Version must be at least GTP 1 */ + /* 29.060 is somewhat unclear on this issue. On gsn->fd1c we expect only */ + /* GTP 1 messages. If GTP 0 message is received we silently discard */ + /* the message */ + if (((pheader->flags & 0xe0) < 0x20)) { + gsn->unsup++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status, + "Unsupported GTP version"); + continue; + } + + /* Check packet flag field */ + if (((pheader->flags & 0xf7) != 0x32)) { + gsn->unsup++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status, + "Unsupported packet flag"); + continue; + } + + /* Check length of packet */ + if (status < GTP1_HEADER_SIZE_LONG) { + gsn->tooshort++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status, + "GTP packet too short"); + continue; /* Silently discard 29.60: 11.1.2 */ + } + + /* Check packet length field versus length of packet */ + if (status != (ntoh16(pheader->length) + GTP1_HEADER_SIZE_SHORT)) { + gsn->tooshort++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status, + "GTP packet length field does not match actual length"); + continue; /* Silently discard */ + } + + if ((gsn->mode == GTP_MODE_GGSN) && + ((pheader->type == GTP_CREATE_PDP_RSP) || + (pheader->type == GTP_UPDATE_PDP_RSP) || + (pheader->type == GTP_DELETE_PDP_RSP))) { + gsn->unexpect++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status, + "Unexpected GTP Signalling Message"); + continue; /* Silently discard 29.60: 11.1.4 */ + } + + if ((gsn->mode == GTP_MODE_SGSN) && + ((pheader->type == GTP_CREATE_PDP_REQ) || + (pheader->type == GTP_UPDATE_PDP_REQ) || + (pheader->type == GTP_DELETE_PDP_REQ))) { + gsn->unexpect++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status, + "Unexpected GTP Signalling Message"); + continue; /* Silently discard 29.60: 11.1.4 */ + } + switch (pheader->type) { case GTP_ECHO_REQ: - gtp_echo_ind(gsn, &peer, buffer+ip_len, status - ip_len); + gtp_echo_ind(gsn, version, &peer, fd, buffer, status); break; case GTP_ECHO_RSP: - gtp_echo_conf(gsn, &peer, buffer+ip_len, status - ip_len); + gtp_echo_conf(gsn, version, &peer, buffer, status); break; case GTP_NOT_SUPPORTED: - gtp_unsup_conf(gsn, &peer, buffer+ip_len, status - ip_len); + gtp_unsup_ind(gsn, &peer, buffer, status); break; case GTP_CREATE_PDP_REQ: - gtp_create_pdp_ind(gsn, version, &peer, buffer+ip_len, - status - ip_len); + gtp_create_pdp_ind(gsn, version, &peer, fd, buffer, status); break; case GTP_CREATE_PDP_RSP: - gtp_create_pdp_conf(gsn, version, &peer, buffer+ip_len, - status - ip_len); + gtp_create_pdp_conf(gsn, version, &peer, buffer, status); break; case GTP_UPDATE_PDP_REQ: - gtp_update_pdp_ind(gsn, version, &peer, buffer+ip_len, - status - ip_len); + gtp_update_pdp_ind(gsn, version, &peer, fd, buffer, status); break; case GTP_UPDATE_PDP_RSP: - gtp_update_pdp_conf(gsn, version, &peer, buffer+ip_len, - status - ip_len); + gtp_update_pdp_conf(gsn, version, &peer, buffer, status); break; case GTP_DELETE_PDP_REQ: - gtp_delete_pdp_ind(gsn, version, &peer, buffer+ip_len, - status - ip_len); + gtp_delete_pdp_ind(gsn, version, &peer, fd, buffer, status); break; case GTP_DELETE_PDP_RSP: - gtp_delete_pdp_conf(gsn, version, &peer, buffer+ip_len, - status - ip_len); + gtp_delete_pdp_conf(gsn, version, &peer, buffer, status); break; case GTP_ERROR: - gtp_error_ind_conf(gsn, version, &peer, buffer+ip_len, - status - ip_len); + gtp_error_ind_conf(gsn, version, &peer, buffer, status); + break; + default: + gsn->unknown++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status, + "Unknown GTP message type received"); break; + } + } +} + +int gtp_decaps1u(struct gsn_t *gsn) +{ + unsigned char buffer[PACKET_MAX + 64 /*TODO: ip header */ ]; + struct sockaddr_in peer; + int peerlen; + int status; + struct gtp1_header_short *pheader; + int version = 1; /* GTP version should be determined from header!*/ + int fd = gsn->fd1u; + + /* TODO: Need strategy of userspace buffering and blocking */ + /* Currently read is non-blocking and send is blocking. */ + /* This means that the program have to wait for busy send calls...*/ + + while (1) { /* Loop until no more to read */ + if (fcntl(gsn->fd1u, F_SETFL, O_NONBLOCK)) { + gtp_err(LOG_ERR, __FILE__, __LINE__, "fnctl()"); + return -1; + } + peerlen = sizeof(peer); + if ((status = + recvfrom(gsn->fd1u, buffer, sizeof(buffer), 0, + (struct sockaddr *) &peer, &peerlen)) < 0 ) { + if (errno == EAGAIN) return 0; + gsn->err_readfrom++; + gtp_err(LOG_ERR, __FILE__, __LINE__, "recvfrom(fd1u=%d, buffer=%lx, len=%d) failed: status = %d error = %s", gsn->fd1u, (unsigned long) buffer, sizeof(buffer), status, status ? strerror(errno) : "No error"); + return -1; + } + + /* Need at least 1 byte in order to check version */ + if (status < (1)) { + gsn->empty++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status, + "Discarding packet - too small"); + continue; + } + + pheader = (struct gtp1_header_short *) (buffer); + + /* Version must be no larger than GTP 1 */ + if (((pheader->flags & 0xe0) > 0x20)) { + gsn->unsup++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status, + "Unsupported GTP version"); + gtp_unsup_req(gsn, 1, &peer, gsn->fd1c, buffer, status);/*29.60: 11.1.1*/ + continue; + } + + /* Version must be at least GTP 1 */ + /* 29.060 is somewhat unclear on this issue. On gsn->fd1c we expect only */ + /* GTP 1 messages. If GTP 0 message is received we silently discard */ + /* the message */ + if (((pheader->flags & 0xe0) < 0x20)) { + gsn->unsup++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status, + "Unsupported GTP version"); + continue; + } + + /* Check packet flag field (allow both with and without sequence number)*/ + if (((pheader->flags & 0xf5) != 0x30)) { + gsn->unsup++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status, + "Unsupported packet flag"); + continue; + } + + /* Check length of packet */ + if (status < GTP1_HEADER_SIZE_SHORT) { + gsn->tooshort++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status, + "GTP packet too short"); + continue; /* Silently discard 29.60: 11.1.2 */ + } + + /* Check packet length field versus length of packet */ + if (status != (ntoh16(pheader->length) + GTP1_HEADER_SIZE_SHORT)) { + gsn->tooshort++; + gtp_errpack(LOG_ERR, __FILE__, __LINE__, &peer, buffer, status, + "GTP packet length field does not match actual length"); + continue; /* Silently discard */ + } + + switch (pheader->type) { + case GTP_ECHO_REQ: + gtp_echo_ind(gsn, version, &peer, fd, buffer, status); + break; + case GTP_ECHO_RSP: + gtp_echo_conf(gsn, version, &peer, buffer, status); + break; + case GTP_ERROR: + gtp_error_ind_conf(gsn, version, &peer, buffer, status); + break; + /* Supported header extensions */ case GTP_GPDU: - gtp_gpdu_ind(gsn, version, &peer, buffer+ip_len, status - ip_len); + gtp_gpdu_ind(gsn, version, &peer, fd, buffer, status); break; default: gsn->unknown++; @@ -1950,46 +2621,72 @@ int gtp_decaps(struct gsn_t *gsn) } } -int gtp_gpdu(struct gsn_t *gsn, struct pdp_t* pdp, +int gtp_data_req(struct gsn_t *gsn, struct pdp_t* pdp, void *pack, unsigned len) { union gtp_packet packet; struct sockaddr_in addr; - - /*printf("gtp_encaps start\n"); - print_packet(pack, len);*/ + int fd; + int length; memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; - memcpy(&addr.sin_addr, pdp->gsnru.v,pdp->gsnru.l); /* TODO range check */ - addr.sin_port = htons(GTP0_PORT); - get_default_gtp(0, &packet); - packet.gtp0.h.type = hton8(GTP_GPDU); - packet.gtp0.h.length = hton16(len); - packet.gtp0.h.seq = hton16(pdp->gtpsntx++); - packet.gtp0.h.flow = hton16(pdp->flru); - packet.gtp0.h.tid = (pdp->imsi & 0x0fffffffffffffff) + ((uint64_t)pdp->nsapi << 60); - - if (len > sizeof (union gtp_packet) - sizeof(struct gtp0_header)) { - gsn->err_memcpy++; + if (pdp->version == 0) { + + length = GTP0_HEADER_SIZE+len; + addr.sin_port = htons(GTP0_PORT); + fd = gsn->fd0; + + get_default_gtp(0, GTP_GPDU, &packet); + packet.gtp0.h.length = hton16(len); + packet.gtp0.h.seq = hton16(pdp->gtpsntx++); + packet.gtp0.h.flow = hton16(pdp->flru); + packet.gtp0.h.tid = (pdp->imsi & 0x0fffffffffffffff) + ((uint64_t)pdp->nsapi << 60); + + if (len > sizeof (union gtp_packet) - sizeof(struct gtp0_header)) { + gsn->err_memcpy++; + gtp_err(LOG_ERR, __FILE__, __LINE__, + "Memcpy failed"); + return EOF; + } + memcpy(packet.gtp0.p, pack, len); /* TODO Should be avoided! */ + } + else if (pdp->version == 1) { + + length = GTP1_HEADER_SIZE_LONG+len; + addr.sin_port = htons(GTP1U_PORT); + fd = gsn->fd1u; + + get_default_gtp(1, GTP_GPDU, &packet); + packet.gtp1l.h.length = hton16(len-GTP1_HEADER_SIZE_SHORT+ + GTP1_HEADER_SIZE_LONG); + packet.gtp1l.h.seq = hton16(pdp->gtpsntx++); + + if (len > sizeof (union gtp_packet) - sizeof(struct gtp1_header_long)) { + gsn->err_memcpy++; + gtp_err(LOG_ERR, __FILE__, __LINE__, + "Memcpy failed"); + return EOF; + } + memcpy(packet.gtp1l.p, pack, len); /* TODO Should be avoided! */ + } + else { gtp_err(LOG_ERR, __FILE__, __LINE__, - "Memcpy failed"); + "Unknown version"); return EOF; - } + } - if (fcntl(gsn->fd, F_SETFL, 0)) { + if (fcntl(fd, F_SETFL, 0)) { gtp_err(LOG_ERR, __FILE__, __LINE__, "fnctl()"); return -1; } - memcpy(packet.gtp0.p, pack, len); /* TODO Should be avoided! */ - - if (sendto(gsn->fd, &packet, GTP0_HEADER_SIZE+len, 0, + if (sendto(fd, &packet, length, 0, (struct sockaddr *) &addr, sizeof(addr)) < 0) { gsn->err_sendto++; - gtp_err(LOG_ERR, __FILE__, __LINE__, "Sendto(fd=%d, msg=%lx, len=%d) failed: Error = %s", gsn->fd, (unsigned long) &packet, GTP0_HEADER_SIZE+len, strerror(errno)); + gtp_err(LOG_ERR, __FILE__, __LINE__, "Sendto(fd=%d, msg=%lx, len=%d) failed: Error = %s", fd, (unsigned long) &packet, GTP0_HEADER_SIZE+len, strerror(errno)); return EOF; } return 0; @@ -89,6 +89,55 @@ /* 242-254 For future use. */ #define GTP_GPDU 255 /* G-PDU */ + +/* GTP information element cause codes from 29.060 v3.9.0 7.7 */ +/* */ +#define GTPCAUSE_REQ_IMSI 0 /* Request IMSI */ +#define GTPCAUSE_REQ_IMEI 1 /* Request IMEI */ +#define GTPCAUSE_REQ_IMSI_IMEI 2 /* Request IMSI and IMEI */ +#define GTPCAUSE_NO_ID_NEEDED 3 /* No identity needed */ +#define GTPCAUSE_MS_REFUSES_X 4 /* MS refuses */ +#define GTPCAUSE_MS_NOT_RESP_X 5 /* MS is not GPRS responding */ +#define GTPCAUSE_006 6 /* For future use 6-48 */ +#define GTPCAUSE_049 49 /* Cause values reserved for GPRS charging protocol use (See GTP' in GSM 12.15) 49-63 */ +#define GTPCAUSE_064 64 /* For future use 64-127 */ +#define GTPCAUSE_ACC_REQ 128 /* Request accepted */ +#define GTPCAUSE_129 129 /* For future use 129-176 */ +#define GTPCAUSE_177 177 /* Cause values reserved for GPRS charging protocol use (See GTP' In GSM 12.15) 177-191 */ +#define GTPCAUSE_NON_EXIST 192 /* Non-existent */ +#define GTPCAUSE_INVALID_MESSAGE 193 /* Invalid message format */ +#define GTPCAUSE_IMSI_NOT_KNOWN 194 /* IMSI not known */ +#define GTPCAUSE_MS_DETACHED 195 /* MS is GPRS detached */ +#define GTPCAUSE_MS_NOT_RESP 196 /* MS is not GPRS responding */ +#define GTPCAUSE_MS_REFUSES 197 /* MS refuses */ +#define GTPCAUSE_198 198 /* For future use */ +#define GTPCAUSE_NO_RESOURCES 199 /* No resources available */ +#define GTPCAUSE_NOT_SUPPORTED 200 /* Service not supported */ +#define GTPCAUSE_MAN_IE_INCORRECT 201 /* Mandatory IE incorrect */ +#define GTPCAUSE_MAN_IE_MISSING 202 /* Mandatory IE missing */ +#define GTPCAUSE_OPT_IE_INCORRECT 203 /* Optional IE incorrect */ +#define GTPCAUSE_SYS_FAIL 204 /* System failure */ +#define GTPCAUSE_ROAMING_REST 205 /* Roaming Restriction */ +#define GTPCAUSE_PTIMSI_MISMATCH 206 /* P-TMSI signature mismatch */ +#define GTPCAUSE_CONN_SUSP 207 /* GPRS connection suspended */ +#define GTPCAUSE_AUTH_FAIL 208 /* Authentication failure */ +#define GTPCAUSE_USER_AUTH_FAIL 209 /* User authentication failed */ +#define GTPCAUSE_CONTEXT_NOT_FOUND 210 /* Context not found */ +#define GTPCAUSE_ADDR_OCCUPIED 211 /* All dynamic PDP addresses are occupied */ +#define GTPCAUSE_NO_MEMORY 212 /* No memory is available */ +#define GTPCAUSE_RELOC_FAIL 213 /* Relocation failure */ +#define GTPCAUSE_UNKNOWN_MAN_EXTHEADER 214 /* Unknown mandatory extension header */ +#define GTPCAUSE_SEM_ERR_TFT 215 /* Semantic error in the TFT operation */ +#define GTPCAUSE_SYN_ERR_TFT 216 /* Syntactic error in the TFT operation */ +#define GTPCAUSE_SEM_ERR_FILTER 217 /* Semantic errors in packet filter(s) */ +#define GTPCAUSE_SYN_ERR_FILTER 218 /* Syntactic errors in packet filter(s) */ +#define GTPCAUSE_MISSING_APN 219 /* Missing or unknown APN*/ +#define GTPCAUSE_UNKNOWN_PDP 220 /* Unknown PDP address or PDP type */ +#define GTPCAUSE_221 221 /* For Future Use 221-240 */ +#define GTPCAUSE_241 241 /* Cause Values Reserved For Gprs Charging Protocol Use (See Gtp' In Gsm 12.15) 241-255 */ + + + /* GTP 0 header. * Explanation to some of the fields: * SNDCP NPDU Number flag = 0 except for inter SGSN handover situations @@ -100,49 +149,49 @@ * Tunnel ID is IMSI+NSAPI. Unique identifier of PDP context. Is somewhat * redundant because the header also includes flow. */ -struct gtp0_header { /* Descriptions from 3GPP 09.60 */ - u_int8_t flags; /* 01 bitfield, with typical values */ - /* 000..... Version: 1 (0) */ - /* ...1111. Spare (7) */ - /* .......0 SNDCP N-PDU Number flag (0) */ - u_int8_t type; /* 02 Message type. T-PDU = 0xff */ - u_int16_t length; /* 03 Length (of G-PDU excluding header) */ - u_int16_t seq; /* 05 Sequence Number */ - u_int16_t flow; /* 07 Flow Label ( = 0 for signalling) */ - u_int8_t number; /* 09 SNDCP N-PDU LCC Number ( 0 = 0xff) */ - u_int8_t spare1; /* 10 Spare */ - u_int8_t spare2; /* 11 Spare */ - u_int8_t spare3; /* 12 Spare */ - u_int64_t tid; /* 13 Tunnel ID */ -}; /* 20 */ - -struct gtp1_header_short { /* Descriptions from 3GPP 29060 */ - u_int8_t flags; /* 01 bitfield, with typical values */ - /* 000..... Version: 1 */ - /* ...1.... Protocol Type: GTP=1, GTP'=0 */ - /* ....1... Spare = 1 */ - /* .....1.. Extension header flag: 1 */ - /* ......1. Sequence number flag: 1 */ - /* .......0 PN: N-PDU Number flag */ - u_int8_t type; /* 02 Message type. T-PDU = 0xff */ - u_int16_t length; /* 03 Length (of IP packet or signalling) */ - u_int64_t tid; /* 05 - 08 Tunnel ID */ +struct gtp0_header { /* Descriptions from 3GPP 09.60 */ + u_int8_t flags; /* 01 bitfield, with typical values */ + /* 000..... Version: 1 (0) */ + /* ...1111. Spare (7) */ + /* .......0 SNDCP N-PDU Number flag (0) */ + u_int8_t type; /* 02 Message type. T-PDU = 0xff */ + u_int16_t length; /* 03 Length (of G-PDU excluding header) */ + u_int16_t seq; /* 05 Sequence Number */ + u_int16_t flow; /* 07 Flow Label ( = 0 for signalling) */ + u_int8_t number; /* 09 SNDCP N-PDU LCC Number ( 0 = 0xff) */ + u_int8_t spare1; /* 10 Spare */ + u_int8_t spare2; /* 11 Spare */ + u_int8_t spare3; /* 12 Spare */ + u_int64_t tid; /* 13 Tunnel ID */ +}; /* 20 */ + +struct gtp1_header_short { /* Descriptions from 3GPP 29060 */ + u_int8_t flags; /* 01 bitfield, with typical values */ + /* 001..... Version: 1 */ + /* ...1.... Protocol Type: GTP=1, GTP'=0 */ + /* ....0... Spare = 0 */ + /* .....0.. Extension header flag: 0 */ + /* ......0. Sequence number flag: 0 */ + /* .......0 PN: N-PDU Number flag */ + u_int8_t type; /* 02 Message type. T-PDU = 0xff */ + u_int16_t length; /* 03 Length (of IP packet or signalling) */ + u_int32_t tei; /* 05 - 08 Tunnel Endpoint ID */ }; -struct gtp1_header_long { /* Descriptions from 3GPP 29060 */ - u_int8_t flags; /* 01 bitfield, with typical values */ - /* 000..... Version: 1 */ - /* ...1.... Protocol Type: GTP=1, GTP'=0 */ - /* ....1... Spare = 1 */ - /* .....1.. Extension header flag: 1 */ - /* ......1. Sequence number flag: 1 */ - /* .......0 PN: N-PDU Number flag */ - u_int8_t type; /* 02 Message type. T-PDU = 0xff */ - u_int16_t length; /* 03 Length (of IP packet or signalling) */ - u_int64_t tid; /* 05 Tunnel ID */ - u_int16_t seq; /* 10 Sequence Number */ - u_int8_t npdu; /* 11 N-PDU Number */ - u_int8_t next; /* 12 Next extension header type. Empty = 0 */ +struct gtp1_header_long { /* Descriptions from 3GPP 29060 */ + u_int8_t flags; /* 01 bitfield, with typical values */ + /* 001..... Version: 1 */ + /* ...1.... Protocol Type: GTP=1, GTP'=0 */ + /* ....0... Spare = 0 */ + /* .....0.. Extension header flag: 0 */ + /* ......1. Sequence number flag: 1 */ + /* .......0 PN: N-PDU Number flag */ + u_int8_t type; /* 02 Message type. T-PDU = 0xff */ + u_int16_t length; /* 03 Length (of IP packet or signalling) */ + u_int32_t tei; /* 05 Tunnel Endpoint ID */ + u_int16_t seq; /* 10 Sequence Number */ + u_int8_t npdu; /* 11 N-PDU Number */ + u_int8_t next; /* 12 Next extension header type. Empty = 0 */ }; struct gtp0_packet { @@ -162,9 +211,9 @@ struct gtp1_packet_long { union gtp_packet { u_int8_t flags; - struct gtp0_packet gtp0; - struct gtp1_packet_short gtp1s; - struct gtp1_packet_long gtp1l; + struct gtp0_packet gtp0; + struct gtp1_packet_short gtp1s; + struct gtp1_packet_long gtp1l; } __attribute__((packed)) h; @@ -188,7 +237,9 @@ union gtp_packet { struct gsn_t { /* Parameters related to the network interface */ - int fd; /* File descriptor to network interface */ + int fd0; /* GTP0 file descriptor */ + int fd1c; /* GTP1 control plane file descriptor */ + int fd1u; /* GTP0 user plane file descriptor */ int mode; /* Mode of operation: GGSN or SGSN */ struct in_addr gsnc; /* IP address of this gsn for signalling */ struct in_addr gsnu; /* IP address of this gsn for user traffic */ @@ -206,9 +257,10 @@ struct gsn_t { /* Call back functions */ int (*cb_delete_context) (struct pdp_t*); - int (*cb_create_context) (struct pdp_t*); - int (*cb_conf) (int type, int cause, struct pdp_t *pdp, void* aid); - int (*cb_gpdu) (struct pdp_t* pdp, void* pack, unsigned len); + int (*cb_create_context_ind) (struct pdp_t*); + int (*cb_unsup_ind) (struct sockaddr_in *peer); + int (*cb_conf) (int type, int cause, struct pdp_t *pdp, void* cbp); + int (*cb_data_ind) (struct pdp_t* pdp, void* pack, unsigned len); /* Counters */ @@ -247,100 +299,92 @@ extern int gtp_newpdp(struct gsn_t *gsn, struct pdp_t **pdp, uint64_t imsi, uint8_t nsapi); extern int gtp_freepdp(struct gsn_t *gsn, struct pdp_t *pdp); -extern int gtp_create_context(struct gsn_t *gsn, struct pdp_t *pdp, void *aid, - struct in_addr* inetaddr); -extern int gtp_update_context(struct gsn_t *gsn, struct pdp_t *pdp, void *aid, - struct in_addr* inetaddr); -extern int gtp_delete_context(struct gsn_t *gsn, struct pdp_t *pdp, void *aid); +extern int gtp_create_context_req(struct gsn_t *gsn, struct pdp_t *pdp, + void *cbp, struct in_addr* inetaddr); + +extern int gtp_set_cb_create_context_ind(struct gsn_t *gsn, + int (*cb_create_context_ind) (struct pdp_t* pdp)); + +extern int gtp_create_context_resp(struct gsn_t *gsn, struct pdp_t *pdp, + int cause); + +extern int gtp_update_context(struct gsn_t *gsn, struct pdp_t *pdp, + void *cbp, struct in_addr* inetaddr); + +extern int gtp_delete_context_req(struct gsn_t *gsn, struct pdp_t *pdp, + void *cbp); + +extern int gtp_data_req(struct gsn_t *gsn, struct pdp_t *pdp, + void *pack, unsigned len); -extern int -gtp_create_context2(struct gsn_t *gsn, void *aid, - struct in_addr* inetaddr, - int selmode, uint64_t imsi, int nsapi, - uint8_t *qos, int qoslen, - char *apn, int apnlen, - char *msisdn, int msisdnlen, - uint8_t *pco, int pcolen); +extern int gtp_set_cb_data_ind(struct gsn_t *gsn, + int (*cb_data_ind) (struct pdp_t* pdp, void* pack, unsigned len)); -extern int gtp_gpdu(struct gsn_t *gsn, struct pdp_t *pdp, - void *pack, unsigned len); extern int gtp_fd(struct gsn_t *gsn); -extern int gtp_decaps(struct gsn_t *gsn); +extern int gtp_decaps0(struct gsn_t *gsn); +extern int gtp_decaps1c(struct gsn_t *gsn); +extern int gtp_decaps1u(struct gsn_t *gsn); extern int gtp_retrans(struct gsn_t *gsn); extern int gtp_retranstimeout(struct gsn_t *gsn, struct timeval *timeout); -/* -extern int gtp_set_cb_newpdp(struct gsn_t *gsn, - int (*cb) (struct pdp_t*)); -extern int gtp_set_cb_freepdp(struct gsn_t *gsn, - int (*cb) (struct pdp_t*)); -extern int gtp_set_cb_create_pdp_ind(struct gsn_t *gsn, - int (*cb) (struct pdp_t*)); -extern int gtp_set_cb_create_pdp_conf(struct gsn_t *gsn, - int (*cb) (struct pdp_t*, int)); -extern int gtp_set_cb_update_pdp_conf(struct gsn_t *gsn, - int (*cb) (struct pdp_t*, int, int)); -extern int gtp_set_cb_delete_pdp_ind(struct gsn_t *gsn, - int (*cb) (struct pdp_t*)); -extern int gtp_set_cb_delete_pdp_conf(struct gsn_t *gsn, - int (*cb) (struct pdp_t*, int)); -*/ - extern int gtp_set_cb_delete_context(struct gsn_t *gsn, int (*cb_delete_context) (struct pdp_t* pdp)); -extern int gtp_set_cb_create_context(struct gsn_t *gsn, - int (*cb_create_context) (struct pdp_t* pdp)); +/*extern int gtp_set_cb_create_context(struct gsn_t *gsn, + int (*cb_create_context) (struct pdp_t* pdp)); */ + +extern int gtp_set_cb_unsup_ind(struct gsn_t *gsn, + int (*cb) (struct sockaddr_in *peer)); + + extern int gtp_set_cb_conf(struct gsn_t *gsn, - int (*cb) (int type, int cause, struct pdp_t* pdp, void *aid)); -extern int gtp_set_cb_gpdu(struct gsn_t *gsn, - int (*cb_gpdu) (struct pdp_t* pdp, void* pack, unsigned len)); + int (*cb) (int type, int cause, struct pdp_t* pdp, void *cbp)); /* Internal functions (not part of the API */ -extern int gtp_echo_req(struct gsn_t *gsn, struct in_addr *inetaddrs); -extern int gtp_echo_resp(struct gsn_t *gsn, struct sockaddr_in *peer, +extern int gtp_echo_req(struct gsn_t *gsn, int version, void *cbp, + struct in_addr *inetaddrs); +extern int gtp_echo_resp(struct gsn_t *gsn, int version, + struct sockaddr_in *peer, int fd, void *pack, unsigned len); -extern int gtp_echo_ind(struct gsn_t *gsn, struct sockaddr_in *peer, +extern int gtp_echo_ind(struct gsn_t *gsn, int version, + struct sockaddr_in *peer, int fd, void *pack, unsigned len); -extern int gtp_echo_conf(struct gsn_t *gsn, struct sockaddr_in *peer, +extern int gtp_echo_conf(struct gsn_t *gsn, int version, + struct sockaddr_in *peer, void *pack, unsigned len); -extern int gtp_unsup_resp(struct gsn_t *gsn, struct sockaddr_in *peer, - void *pack, unsigned len); -extern int gtp_unsup_conf(struct gsn_t *gsn, struct sockaddr_in *peer, - void *pack, unsigned len); - -extern int gtp_create_pdp_req(struct gsn_t *gsn, int version, void *aid, - struct in_addr* inetaddr, struct pdp_t *pdp); +extern int gtp_unsup_req(struct gsn_t *gsn, int version, + struct sockaddr_in *peer, + int fd, void *pack, unsigned len); +extern int gtp_unsup_ind(struct gsn_t *gsn, struct sockaddr_in *peer, + void *pack, unsigned len); -extern int gtp_create_pdp_resp(struct gsn_t *gsn, int version, - struct sockaddr_in *peer, - void *pack, unsigned len, +extern int gtp_create_pdp_resp(struct gsn_t *gsn, int version, struct pdp_t *pdp, uint8_t cause); extern int gtp_create_pdp_ind(struct gsn_t *gsn, int version, - struct sockaddr_in *peer, + struct sockaddr_in *peer, int fd, void *pack, unsigned len); extern int gtp_create_pdp_conf(struct gsn_t *gsn, int version, struct sockaddr_in *peer, void *pack, unsigned len); -extern int gtp_update_pdp_req(struct gsn_t *gsn, int version, void *aid, +extern int gtp_update_pdp_req(struct gsn_t *gsn, int version, void *cbp, struct in_addr* inetaddr, struct pdp_t *pdp); -extern int gtp_delete_pdp_req(struct gsn_t *gsn, int version, void *aid, +extern int gtp_delete_pdp_req(struct gsn_t *gsn, int version, void *cbp, struct pdp_t *pdp); extern int gtp_delete_pdp_resp(struct gsn_t *gsn, int version, - struct sockaddr_in *peer, + struct sockaddr_in *peer, int fd, void *pack, unsigned len, struct pdp_t *pdp, uint8_t cause); extern int gtp_delete_pdp_ind(struct gsn_t *gsn, int version, - struct sockaddr_in *peer, + struct sockaddr_in *peer, int fd, void *pack, unsigned len); extern int gtp_delete_pdp_conf(struct gsn_t *gsn, int version, diff --git a/gtp/gtpie.c b/gtp/gtpie.c index 8fd4a20..68f912f 100644 --- a/gtp/gtpie.c +++ b/gtp/gtpie.c @@ -79,6 +79,14 @@ int gtpie_tv4(void *p, int *length, int size, u_int8_t t, u_int32_t v) { return 0; } +int gtpie_tv8(void *p, int *length, int size, u_int8_t t, u_int64_t v) { + if ((*length + 9) >= size) return 1; + ((union gtpie_member*) (p + *length))->tv8.t = hton8(t); + ((union gtpie_member*) (p + *length))->tv8.v = hton64(v); + *length += 9; + return 0; +} + int gtpie_getie(union gtpie_member* ie[], int type, int instance) { int j; for (j=0; j< GTPIE_SIZE; j++) { @@ -157,7 +165,18 @@ int gtpie_gettv4(union gtpie_member* ie[], int type, int instance, return 0; } -int gtpie_decaps(union gtpie_member* ie[], void *pack, unsigned len) { +int gtpie_gettv8(union gtpie_member* ie[], int type, int instance, + uint64_t *dst){ + int ien; + ien = gtpie_getie(ie, type, instance); + if (ien>=0) + *dst = ntoh64(ie[ien]->tv8.v); + else + return EOF; + return 0; +} + +int gtpie_decaps(union gtpie_member* ie[], int version, void *pack, unsigned len) { int i; int j = 0; unsigned char *p; @@ -175,9 +194,9 @@ int gtpie_decaps(union gtpie_member* ie[], void *pack, unsigned len) { printf("%02x ", (unsigned char)*(char *)(p+i)); if (!((i+1)%16)) printf("\n"); }; - printf("\n"); + printf("\n"); } - + switch (*p) { case GTPIE_CAUSE: /* TV GTPIE types with value length 1 */ case GTPIE_REORDER: @@ -194,14 +213,26 @@ int gtpie_decaps(union gtpie_member* ie[], void *pack, unsigned len) { if (j<GTPIE_SIZE) { ie[j] = (union gtpie_member*) p; if (GTPIE_DEBUG) printf("GTPIE TV1 found. Type %d, value %d\n", - ie[j]->tv1.t, ie[j]->tv1.v); + ie[j]->tv1.t, ie[j]->tv1.v); p+= 1 + 1; j++; } break; - case GTPIE_FL_DI: /* TV GTPIE types with value length 2 */ + case GTPIE_FL_DI: /* TV GTPIE types with value length 2 or 4 */ case GTPIE_FL_C: - case GTPIE_PFI: + if (version != 0) { + if (j<GTPIE_SIZE) { /* GTPIE_TEI_DI & GTPIE_TEI_C with length 4 */ + /* case GTPIE_TEI_DI: gtp1 */ + /* case GTPIE_TEI_C: gtp1 */ + ie[j] = (union gtpie_member*) p; + if (GTPIE_DEBUG) printf("GTPIE TV 4 found. Type %d, value %d\n", + ie[j]->tv4.t, ie[j]->tv4.v); + p+= 1 + 4; + j++; + } + break; + } + case GTPIE_PFI: /* TV GTPIE types with value length 2 */ case GTPIE_CHARGING_C: case GTPIE_TRACE_REF: case GTPIE_TRACE_TYPE: @@ -227,9 +258,9 @@ int gtpie_decaps(union gtpie_member* ie[], void *pack, unsigned len) { case GTPIE_TLLI: /* TV GTPIE types with value length 4 */ case GTPIE_P_TMSI: case GTPIE_CHARGING_ID: + /* case GTPIE_TEI_DI: Handled by GTPIE_FL_DI */ + /* case GTPIE_TEI_C: Handled by GTPIE_FL_DI */ if (j<GTPIE_SIZE) { - /* case GTPIE_TEI_DI: gtp1 */ - /* case GTPIE_TEI_C: gtp1 */ ie[j] = (union gtpie_member*) p; if (GTPIE_DEBUG) printf("GTPIE TV 4 found. Type %d, value %d\n", ie[j]->tv4.t, ie[j]->tv4.v); diff --git a/gtp/gtpie.h b/gtp/gtpie.h index 58a36e9..f8990dc 100644 --- a/gtp/gtpie.h +++ b/gtp/gtpie.h @@ -25,6 +25,29 @@ #define hton32(x) htonl(x) #define ntoh32(x) ntohl(x) +#if BYTE_ORDER == LITTLE_ENDIAN +static __inline u_int64_t +hton64(u_int64_t q) +{ + register u_int32_t u, l; + u = q >> 32; + l = (u_int32_t) q; + + return htonl(u) | ((u_int64_t)htonl(l) << 32); +} + +#define ntoh64(_x) hton64(_x) + +#elif BYTE_ORDER == BIG_ENDIAN + +#define hton64(_x) (_x) +#define ntoh64(_x) hton64(_x) + +#else +#error "Please fix <machine/endian.h>" +#endif + + #define GTPIE_SIZE 256 /* Max number of information elements */ #define GTPIE_MAX 0xffff /* Max length of information elements */ #define GTPIE_MAX_TV 28 /* Max length of type value pair */ @@ -91,52 +114,6 @@ /* 252-254 Reserved for the GPRS charging protocol (see GTP' in GSM 12.15) */ #define GTPIE_PRIVATE 255 /* Private Extension */ -/* GTP information element cause codes from 29.060 v3.9.0 7.7 */ -/* */ -#define GTPCAUSE_REQ_IMSI 0 /* Request IMSI */ -#define GTPCAUSE_REQ_IMEI 1 /* Request IMEI */ -#define GTPCAUSE_REQ_IMSI_IMEI 2 /* Request IMSI and IMEI */ -#define GTPCAUSE_NO_ID_NEEDED 3 /* No identity needed */ -#define GTPCAUSE_MS_REFUSES_X 4 /* MS refuses */ -#define GTPCAUSE_MS_NOT_RESP_X 5 /* MS is not GPRS responding */ -#define GTPCAUSE_006 6 /* For future use 6-48 */ -#define GTPCAUSE_049 49 /* Cause values reserved for GPRS charging protocol use (See GTP' in GSM 12.15) 49-63 */ -#define GTPCAUSE_064 64 /* For future use 64-127 */ -#define GTPCAUSE_ACC_REQ 128 /* Request accepted */ -#define GTPCAUSE_129 129 /* For future use 129-176 */ -#define GTPCAUSE_177 177 /* Cause values reserved for GPRS charging protocol use (See GTP' In GSM 12.15) 177-191 */ -#define GTPCAUSE_NON_EXIST 192 /* Non-existent */ -#define GTPCAUSE_INVALID_MESSAGE 193 /* Invalid message format */ -#define GTPCAUSE_IMSI_NOT_KNOWN 194 /* IMSI not known */ -#define GTPCAUSE_MS_DETACHED 195 /* MS is GPRS detached */ -#define GTPCAUSE_MS_NOT_RESP 196 /* MS is not GPRS responding */ -#define GTPCAUSE_MS_REFUSES 197 /* MS refuses */ -#define GTPCAUSE_198 198 /* For future use */ -#define GTPCAUSE_NO_RESOURCES 199 /* No resources available */ -#define GTPCAUSE_NOT_SUPPORTED 200 /* Service not supported */ -#define GTPCAUSE_MAN_IE_INCORRECT 201 /* Mandatory IE incorrect */ -#define GTPCAUSE_MAN_IE_MISSING 202 /* Mandatory IE missing */ -#define GTPCAUSE_OPT_IE_INCORRECT 203 /* Optional IE incorrect */ -#define GTPCAUSE_SYS_FAIL 204 /* System failure */ -#define GTPCAUSE_ROAMING_REST 205 /* Roaming Restriction */ -#define GTPCAUSE_PTIMSI_MISMATCH 206 /* P-TMSI signature mismatch */ -#define GTPCAUSE_CONN_SUSP 207 /* GPRS connection suspended */ -#define GTPCAUSE_AUTH_FAIL 208 /* Authentication failure */ -#define GTPCAUSE_USER_AUTH_FAIL 209 /* User authentication failed */ -#define GTPCAUSE_CONTEXT_NOT_FOUND 210 /* Context not found */ -#define GTPCAUSE_ADDR_OCCUPIED 211 /* All dynamic PDP addresses are occupied */ -#define GTPCAUSE_NO_MEMORY 212 /* No memory is available */ -#define GTPCAUSE_RELOC_FAIL 213 /* Relocation failure */ -#define GTPCAUSE_UNKNOWN_MAN_EXTHEADER 214 /* Unknown mandatory extension header */ -#define GTPCAUSE_SEM_ERR_TFT 215 /* Semantic error in the TFT operation */ -#define GTPCAUSE_SYN_ERR_TFT 216 /* Syntactic error in the TFT operation */ -#define GTPCAUSE_SEM_ERR_FILTER 217 /* Semantic errors in packet filter(s) */ -#define GTPCAUSE_SYN_ERR_FILTER 218 /* Syntactic errors in packet filter(s) */ -#define GTPCAUSE_MISSING_APN 219 /* Missing or unknown APN*/ -#define GTPCAUSE_UNKNOWN_PDP 220 /* Unknown PDP address or PDP type */ -#define GTPCAUSE_221 221 /* For Future Use 221-240 */ -#define GTPCAUSE_241 241 /* Cause Values Reserved For Gprs Charging Protocol Use (See Gtp' In Gsm 12.15) 241-255 */ - /* GTP information element structs in network order */ struct gtpie_ext { /* Extension header */ @@ -267,8 +244,11 @@ extern int gtpie_gettv2(union gtpie_member* ie[], int type, int instance, uint16_t *dst); extern int gtpie_gettv4(union gtpie_member* ie[], int type, int instance, uint32_t *dst); +extern int gtpie_gettv8(union gtpie_member* ie[], int type, int instance, + uint64_t *dst); -extern int gtpie_decaps(union gtpie_member* ie[], void *pack, unsigned len); +extern int gtpie_decaps(union gtpie_member* ie[], int version, + void *pack, unsigned len); extern int gtpie_encaps(union gtpie_member* ie[], void *pack, unsigned *len); extern int gtpie_encaps2(union gtpie_member ie[], int size, void *pack, unsigned *len); @@ -128,7 +128,7 @@ int pdp_newpdp(struct pdp_t **pdp, uint64_t imsi, uint8_t nsapi, (*pdp)->fllc = (uint16_t) n; (*pdp)->fllu = (uint16_t) n; (*pdp)->teic_own = (uint32_t) n; - (*pdp)->teic_own = (uint32_t) n; + (*pdp)->teid_own = (uint32_t) n; pdp_tidset(*pdp, pdp_gettid(imsi, nsapi)); return 0; } @@ -227,6 +227,11 @@ int pdp_tidget(struct pdp_t **pdp, uint64_t tid) { return EOF; /* End of linked list and not found */ } +int pdp_getimsi(struct pdp_t **pdp, uint64_t imsi, uint8_t nsapi) { + return pdp_tidget(pdp, + (imsi & 0x0fffffffffffffff) + ((uint64_t)nsapi << 60)); +} + /* int pdp_iphash(void* ipif, struct ul66_t *eua) { /#printf("IPhash %ld\n", lookup(eua->v, eua->l, ipif) % PDP_MAX);#/ @@ -123,6 +123,7 @@ struct pdp_t { struct ul255_t apn_sub;/* The APN received from the HLR. */ struct ul255_t apn_use;/* The APN Network Identifier currently used. */ uint8_t nsapi; /* Network layer Service Access Point Identifier. (4 bit) */ + uint8_t linked_nsapi; /* (Linked NSAPI) (4 bit) */ uint16_t ti; /* Transaction Identifier. (4 or 12 bit) */ uint32_t teic_own; /* (Own Tunnel Endpoint Identifier Control) */ @@ -136,7 +137,7 @@ struct pdp_t { uint16_t flrc; /* (Remote gn/gp Flow Label Control, gtp0) */ uint16_t flru; /* (Remote gn/gp Flow Label Data I, gtp0) */ - struct ul_t tft; /* Traffic flow template. */ + struct ul255_t tft; /* Traffic flow template. */ /*struct ul16_t sgsnc; * The IP address of the SGSN currently serving this MS. (Control plane) */ /*struct ul16_t sgsnu; * The IP address of the SGSN currently serving this MS. (User plane) */ /*struct ul16_t ggsnc; * The IP address of the GGSN currently used. (Control plane) */ @@ -173,7 +174,15 @@ struct pdp_t { struct ul255_t pco_req; /* Requested packet control options. */ struct ul255_t pco_neg; /* Negotiated packet control options. */ uint32_t selmode; /* Selection mode. */ - uint64_t tid; /* (Combination of imsi and nsapi) */ + + /* Additional parameters used by library */ + + int version; /* Protocol version currently in use. 0 or 1 */ + + uint64_t tid; /* Combination of imsi and nsapi */ + u_int16_t seq; /* Sequence number of last request */ + struct sockaddr_in sa_peer; /* Address of last request */ + int fd; /* File descriptor request was received on */ }; @@ -185,13 +194,16 @@ int pdp_freepdp(struct pdp_t *pdp); int pdp_getpdp(struct pdp_t **pdp); int pdp_getgtp0(struct pdp_t **pdp, uint16_t fl); -int pdp_getgtp1(struct pdp_t **pdp, uint32_t teid); +int pdp_getgtp1(struct pdp_t **pdp, uint32_t tei); + +int pdp_getimsi(struct pdp_t **pdp, uint64_t imsi, uint8_t nsapi); int pdp_tidhash(uint64_t tid); int pdp_tidset(struct pdp_t *pdp, uint64_t tid); int pdp_tiddel(struct pdp_t *pdp); int pdp_tidget(struct pdp_t **pdp, uint64_t tid); + /* int pdp_iphash(void* ipif, struct ul66_t *eua); int pdp_ipset(struct pdp_t *pdp, void* ipif, struct ul66_t *eua); diff --git a/gtp/queue.c b/gtp/queue.c index 900f240..845b4ba 100644 --- a/gtp/queue.c +++ b/gtp/queue.c @@ -77,6 +77,8 @@ int queue_seqset(struct queue_t *queue, struct qmsg_t *qmsg, if (QUEUE_DEBUG) printf("End queue_seqset\n"); return 0; } + + int queue_seqdel(struct queue_t *queue, struct qmsg_t *qmsg) { int hash = queue_seqhash(&qmsg->peer, qmsg->seq); struct qmsg_t *qmsg2; @@ -234,14 +236,14 @@ int queue_seqget(struct queue_t *queue, struct qmsg_t **qmsg, } int queue_freemsg_seq(struct queue_t *queue, struct sockaddr_in *peer, - uint16_t seq, uint8_t *type, void **aid) { + uint16_t seq, uint8_t *type, void **cbp) { struct qmsg_t *qmsg; if (queue_seqget(queue, &qmsg, peer, seq)) { - *aid = NULL; + *cbp = NULL; *type = 0; return EOF; } - *aid = qmsg->aid; + *cbp = qmsg->cbp; *type = qmsg->type; if (queue_freemsg(queue, qmsg)) { return EOF; diff --git a/gtp/queue.h b/gtp/queue.h index 076a3ef..1e226c9 100644 --- a/gtp/queue.h +++ b/gtp/queue.h @@ -30,10 +30,11 @@ struct qmsg_t { /* Holder for queued packets */ int state; /* 0=empty, 1=full */ uint16_t seq; /* The sequence number */ - u_int8_t type; /* The type of packet */ - void *aid; /* Application specific pointer */ + u_int8_t type; /* The type of packet */ + void *cbp; /* Application specific pointer */ union gtp_packet p; /* The packet stored */ int l; /* Length of the packet */ + int fd; /* Socket packet was sent to / received from */ struct sockaddr_in peer;/* Address packet was sent to / received from */ struct qmsg_t *seqnext; /* Pointer to next in sequence hash list */ int next; /* Pointer to the next in queue. -1: Last */ @@ -70,7 +71,7 @@ int queue_seqget(struct queue_t *queue, struct qmsg_t **qmsg, struct sockaddr_in *peer, uint16_t seq); /* Free message based on sequence number */ int queue_freemsg_seq(struct queue_t *queue, struct sockaddr_in *peer, - uint16_t seq, uint8_t *type, void **aid); + uint16_t seq, uint8_t *type, void **cbp); #endif /* !_QUEUE_H */ diff --git a/sgsnemu/sgsnemu.c b/sgsnemu/sgsnemu.c index 1148755..577428f 100644 --- a/sgsnemu/sgsnemu.c +++ b/sgsnemu/sgsnemu.c @@ -739,7 +739,7 @@ int create_ping(void *gsn, struct pdp_t *pdp, pack.checksum = ~sum; ntransmitted++; - return gtp_gpdu(gsn, pdp, &pack, 28 + datasize); + return gtp_data_req(gsn, pdp, &pack, 28 + datasize); } @@ -771,7 +771,7 @@ int cb_tun_ind(struct tun_t *tun, void *pack, unsigned len) { } if (ipm->pdp) /* Check if a peer protocol is defined */ - gtp_gpdu(gsn, ipm->pdp, pack, len); + gtp_data_req(gsn, ipm->pdp, pack, len); return 0; } @@ -818,13 +818,13 @@ int delete_pdp_conf(struct pdp_t *pdp, int cause) { return 0; } -int echo_conf(struct pdp_t *pdp, int cause) { - if (cause <0) { +int echo_conf(int recovery) { + if (recovery <0) { printf("Echo request timed out\n"); state = 0; } else - printf("Received echo response.\n"); + printf("Received echo response\n"); return 0; } @@ -832,7 +832,7 @@ int conf(int type, int cause, struct pdp_t* pdp, void *aid) { /* if (cause < 0) return 0; Some error occurred. We don't care */ switch (type) { case GTP_ECHO_REQ: - return echo_conf(pdp, cause); + return echo_conf(cause); case GTP_CREATE_PDP_REQ: if (cause !=128) return 0; /* Request not accepted. We don't care */ return create_pdp_conf(pdp, cause); @@ -878,14 +878,16 @@ int main(int argc, char **argv) "Failed to create gtp"); exit(1); } - if (gsn->fd > maxfd) maxfd = gsn->fd; + if (gsn->fd0 > maxfd) maxfd = gsn->fd0; + if (gsn->fd1c > maxfd) maxfd = gsn->fd1c; + if (gsn->fd1u > maxfd) maxfd = gsn->fd1u; gtp_set_cb_delete_context(gsn, delete_context); gtp_set_cb_conf(gsn, conf); if (options.createif) - gtp_set_cb_gpdu(gsn, encaps_tun); + gtp_set_cb_data_ind(gsn, encaps_tun); else - gtp_set_cb_gpdu(gsn, encaps_ping); + gtp_set_cb_data_ind(gsn, encaps_ping); if (options.createif) { printf("Setting up interface\n"); @@ -907,7 +909,8 @@ int main(int argc, char **argv) /* See if anybody is there */ printf("Sending off echo request\n"); - gtp_echo_req(gsn, &options.remote); /* See if remote is alive ? */ + gtp_echo_req(gsn, 1, NULL, &options.remote); /* See if remote is alive ? */ + gtp_echo_req(gsn, 0, NULL, &options.remote); /* See if remote is alive ? */ for(n=0; n<options.contexts; n++) { printf("Setting up PDP context #%d\n", n); @@ -927,6 +930,11 @@ int main(int argc, char **argv) else { memcpy(pdp->qos_req0, options.qos.v, options.qos.l); } + + /* TODO */ + pdp->qos_req.l = 4; + pdp->qos_req.v[0] = 0x00; + memcpy(pdp->qos_req.v+1, options.qos.v, options.qos.l); pdp->selmode = 0x01; /* MS provided APN, subscription not verified */ @@ -964,9 +972,11 @@ int main(int argc, char **argv) memcpy(pdp->pco_req.v, options.pco.v, options.pco.l); } + pdp->version = 1; /* First try with version 1 */ + /* Create context */ /* We send this of once. Retransmissions are handled by gtplib */ - gtp_create_context(gsn, pdp, NULL, &options.remote); + gtp_create_context_req(gsn, pdp, NULL, &options.remote); } state = 1; /* Enter wait_connection state */ @@ -1015,7 +1025,7 @@ int main(int argc, char **argv) for(n=0; n<options.contexts; n++) { /* Delete context */ printf("Disconnecting PDP context #%d\n", n); - gtp_delete_context(gsn, iparr[n].pdp, NULL); + gtp_delete_context_req(gsn, iparr[n].pdp, NULL); if ((options.pinghost.s_addr !=0) && ntransmitted) ping_finish(); } } @@ -1041,7 +1051,9 @@ int main(int argc, char **argv) FD_ZERO(&fds); if (tun) FD_SET(tun->fd, &fds); - FD_SET(gsn->fd, &fds); + FD_SET(gsn->fd0, &fds); + FD_SET(gsn->fd1c, &fds); + FD_SET(gsn->fd1u, &fds); gtp_retranstimeout(gsn, &idleTime); ping_timeout(&idleTime); @@ -1066,9 +1078,14 @@ int main(int argc, char **argv) "TUN decaps failed"); } - if (FD_ISSET(gsn->fd, &fds)) - gtp_decaps(gsn); - + if (FD_ISSET(gsn->fd0, &fds)) + gtp_decaps0(gsn); + + if (FD_ISSET(gsn->fd1c, &fds)) + gtp_decaps1c(gsn); + + if (FD_ISSET(gsn->fd1u, &fds)) + gtp_decaps1u(gsn); } gtp_free(gsn); /* Clean up the gsn instance */ |